webpack loader和plugin
# webpack Loader 和 Plugin
# 一、Loader 和 Plugin 的区别
不同的作用
Loader直译为"加载器"。Webpack 将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到 loader。
所以 Loader 的作用是让 webpack 拥有了加载和解析非 JavaScript 文件的能力。
Plugin直译为"插件"。Plugin 可以扩展 webpack 的功能,让 webpack 具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
不同的用法
Loader在 module.rules 中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个 Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
Plugin在 plugins 中单独配置。 类型为数组,每一项是一个 plugin 的实例,参数都通过构造函数传入。
# 二、Webpack 常见的 Loader
babel-loader
用babel
来转换ES6
文件到ES5
esbuild-loader
:加载 ES2015+ 代码并使用 esbuild 转译到 ES6+vue-loader
:加载并编译 Vue 组件css-loader
允许将css
文件通过import
的方式引入,并返回css
代码less-loader
处理 lesssass-loader
处理 sassimage-loader
:加载并且压缩图片文件eslint-loader
:通过 ESLint 检查 JavaScript 代码url-loader
:和file-loader
类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去html-minify-loader
压缩 HTML
// 下面的一组loader就是链式传递, 从 sass-loader 开始执行,然后继续执行 css-loader,最后以 style-loader 为结束
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
// 通过options配置
options: {
modules: true,
minimize: true
}
},
{ loader: 'sass-loader' }
]
2
3
4
5
6
7
8
9
10
11
12
13
- loader是webpack核心**,**用于对模块的源代码进行转换
- loader 支持链式调用,从右至左执行,支持同步或异步函数
# 三、手写一个 loader
Loader 像一个"翻译官"把读到的源文件内容转义成新的文件内容,并且每个 Loader 通过链式操作,将源文件一步步翻译成想要的样子。
编写 Loader 时要遵循单一原则,每个 Loader 只做一种"转义"工作。 每个 Loader 的拿到的是源文件内容(source),
可以通过返回值的方式将处理后的内容输出,
也可以调用 this.callback()方法,将内容返回给 webpack。
还可以通过 this.async()生成一个 callback 函数,再用这个 callback 将处理后的内容输出出去。
此外还可以使用 webpack 工具函数集——loader-utils。
例:写一个去除 console.log 的 loader
module.exports = function(content) {
return content.replace(/console.log\(['|"](.*?)['|"]\)/, '')
}
2
3
配置使用
module: {
rules: [
{
test: /\.js$/, // 对js文件使用
use: [
'console-loader'
],
},
],
},
2
3
4
5
6
7
8
9
10
11
# 四、手写一个 plugin
相对于 Loader 而言,Plugin 的编写就灵活了许多。 webpack在运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
写个插件记录打包
class OutLogPlugin {
constructor(options) {
this.outFileName = options.outFileName
}
apply(compiler) {
// 可以从编译器对象访问 webpack 模块实例
// 并且可以保证 webpack 版本正确
const { webpack } = compiler
// 获取 Compilation 后续会用到 Compilation 提供的 stage
const { Compilation } = webpack
const { RawSource } = webpack.sources
/** compiler.hooks.<hoonkName>.tap/tapAsync/tapPromise */
compiler.hooks.compilation.tap('OutLogPlugin', (compilation) => {
compilation.hooks.processAssets.tap(
{
name: 'OutLogPlugin',
// 选择适当的 stage,具体参见:
// https://webpack.js.org/api/compilation-hooks/#list-of-asset-processing-stages
stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE
},
(assets) => {
let resOutput = `buildTime: ${new Date().toLocaleString()}\n\n`
resOutput += `| fileName | fileSize |\n| --------- | --------- |\n`
Object.entries(assets).forEach(([pathname, source]) => {
resOutput += `| ${pathname} | ${source.size()} bytes |\n`
})
compilation.emitAsset(
`${this.outFileName}.md`,
new RawSource(resOutput)
)
}
)
})
}
}
module.exports = OutLogPlugin
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
配置使用
const OutLogPlugin = require('./plugins/OutLogPlugin')
module.exports = {
plugins: [new OutLogPlugin({ outFileName: 'buildInfo' })]
}
2
3
4
5
输出 md 文件内容
buildTime: 2021/12/1 下午 4:59:48
fileName | fileSize |
---|---|
bundle.js | 4398 bytes |
bundle.map.js | 4098 bytes |