集成react
集成 react
,安装依赖。
npm i react react-dom -Snpm i @babel/preset-react -D复制代码
配置 babel.config.js
。
// babel.config.jsmodule.exports = { presets: [ ["@babel/preset-react", {}] ]}复制代码
集成vue
集成 vue
,安装依赖。这个其实跟 babel
没啥关系,顺便在这写了。
要注意 vue
和 vue-template-compiler
的版本要保持一致。
npm i vue vue-loader vue-template-compiler -D复制代码
配置 webpack.config.js
。
// webpack.config.jsconst { VueLoaderPlugin } = require('vue-loader')module.exports = { module: { rules: [ // ... 其它规则 { test: /.vue$/, loader: 'vue-loader' } ] }, plugins: [ // 请确保引入这个插件! new VueLoaderPlugin() ]}复制代码
实现自定义plugin
plugin的结构
根目录下新建 myPlugins/my-plugin.js
。
plugin
的实质就是一个类。通过构造函数接收 options
配置。每个 plugin
必须内置一个 apply
方法,该方法接收一个参数 compiler
,就是实例化的 webpack
,其中包含配置等信息。
// my-plugin.jsclass MyPlugin { constructor(options) { console.log('????????~ options:', options); } apply(compiler) { // console.log('????????~ : my-plugin'); }}module.exports = MyPlugin复制代码
plugin的引用
新建实例的方式引用,可以在创建实例的时候传递 options
。
// webpack.config.jsconst MyPlugin = require("./myPlugins/my-plugin")module.exports = { plugins: [ new MyPlugin({ name: '一尾流莺' }) ]}复制代码
plugin的编写
怎么确定 plugin
的执行时机?
其实 webpack
也是有生命周期钩子的。我们可以来看一下都有哪些钩子。
// 跟目录下新建 webpack.js 然后通过 node webpack.js 启动// 引入 webpackconst webpack = require("webpack")// 引入配置文件const config = require("./webpack.config.js")// 根据配置文件 生产 webpack 实例const compiler = webpack(config)// 打印 webpack 的 生命周期钩子Object.keys(compiler.hooks).forEach((hookName) => { compiler.hooks[hookName].tap("xxx", (compilation) => { console.log('????????~ hookName:', hookName); })})// 执行 编译compiler.run()复制代码
所有的生命周期钩子都在 compiler.hooks
属性上,所以我们遍历打印出来的结果如下:
可以看到 webpack
的生命周期钩子实在是太多了。
所以我们的 plugin
的事件只需要注册在对应的生命周期钩子上就可以了,然后 webpack
就会在恰当的时机通过我们自己的 plugin
了。
class MyPlugin { constructor(options) { } // 接收一个参数 compiler 就是实例化的webpack 包含配置等信息 apply(compiler) { // 注册事件 同步钩子用tap 异步钩子用tapAsync注册 // 事件名称可以为任意值,建议和插件名称保持语义一致 compiler.hooks.emit.tapAsync('xxx', (compilation, cb) => { // compilation 半成品 console.log('????????~ compilation:', compilation.assets); const content = 'hello,plugin xxxxx' // 添加静态资源 compilation.assets['warbler.txt'] = { source: function() { return content }, // 只是用来查看的,并不会影响文件真实大小 size: function() { return content.length } } cb() }) }}module.exports = MyPlugin复制代码
通过 apply
方法的 compiler
参数进行事件的注册,可以注册在任何一个生命周期中,但是有的生命周期是同步的,有的是异步的,具体的还是要查看官网。
同步钩子用 tap
注册事件, 异步钩子用 tapAsync
注册事件。
如果是异步钩子的话, 需要在事件的回调中传递一个 cb
参数,并在最后调用一下。
事件名称可以为任意值,建议和插件名称保持语义一致,方便阅读源码,理解功能。
事件回调的 compilation
参数就是上一个钩子执行过后的半成品,属性有很多,可以阅读官网。