webpack 核心概念和手写 plugin
webpack 常用概念
Entry :项目入口,指示 webpack 应该使用哪个模块,来作为构建气内部依赖图的头节点
Output :输出,告诉 webpack 在哪里输入它所创建的 bundle,以及如何命名这些输出文件
Module :一个模块对应于一个文件,模块之间由引用关系构成依赖树
Chunk :构建后的代码块,一个 chunk 是多个模块分割合并构建后的结果
Loader :模块转换器,webpack 之所以可以处理不同类型的文件,是因为有一个个处理这些文件的 loader,loader 中的代码可以拿到文件的内容和 webpack 的配置,以处理文件并用于后面构建流程的输出
Plugin :功能插件。在 webpack 构建管道中,会广播很多事件,在 plugin 中,可以监听这些事件用于处理不同时机的流程。
比如打包压缩,资源管理,注入环境变量。Mode:模式,告知 webpack 使用相应模式的内置优化
Browser Compatibility:浏览器兼容性,Webpack 支持所有符合 ES5 标准 的浏览器(IE8 以上版本)
webpack 的常用功能
- 代码分割
- 文件合并压缩
- ES5 兼容
- 按需加载
- 代码校验
- Tree Shaking
- 模块热替换等
Plugin 概念
webpack 构建的过程类似一个管道,处理依赖树是要经过多个流程节点的,且下一个流程节点会受上一个节点的影响。
插件的功能就是向这些节点中插入一段流程,用来处理流程。
对于 loader,它就是一个转换器,将 A 文件进行编译形成 B 文件,这里操作的是文件,比如将 A.scss 或 A.less 转变为 B.css,单纯的文件转换过程
plugin 是一个扩展器,它丰富了 wepack 本身,针对是 loader 结束后,webpack 打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听 webpack 打包过程中的某些节点,执行广泛的任务。
常用 Plugin
1,copy-webpack-plugin
将已经存在的单个文件或整个目录复制到构建目录
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "./template/page.html",
to: `${__dirname}/output/cp/page.html`
}
]
})
]
};
2,html-webpack-plugin
基本作用是生成 html 文件
要生成多个 html 文件,可以配置多套
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: {
news: [path.resolve(__dirname, "../src/news/index.js")],
video: path.resolve(__dirname, "../src/video/index.js")
},
plugins: [
new HtmlWebpackPlugin({
title: "news page", // 生成的文件名称 相对于webpackConfig.output.path路径而言
filename: "pages/news.html", // 生成filename的文件模板
template: path.resolve(__dirname, "../template/news/index.html"),
chunks: ["news"]
}),
new HtmlWebpackPlugin({
title: "video page", // 生成的文件名称
filename: "pages/video.html", // 生成filename的文件模板
template: path.resolve(__dirname, "../template/video/index.html"),
chunks: ["video"]
})
]
};
3,SplitChunksPlugin
代码分割
4,HotModuleReplacementPlugin
模块热更新(用于开发模式)
实现一个 plugin
/plugins/myPlugin.js
class myPlugin {
constructor(options) {
console.log('my plugins', options)
}
apply (compiler) {
compiler.plugin('compilation', compilation => {
console.log('myPlus1')
})
}
}
module.exports = myPlugin
webpack.config.js
const myPlugin = require('./plugins/myPlugin')
module.exports = {
entry: {
index: './src/js/index.js'
},
plugins: [
new myPlugin({ param: 'xxx' })
]
}
以上是一个最简单的plugin
- webpack启动后,先实例化一个plugin对象,然后调用其中的代码
- 调用到apply函数后,plugin会注册一个监听事件函数
- 当webpack管线出发事件广播的时候,这个监听事件的回调函数会被调用
- 回调函数里面可以拿到关于webpack管线上下文对象,从而可以操作webpack的行为
compiler对象
- 包含了webpack管线环境的所有信息,可以看作是webpack对象的一个实例。比如会包含loader,plugin,options
compilation对象
- webpack的对每个文件的编译,都会出发compilation事件,这个事件中的回调参数就是compilation对象,其中包含了所有本次文件编译的信息
事件流
- webpack通过管线来组织编译过程
- webpack的事件流机制保证了插件工作的有序性
- webpack的事件流运用了发布订阅模式
compiler.plugin('event-name', params => {
...
});
注意点
- compiler对象和compilation对象本身也能发布事件,在其他插件中就能监听到这些事件。
- 有些事件是异步的,异步事件会附带两个参数,第二个参数为回电函数
compiler.plugin('emit',function(compilation, callback) {
...
// 处理完毕后执行 callback 以通知 Webpack
// 如果不执行 callback,运行流程将会一直卡在这不往下执行
callback();
});
- 更多webpack钩子 可以查看