「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。
webpack使用时间久了,只是会使用loader已经不能让我起飞了。为了在兄弟们面前吹上一把,我决定彻底撸会webpack loader开发。
废话不多说,如果还有对loader使用不太清楚的,建议先去看一下 loader教程 ,不然会让我唠的云里雾里的。
开发loader的正确姿势
编写 loader 时应该遵循以下准则。它们按重要程度排序,但是有些仅适用于某些特殊场景。
- 简单易用。
- 使用链式传递。
- 模块化的输出。
- 确保无状态。
- 使用 loader utilities。
- 记录 loader 的依赖。
- 解析模块依赖关系。
- 提取通用代码。
- 避免绝对路径。
- 使用 peer dependencies。
姿势摆好,正式开撸
- 入口文件
webpack是基于node环境的,所以我们开发loader的时候,使用commonJs开发规范。
module.exports = function (source) {
// 处理 source ...
return newSource;
}
需要特别注意的地方
返回的source必需是 string 或者 buffer 类型
module.exports导出的方法不能使用箭头函数,如果使用箭头函数,this将指向global;正常情况下,this指向调用上下文,也就是webpack执行 runLoaders 的时候,传入的loaderContext
- 获取loader的options
相信大家配置webpack的rules的时候,肯定或多或少的时候了loader的options属性,那么loader中又是如何拿到大家配置的options呢?下面我们就一起看一下getOptions这个方法。
没错,我承认了,getOptions这个方法就是用来获取配置的options的,那这个方法从哪里获取呢,就是我们前文说到的this上。
当然,还有一种方式哈,可以通过 loader-utils 提供的 getOptions 方法获取。
虽然说结果是一样的,但是小编比较推荐第二种(webpack上dome是这样的,不是乱说的)
- 利用缓存
对于某些处理资源非常消耗性能的,推荐使用缓存进行优化。使用缓存之后,如果需要处理的资源和依赖的资源没有发生变化,生成的结果必然是相同的
// 开启缓存
this.cacheable(false)
// 关闭缓存
this.cacheable(true)
- 异步方法
通过async方法告诉 webpack 本次转换是异步的,并获取到 callback 方法
const callback = this.async();
然后,在 webpack 异步执行完成之后,通过 callback 方法,将转换结果通知到 webpack
callback(err, result, ...);
- loader 依赖
如果一个 loader 使用外部资源(例如,从文件系统读取),必须声明它。这些信息用于使缓存 loaders 无效,以及在观察模式(watch mode)下重编译。
const headerPath = path.resolve('header.js');
this.addDependency(headerPath);
如果不添加
this.addDependency的话项目并不会报错,只是在观察模式下,如果依赖的文件发生了变化生成的bundle文件并不能及时更新。
测试姿势
本地调试loader的三种方法
- 单个 loader,你可以简单通过在 rule 对象设置
path.resolve指向这个本地文件
{
test: /.js$/
use: [
{
loader: path.resolve('path/to/loader.js'),
options: {/* ... */}
}
]
}
- 多个 loaders,你可以使用
resolveLoader.modules配置,webpack 将会从这些目录中搜索这些 loaders
resolveLoader: {
modules: [
'node_modules',
path.resolve(__dirname, 'loaders')
]
}
- npm link
首先在打包好的loader项目中执行 npm link命令,然后在测试的项目中通过 npm link xxx 的方式将loader引入,接下来就可以跟npm install安装的依赖一样使用了