功能
- 代码转换 (loaders)
- 文件优化,压缩代码,压缩图片
- 代码分割,提取公共代码
- 模块合并
- 自动刷新
常见配置
- Entry
- output
- mode
- Module
- Chunk
- Loader
- Plugin
原理/工作流程
- 参数解析:从配置文件和 shell 语句中读取与合并参数,得出最终的参数
- 找到入口文件:从 Entry 里配置的 Module 开始递归解析 Entry 依赖的所有 Module,生成 map 对象
- 调用 Loader 编译文件,每找到一个 Module,就会根据配置的 Loader 去找出对应的转换规则
- 遍历 AST,收集依赖:对 Module 进行转换后,再解析出当前 Module 依赖的 Module
- 生成 Chunk: 这些模块会以 Entry 为单位进行分组,一个 Entry 和其所有依赖的 Module 被分到一个组也就是一个 Chunk
- 输出文件:最后 Webpack 会把所有 Chunk 转换成文件输出
1// webpack.config.js2module.exports = {3 module: {4 rules: [5 {6 test: /\.vue$/,7 loader: "vue-loader",8 },9 { test: /\.js$/, use: "babel-loader" },10 {11 test: /\.css$/,12 use: [13 { loader: "style-loader" },14 { loader: "css-loader" },15 { loader: "postcss-loader" },16 ],17 },18 ],19 },20};
Loader 工作流
webpack.config.js 里配置了一个 模块 的 Loader;
遇到 相应模块 文件时,触发了 该模块的 loader;
loader 接受了一个表示该 模块 文件内容的 source;
loader 使用 webapck 提供的一系列 api 对 source 进行转换,得到一个 result;
将 result 返回或者传递给下一个 Loader,直到处理完毕。
Plugin
插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理。webpack 通过 Tapable 来组织这条复杂的生产线。 webpack 在编译过代码程中,会触发一系列 Tapable 钩子事件,插件所做的,就是找到相应的钩子,往上面挂上自己的任务,也就是注册事件,这样,当 webpack 构建的时候,插件注册的事件就会随着钩子的触发而执行了。
webpack 插件由以下组成:
- 一个 JavaScript 命名函数。
- 在插件函数的 prototype 上定义一个 apply 方法。
- 指定一个绑定到 webpack 自身的事件钩子。
- 处理 webpack 内部实例的特定数据。
- 功能完成后调用 webpack 提供的回调
插件示例:
1// 一个 JavaScript 命名函数。2function MyExampleWebpackPlugin() {}3// 在插件函数的 prototype 上定义一个 apply 方法。4MyExampleWebpackPlugin.prototype.apply = function (compiler) {5 // 指定一个挂载到 webpack 自身的事件钩子。6 compiler.plugin(7 "webpacksEventHook",8 function (compilation /* 处理 webpack 内部实例的特定数据。*/, callback) {9 console.log("This is an example plugin!!!");10 // 功能完成后调用 webpack 提供的回调。11 callback();12 复制代码;13 }14 );15};
webpack 如何优化前端性能
- 第三方库按需加载、路由懒加载
- 代码分割
提取第三方库「vendor」
依赖库分离「splitChunks」
1optimization: {2 splitChunks: {3 chunks: "async", // 必须三选一: "initial" | "all"(推荐) | "async" (默认就是async)4 minSize: 30000, // 最小尺寸,300005 minChunks: 1, // 最小 chunk ,默认16 maxAsyncRequests: 5, // 最大异步请求数, 默认57 maxInitialRequests : 3, // 最大初始化请求书,默认38 automaticNameDelimiter: '~',// 打包分隔符9 name: function(){}, // 打包后的名称,此选项可接收 function10 cacheGroups:{ // 这里开始设置缓存的 chunks11 priority: 0, // 缓存组优先级12 vendor: { // key 为entry中定义的 入口名称13 chunks: "initial", // 必须三选一: "initial" | "all" | "async"(默认就是async)14 test: /react|lodash/, // 正则规则验证,如果符合就提取 chunk15 name: "vendor", // 要缓存的 分隔出来的 chunk 名称16 minSize: 30000,17 minChunks: 1,18 enforce: true,19 maxAsyncRequests: 5, // 最大异步请求数, 默认120 maxInitialRequests : 3, // 最大初始化请求书,默认121 reuseExistingChunk: true // 可设置是否重用该chunk22 }23 }24 }25}