2. 配置静态文件名
默认情况下,打包以后的文件是散在 dist 文件夹中的,难以区分和维护。
现在,需要将他们分门别类地放进对应的文件夹中,就需要对文件名做统一的管理。
webpack.config.js
const path = require("path"); const miniSVGDataURI = require("mini-svg-data-uri"); module.exports = { mode: "production", entry: { main: "./src/index.js", }, output: { path: path.resolve(__dirname, "dist"), filename: "bundle.js", // 静态文件打包后的路径及文件名(默认是走全局的,如果有独立的设置就按照自己独立的设置来。) assetModuleFilename: "assets/[name]_[hash][ext]", }, module: { rules: [ // 图片文件 { test: /\.(jpe?g|png|gif)$/i, type: "asset", generator: { filename: "images/[name]_[hash][ext]", // 独立的配置 }, }, // svg 文件 { test: /\.svg$/i, type: "asset", generator: { dataUrl(content) { content = content.toString(); return miniSVGDataURI(content); }, }, }, // 字体文件 { test: /\.(otf|eot|woff2?|ttf|svg)$/i, type: "asset", generator: { filename: "fonts/[name]_[hash][ext]", }, }, // 数据文件 { test: /\.(txt|xml)$/i, type: "asset/source", // exports the source code of the asset }, ], }, };
第 23 - 25 行,用于单独配置静态文件名;
generator: { filename: 'images/[name]_[hash][ext]' // 单独配置打包的路径及文件名 },
第 12 行,assetModuleFilename: 'assets/[name][ext]',
用于设置全局的静态文件路径及文件名。如果文件模块没有单独进行配置,就按照这个来设置文件名。
其中,[name] 表示原来的文件名,[hash] 表示散列值,[ext] 表示文件后缀。这些都属于占位符(placeholders),在 webpack4 中有提到:v4.webpack.js.org/loaders/fil…
3. asset 类型
当 type 设置为'asset'
,就会按照以下的策略去打包文件:
- 如果一个模块大小超过 8 kb(这个值是默认的),就使用
asset/resource
,被打包进输出文件夹中。(类似于 file-loader) - 否则,就使用
asset/inline
,内联到打包文件中。(类似于 url-loader)
区别在于:前者会被单独放进输出文件夹中,后者被处理成 base64 编码字符串内敛进打包出的 JS 文件中。
后者的好处在于减少一次 http 请求,但是过长的字符串也会加重 js 的体积导致加载变慢,因此需要根据实际情况来确定到底采用哪一种方式去处理文件。
注意,当被作为后者处理时,是可以设置编码方式的,例如上面提到的特殊处理。
手动通过 Rule.parser.dataUrlCondition.maxSize
去设置两者的界限:
{ test: /\.(jpe?g|png|gif)$/i, type: 'asset', generator: { filename: 'images/[name]_[hash][ext]', }, parser: { dataUrlCondition: { maxSize: 8 * 1024 // 8kb (低于8kb都会压缩成 base64) } }, }, { test: /\.svg$/i, type: 'asset', generator: { filename: 'icons/[name]_[hash][ext]', dataUrl(content) { content = content.toString(); return miniSVGDataURI(content); // 通过插件提供的编码算法处理文件 } }, parser: { dataUrlCondition: { maxSize: 2 * 1024 // 2kb (低于2kb都会压缩) } }, },
另外,除了asset/resource
、asset/inline
,还有一个上文提到的,用于处理 txt、xml 文件的asset/source
,它相当于 webpack4 的 raw-loader。
三、样式文件的处理
1. style-loader & css-loader
style-loader 和 css-loader 是相辅相成的。
- style-loader:将
<style>
标签插入到 DOM 中。 - css-loader:解析通过 @import、url()、import/require() 这些方式引入的样式文件。
安装 loaders:
npm install --save-dev css-loader style-loader
webpack.config.js
module.exports = { module: { rules: [ // ... { test: /\.css$/i, use: ["style-loader", "css-loader"], }, ], }, };
注意两个 loader 的位置,要反过来写。
index.js
// ... const reset = require("./assets/styles/reset.css"); console.log("css: ", reset); import "./assets/styles/reset.css"; const dom = document.getElementById("root"); dom.innerHTML += '<p class="iconfont icon-mianxingshezhi">This a text.</p>';
reset.css
@font-face { font-family: "iconfont"; /* Project id 1947684 */ src: url("../fonts/iconfont.woff2?t=1627306378388") format("woff2"), url("../fonts/iconfont.woff?t=1627306378388") format("woff"), url("../fonts/iconfont.ttf?t=1627306378388") format("truetype"); } .iconfont { font-family: "iconfont" !important; font-size: 16px; font-style: normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .icon-mianxingshezhi:before { content: "\e6ad"; } /* ... */
解释:reset.css 中引入了字体图标(来自 iconfont),index.js 中通过import
的方式引入了这个 css 文件,并使用了这个字体图标。
其中,
import './assets/styles/reset.css'
、
onst reset = require('./assets/styles/reset.css');
这两段语句背后的 CSS 代码就是通过 css-loader 去解析的。
控制台展示如下:
上图中,在 CSS 样式被 css-loader 解析完成后, <style>
标签通过 style-loader 插入到 DOM 中。
2. sass-loader
- sass-loader:加载一个 Sass/SCSS 文件,并编译成 CSS。
安装:
npm install sass-loader sass webpack --save-dev
webpack.config.js
module.exports = { module: { rules: [ // ... { test: /\.s[ac]ss$/i, use: [ // Creates `style` nodes from JS strings "style-loader", // Translates CSS into CommonJS "css-loader", // Compiles Sass to CSS "sass-loader", ], }, ], }, };
index.js
const global = require("./assets/styles/global.scss"); console.log("scss: ", global); import "./assets/styles/global.scss"; const dom = document.getElementById("root"); // insert an image const img = new Image(); img.src = dog1; // img.width = 200; img.classList.add("avatar"); root.append(img);
global.scss
// 自定义变量 $color: #ff4200; $fs: 14px; $ls: 1.2; // 自定义mixin @mixin size($w, $h: $w) { width: $w; height: $h; } body { font-size: $fs; background-color: #eaeaea; .avatar { @include size(150px); transform: translateX(50px); } }
控制台展示如下:
上图第二个 <style>
标签内的样式代码就是 global.scss 中转译成 css,并通过 style-loader 插入到 DOM 中的。