2.Webpack:loader 和 plugin
wabicai
# 2.Webpack:loader 和 plugin
# 什么是 loader
loader用于对模块的源代码进行转换,在import或"加载"模块时预处理文件- 因为 webpack 只认识 js,所以需要 loader 对其他文件进行预处理
- 比如将 css 文件中的
.a font-size 20px;
1
转为
document.getElementById("style").innerHTML = ".a { font-size: 20px }";
1
# 什么是 plugin
plugin赋予 webpack 各种灵活的功能,例如打包优化、资源管理、环境变量注入等,它们会运行在webpack的不同阶段(钩子 / 生命周期),贯穿了webpack整个编译周期
# 常见的 loader 和 plugin
在页面开发过程中,我们经常性加载除了js文件以外的内容,这时候我们就需要配置响应的loader进行加载
常见的loader如下:
- style-loader: 将 css 添加到 DOM 的内联样式标签 style 里
- css-loader :允许将 css 文件通过 require 的方式引入,并返回 css 代码
- less-loader: 处理 less
- postcss-loader: 用 postcss 来处理 CSS,处理 CSS3 属性前缀,
- file-loader: 分发文件到 output 目录并返回相对路径
- url-loader: 和 file-loader 类似,但是当文件小于设定的 limit 时可以返回一个 Data Url
- html-minify-loader: 压缩 HTML
- babel-loader :用 babel 来转换 ES6 文件到 ES
- i18n-loader: 国际化
- cache-loader: 可以在一些性能开销较大的 Loader 之前添加,目的是将结果缓存到磁盘里
常见的 plugin:
- define-plugin:定义环境变量
- webpack-bundle-analyzer: 可视化 Webpack 输出文件的体积 (业务组件、依赖第三方模块)
- mini-css-extract-plugin: 分离样式文件,CSS 提取为独立文件,支持按需加载 (替代 extract-text-webpack-plugin)
- webpack-dashboard:可以更友好的展示相关打包信息。
- webpack-merge:提取公共配置,减少重复配置代码
- speed-measure-webpack-plugin:简称 SMP,分析出 Webpack 打包过程中 Loader 和 Plugin 的耗时,有助于找到构建过程中的性能瓶颈。
- size-plugin:监控资源体积变化,尽早发现问题
- HotModuleReplacementPlugin:模块热替换
- 目的在于解决
loader无法实现的其他事
# Loader 和 Plugin 的区别
- Loader 本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。 因为 Webpack 只认识 JavaScript,所以 Loader 就成了翻译官。
- 对于
loader,实质是一个转换器,将 A 文件进行编译形成 B 文件,操作的是文件,比如将A.scss或A.less转变为B.css,单纯的文件转换过程
- 对于
- 在
Webpack运行的生命周期中会广播出许多事件,Plugin可以监听这些事件,在合适的时机通过Webpack提供的API改变输出结果
# 自定义 loader
# 同步 loader
function test1(content, sourceMap, meta) {
// 1.
// return content
// 2.error, content, SourceMap, 是否是AST语法树
// this.callback(null,content,sourceMap,abstractSyntaxTree)
// return
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 异步 loader
module.exports = function (source) {
// 调用 this.async() API,告诉 webpack本次转换是异步的,loader 会在 callback 中返回结果
const callback = this.async();
// 使用 setTimeout 模拟异步过程
setTimeout(() => {
const content = source.replace("hello", "哈哈");
// 通过 callback 返回执行异步后的结果
callback(null, content);
}, 3000);
};
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 实战自定义 loader
- mini 版 style-loader
module.exports = function (source) {
return `const styleTag = document.createElement('style');
styleTag.innerHTML = ${source};
document.head.appendChild(styleTag);
`;
};
1
2
3
4
5
6
2
3
4
5
6
- mini 版 css-loader
module.exports = function (source) {
return JSON.stringify(source);
};
1
2
3
2
3
# 自定义 plugin
# plugin 能做,loader 不能做的事情
- 代码压缩、文件拆分、Tree Shaking、清理旧文件、生成统计报告、
# loader 能做,plugin 不能做的事情
# babel-loader:ES6 转 ES5
这是一个文件级别的操作,需要在每个.js 文件被加载时进行。Plugin 在这种情况下无法工作,因为它们操作的是整个编译过程,而不是单个文件。
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
},
},
},
],
},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# plugin 和 loader 都能做的事情
# 执行顺序
- loader:从右到左,从下到上,先于 plugin 执行
- plugin:在 loader 之后,并且是事件驱动的