webpack
Favori,
图:Nguyen Nhut
功能
- 代码转换 (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 转换成文件输出
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
loader: "vue-loader",
},
{ test: /\.js$/, use: "babel-loader" },
{
test: /\.css$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
{ loader: "postcss-loader" },
],
},
],
},
};
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 提供的回调
插件示例:
// 一个 JavaScript 命名函数。
function MyExampleWebpackPlugin() {}
// 在插件函数的 prototype 上定义一个 apply 方法。
MyExampleWebpackPlugin.prototype.apply = function (compiler) {
// 指定一个挂载到 webpack 自身的事件钩子。
compiler.plugin(
"webpacksEventHook",
function (compilation /* 处理 webpack 内部实例的特定数据。*/, callback) {
console.log("This is an example plugin!!!");
// 功能完成后调用 webpack 提供的回调。
callback();
复制代码;
}
);
};
webpack 如何优化前端性能
- 第三方库按需加载、路由懒加载
- 代码分割
提取第三方库「vendor」
依赖库分离「splitChunks」
optimization: {
splitChunks: {
chunks: "async", // 必须三选一: "initial" | "all"(推荐) | "async" (默认就是async)
minSize: 30000, // 最小尺寸,30000
minChunks: 1, // 最小 chunk ,默认1
maxAsyncRequests: 5, // 最大异步请求数, 默认5
maxInitialRequests : 3, // 最大初始化请求书,默认3
automaticNameDelimiter: '~',// 打包分隔符
name: function(){}, // 打包后的名称,此选项可接收 function
cacheGroups:{ // 这里开始设置缓存的 chunks
priority: 0, // 缓存组优先级
vendor: { // key 为entry中定义的 入口名称
chunks: "initial", // 必须三选一: "initial" | "all" | "async"(默认就是async)
test: /react|lodash/, // 正则规则验证,如果符合就提取 chunk
name: "vendor", // 要缓存的 分隔出来的 chunk 名称
minSize: 30000,
minChunks: 1,
enforce: true,
maxAsyncRequests: 5, // 最大异步请求数, 默认1
maxInitialRequests : 3, // 最大初始化请求书,默认1
reuseExistingChunk: true // 可设置是否重用该chunk
}
}
}
}