webpack
webpack构建流程
从启动webpack构建到输出结果经历了一系列过程,它们是:
1. 解析webpack配置参数,合并从shell传入和webpack.config.js文件里配置的参数,生产最后的配置结果。
2. 注册所有配置的插件,好让插件监听webpack构建生命周期的事件节点,以做出对应的反应。
3. 从配置的entry入口文件开始解析文件构建AST语法树,找出每个文件所依赖的文件,递归下去。
4 。 在解析文件递归的过程中根据文件类型和loader配置找出合适的loader用来对文件进行转换。
5. 递归完后得到每个文件的最终结果,根据entry配置生成代码块chunk。
6. 输出所有chunk到文件系统。
webpack核心概念
entry
output
module
plugins
- Loader
其中 module 的作用是在 test 字段和文件名匹配成功时就用对应的 loader 对代
码进行编译,Webpack本身只认识 .js 、 .json 这两种类型的文件,而通过
loader,我们就可以对例如 css 等其他格式的文件进行处理。
module.exports = function (content) {
return replace(content);
};
loader的入口需要导出一个函数,这个函数要干的事情就是转换一个文件的内容。 函
数接收的参数content是一个文件在转换前的字符串形式内容,需要返回一个新的字符
串形式内容作为转换后的结果,所有通过模块化倒入的文件都会经过loader。从这里
可以看出loader只能处理一个个单独的文件而不能处理代码块
- 自定义loader
通过自制一个loader之后,可以总结得到webpack支持loader的功能,主要就是4步
读取配置文件webpack.config.js的module.rulesloader配置项,进行倒序迭代
根据正则匹配到对应的文件类型,同时再批量导入loader函数
倒序迭代调用所有loader函数
返回处理后的代码
- Plugin
plugin 则是一些插件,这些插件可以将对编译结果的处理函数注册在 Webpack 的
生命周期钩子上,在生成最终文件之前对编译的结果做一些处理。比如大多数场景下我
们需要将生成的 JS 文件插入到 Html 文件中去。就需要使用到 html-webpack-
plugin 这个插件,我们需要在配置中这样写。
class EndWebpackPlugin {
constructor(doneCallback, failCallback) {
this.doneCallback = doneCallback;
this.failCallback = failCallback;
}
apply(compiler) {
// 监听webpack生命周期里的事件,做相应的处理
compiler.plugin('done', (stats) => {
this.doneCallback(stats);
});
compiler.plugin('failed', (err) => {
this.failCallback(err);
});
// 通常emit 输出 asset 到 output 目录之前执行
// done 在 compilation 完成时执行。
// 例子 添加一个markdown文件来显示dist文件下所有的打包文件。
compiler.hooks.emit.tap('FileListPlugin', (compilation)=>{
// compilation 是webpack 工作流中抛出来的内容,很多东西在这里,要修改工作流就修改这个即可
let assets = compilation.assets;
let content = `## 文件名 资源大小 \r\n`;
// 遍历打包之后的文件列表
Object.entries(assets).forEach(([filename, stateObj])=>{
content += `- ${filename} ${stateObj.size()}\r\n`
})
// 每个文件都有 source (该文件内容) 和 size 该文件大小
assets[this.filename] = {
source(){
return content
},
size(){
return content.length
}
}
})
}
}
module.exports = EndWebpackPlugin;
// 使用
const FileListPlugin = require('./plugins/FileListPlugin');
module.exports = {
plugins:[
new FileListPlugin({
filename:'list.md'
}),
],
}
loader的入口需要导出一个class, 在new EndWebpackPlugin()的时候通过构造
函数传入这个插件需要的参数,在webpack启动的时候会先实例化plugin再调用
plugin的apply方法,插件需要在apply函数里监听webpack生命周期里的事件,
做相应的处理。 webpack plugin 里有2个核心概念:
Compiler: 从webpack启动到推出只存在一个Compiler,Compiler存放着webpack配置
Compilation: 由于webpack的监听文件变化自动编译机制,Compilation代表一次编译。
Compiler 和 Compilation 都会广播一系列事件。 webpack生命周期里有非常多
的事件可以在event-hooks和Compilation里查到。