处理静态资源
目前为止我们通过 webpack 编译 tsx 代码,通过 HtmlWebpackPlugin 生成 html 文件,还没有涉及到静态资源的打包,即图片、字体、音效、css、less。
通过 webpack 打包资源,并生成对应 hash 名以作区分。
webpack 处理资源,是在配置 modules 里通过 loader 来处理,通过 rules 来区分哪些文件该如何处理(即使用哪些 loader)。于是配置就会长这样:
{
"entry": "./src/index.tsx",
"module": {
"rules": [
{
"test": /\.tsx?$/,
"loader": "ts-loader"
},
{
"test": /\.css$/,
"use": [
"style-loader",
"css-loader"
]
}
]
}
}
重点就是使用 webpack 的 rules,通过每个 rule 下的 test 正则来筛选要处理的文件,对应如何处理则一律交给 loader。
样式资源
这里使用 MiniCssExtractPlugin、css-loader 来处理,为啥需要这么多插件?
css-loader
css-loader 将 css 文件转换成 js 文件,并且把 css 文件中的 url() 替换成相应的资源路径。 所以主要做两件事:
- css 里有@import 和 url()写法,开发时用的本地相对路径,需要转换成发布后的真实路径。
- 将 css 的内容转换为 js 模块。
- 所以 css-loader 并不负责把样式放到节点上,只做转译。
因为 css 样式默认直接添加在节点上的 style 属性,css-loader 并不做这个事情,它只是把 css 文件转移成供 js 使用的代码,由其他插件(如 style-loader)来负责使用。
安装:
npm i css-loader style-loader -D
在 webpack 的 modules 中设置针对 css 文件使用 css-loader 来处理:
...
plugins: ...
module: {
rules: [
{
test: /\.(css)$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
},
],
},
],
},
...
模块化引入资源文件
在 pages/index/index.tsx 同目录下创建 styles.module.css 文件,在里面写上样式,然后在 index.tsx 中引入这个文件,会发现有报错:
Cannot find module './styles.module.css' or its corresponding type declarations.ts(2307)
这是因为 ts 不认识.css 文件,所以我们需要添加一个 global.d.ts 文件,里面把各种在代码中引入的资源作为模块导出,这样就不会报错了。
src/global.d.ts
declare module '*.css' {
const styles: any;
export default styles;
}
declare module '*.scss' {
const styles: any;
export default styles;
}
declare module '*.less' {
const styles: any;
export default styles;
}
declare module '_.svg';
declare module '_.png';
declare module '_.jpg';
declare module '_.jpeg';
declare module '_.gif';
declare module '_.bmp';
declare module '_.tiff';
declare module '_.mp3';
declare module '*.webp';
解决完报错,在 index.tsx 中的 div 节点设置 className,编译后就可以看到 css 样式生效了。
css-loader 默认只处理以 module.css 命名结尾的文件,将这个 css 文件内容进行 js 模块化处理。如果想支持所有扩展名为 css 的文件,需要在 css-loader 的 options 配置中添加一个参数 modules: true,或者设置一个空对象也行。
具体参考:modules 参数
- css-loader 将 css 转译为 js 模块,替换里面的资源路径,并不负责使用。
- style-loader 负责在代码中使用 css-loader 转译后的 js 模块,把它插入到 DOM 节点中。
MiniCssExtractPlugin
因为 css-loader 生成对应 js 模块后是直接内嵌到 js 中的,这样会增加 js 文件的体积,一般我们期望 css 文件能单独导出,然后在 index.html 文件中通过 link 引入。MiniCssExtractPlugin 就是干这个事情的。有了它,style-loader 就不需要了。 安装:
npm i mini-css-extract-plugin -D
修改 webpack.config.js:
...
plugins: [...htmlEntries, new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.(css)$/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{
loader: 'css-loader',
options: {
modules: true,
},
},
],
},
],
},
编译后,就会看到 index.html 中的 link 标签,把 css 文件单独导出了。
图片音乐字体等
这类资源的 rules 比较简单,只需要指定类型为 asset 就行。
{
test: /\.(svg|png|jpg|gif|woff|woff2|eot|ttf|otf|mp3|webp)$/,
type: 'asset',
},