loader
1 官方文档:
https://www.webpackjs.com/api/loaders/
2 基础模板
module.exports = function (source) {console.log('source', source)// 这里对source进行处理// .........// 处理完成后,将结果return出去return source}
3 说明
loader的功能就是将传进来的source,按照需求进行加工处理,将处理完的source返回出去,是一个函数,作用就是让任意类型的文件都能运行在浏览器中
2 编写原则
- 单一原则: 每个 Loader 只做一件事;
- 链式调用: Webpack 会按顺序链式调用每个 Loader;
统一原则: 遵循 Webpack 制定的设计规则和结构,输入与输出均为字符串,各个 Loader 完全独立,即插即用;
关键点
Loader 运行在 Node.js 中,我们可以调用任意 Node.js 自带的 API 或者安装第三方模块进行调用
- Webpack 传给 Loader 的原内容都是 UTF-8 格式编码的字符串,当某些场景下 Loader 处理二进制文件时,需要通过 exports.raw = true 告诉 Webpack 该 Loader 是否需要二进制数据
- 尽可能的异步化 Loader,如果计算量很小,同步也可以
- Loader 是无状态的,我们不应该在 Loader 中保留状态
- 使用 loader-utils 和 schema-utils 为我们提供的实用工具
- 加载本地 Loader 方法
- Npm link
- ResolveLoader
plugins
1 官方文档:
https://www.webpackjs.com/api/plugins/
2 基础模板
class DemoWebpackPlugin {constructor () {console.log('plugin init')}apply (compiler) {compiler.hooks.emit.tapAsync('DemoWebpackPlugin', (compilation, fn) => {console.log(compilation)})}}module.exports = DemoWebpackPlugin
3 说明
webpack在运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在特定的阶段钩入想要添加的自定义功能。Webpack 的 Tapable 事件流机制保证了插件的有序性,使得整个系统扩展性良好。
plugin类里面需要实现一个apply方法,webpack打包时候,会调用plugin的aplly方法来执行plugin的逻辑,这个方法接受一个compiler作为参数,这个compiler是webpack实例,compiler提供了本次打包的各个生命周期勾子,在这些钩子里实现需求
plugin是一个class类
4 compiler 、compilation
compiler
compiler 对象包含了Webpack 环境所有的的配置信息。这个对象在启动 webpack 时被一次性建立,并配置好所有可操作的设置,包括 options,loader 和 plugin。当在 webpack 环境中应用一个插件时,插件将收到此 compiler 对象的引用。可以使用它来访问 webpack 的主环境。
compilation
compilation对象包含了当前的模块资源、编译生成资源、变化的文件等。当运行webpack 开发环境中间件时,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。compilation 对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。
compiler和 compilation的区别在于
- compiler代表了当前这一次整个webpack从启动到关闭的生命周期,而compilation 只是代表了一次新的编译过程(比如我们改了一个文件,当前已经启动的webpack并没有先停下然后重新启动,而只是读取变更的文件重新编译了一下)
compiler和compilation暴露出许多钩子,我们可以根据实际需求的场景进行自定义处理
5 关键点:
compiler 暴露了和 Webpack 整个生命周期相关的钩子
- compilation 暴露了与模块和依赖有关的粒度更小的事件钩子
- 插件需要在其原型上绑定apply方法,才能访问 compiler 实例
- 传给每个插件的 compiler 和 compilation对象都是同一个引用,若在一个插件中修改了它们身上的属性,会影响后面的插件
- 找出合适的生命周期钩子去完成想要的功能
- emit 事件发生时,可以读取到最终输出的资源、代码块、模块及其依赖,并进行修改(emit 事件是修改 Webpack 输出资源的最后时机),用的较多
- watch-run 当依赖的文件发生变化时会触发
- 异步的事件需要在插件处理完任务时调用回调函数通知 Webpack 进入下一个流程,不然会卡住
6 plugins示例及使用(同步、异步)
- 新建一个webpack-demoWebpackPlugin.js
实现了一个在输出目录添加一个index.md文件的功能
class demoWebpackPlugin {constructor () {console.log('plugin init')}// compiler是webpack实例apply (compiler) {// 一个新的编译(compilation)创建之后(同步)// compilation代表每一次执行打包,独立的编译compiler.hooks.compile.tap('DemoWebpackPlugin', compilation => {console.log(compilation)})// 生成资源到 output 目录之前(异步)compiler.hooks.emit.tapAsync('DemoWebpackPlugin', (compilation, fn) => {console.log(compilation)compilation.assets['index.md'] = {// 文件内容source: function () {return 'this is a demo for plugin'},// 文件尺寸size: function () {return 25}}fn()})}}module.exports = demoWebpackPlugin
- webpack.config.js中使用该plugin
```javascript
const path = require(‘path’)
const DemoWebpackPlugin = require(‘webpack-demoWebpackPlugin.js’)
module.exports = {
// 省略其他代码
plugins:[
] }new demoWebpackPlugin()
```
