loader
// 只在 test 和 文件名匹配 中使用正则表达式 // 在 include 和 exclude 中使用绝对路径数组 // 尽量避免 exclude,更倾向于使用 include
loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块 (webpack 自身只理解 JavaScript)
- 导出为函数的javascript模块
- 链式调用 把上一个loader产生的结果或资源文件放进去
加载相应的资源文件 loader webpack 根据正则表达式,来确定应该查找哪些文件,并将其提供给指定的 loader
module.rules
{ test: Condition }:匹配特定条件。一般是提供一个正则表达式或正则表达式的数组,但这不是强制的。
{ include: Condition }:匹配特定条件。一般是提供一个字符串或者字符串数组,但这不是强制的。
{ exclude: Condition }:排除特定条件。一般是提供一个字符串或字符串数组,但这不是强制的。
module.resource
{ and: [Condition] }:必须匹配数组中的所有条件
{ or: [Condition] }:匹配数组中任何一个条件
{ not: [Condition] }:必须排除这个条件
loader API
loader:一个导出为函数的 JavaScript 模块。loader runner 会调用这个函数,函数的 this 上下文将由 webpack 填充 如果是单个处理结果,可以在同步模式中直接返回。 如果有多个处理结果,则必须调用 this.callback()。、 在异步模式中,必须调用 this.async(),来指示 loader runner 等待异步结果,它会返回 this.callback() 回调函数,随后 loader 必须返回 undefined 并且调用该回调函数。
- 'Raw' loader
默认情况下,资源文件会被转化为 UTF-8 字符串,然后传给 loader。通过设置 raw,loader 可以接收原始的 Buffer。
- Pitching loader
loader 总是从右到左地被调用。在实际(从右到左)执行 loader 之前,会先从左到右调用 loader 上的 pitch 方法。如果某个 loader 在 pitch 方法中给出一个结果,那么这个过程会回过身来,并跳过剩下的 loader
- this.version loader API的版本号 目前是2
- this.context 模块所在的目录
- this.request 被解析出来的request字符串
- this.callback
- 必须是 Error 或者 null
- 一个 string 或者 Buffer。
- 可选的:必须是一个可以被这个模块解析的 source map。
- 可选的:会被 webpack 忽略,可以是任何东西(例如一些元数据)。
- this.async 告诉loader-runner 这个函数将会异步回调,返回 this.callback
- this.data 在 pitch 阶段和正常阶段之间共享的 data 对象。
- this.cacheable 设置是否可缓存标志的函数
调用 this.cacheable(false) 关闭loader的缓存
- this.loaders 所有loader组成的数组 在pitch阶段可以写入
- this.loaderIndex 当前 loader 在 loader 数组中的索引。
- this.resource request 中的资源部分,包括 query 参数。
- this.resourcePath 资源文件的路径。
- this.resourceQuery 资源的query参数
- this.target 编译的目标。从配置选项中传递过来的。
- this.webpack 是否是由webpack编译 如果是webpack编译的 这个布尔值会被设置为真
- this.sourceMap 生成一个 source map
- this.emitWarning 发出警告this.emitWarning(warning)
- this.emitError 发出一个错误
- this.loadModule
解析给定的 request 到一个模块,应用所有配置的 loader ,并且在回调函数中传入生成的 source 、sourceMap 和 模块实例(通常是 NormalModule 的一个实例)。
- this.resolve 解析一个request
- this.addDependency 添加一个文件作为产生 loader 结果的依赖
- this.addContextDependency 添加一个文件夹作为产生loader结果的依赖
- this.clearDependencies 移除loader结果所有的依赖
- this.emitFile 产生一个文件
- this.fs 用于访问输入文件系统的属性
如何编写一个loader
用法准则
- 简单易用。
- 使用链式传递。
- 模块化的输出。
- 确保无状态。 在不同模块转换之间不保存状态
- 使用 loader utilities。 loader-utils schema-utils
- 记录 loader 的依赖。
- 解析模块依赖关系。 根据模块的不同,可能有不同的模式指定依赖关系。1.转换成require语句 2.使用this.resolve函数解析路径
- 提取通用代码。
- 避免绝对路径。 loader-utils中stringifyRequest 方法,可以将绝对路径转化为相对路径。
- 使用 peer dependencies。 把这个包作为一个 peerDependency 引入。在 package.json 中指定所需的确定版本。
链式调用loader时,他们会以相反的顺序执行,看数组的写法 从右往左或从下往上
- 最后的loader最早执行 会传入原始文件资源
- 第一个 loader 最后调用,期望值是传出 JavaScript 和 source map(可选)。
- 中间的 loader 执行时,会传入前一个 loader 传出的结果。
利用 loader 可以链式调用的优势。写五个简单的 loader 实现五项任务,而不是一个 loader 实现五项任务。功能隔离使 loader 更简单
loader工具库 loader-utils
最常用的工具:getOptions:获取传递给 loader 的选项 stringifyRequest 方法,可以将绝对路径转化为相对路径。 schema-utils
loader 依赖 以来一个外部资源
this.addDependency 如果一个 loader 使用外部资源 必须声明它
模块依赖
根据模块类型,可能会有不同的模式指定依赖关系。例如在 CSS 中,使用 @import 和 url(...) 语句来声明依赖。这些依赖关系应该由模块系统解析。
两种实现方式
- 通过把它们转化成 require 语句。 css-loader @import 语句替换为 require 其他样式文件,将 url(...) 替换为 require 引用文件。
- 使用 this.resolve 函数解析路径。 less-loader .less文件中的变量和混合跟踪都必须一次编译 所以不能将所有的@import 转化为 require,因此,less-loader 将 less 编译器进行了扩展,自定义路径解析逻辑,然后通过this.resolve解析
通用代码
避免在每个模块中生成通用的代码 ,你应该在 loader 中创建一个运行时文件,并生成 require 语句以引用该共享模块。
绝对路径
不要再模板代码中插入绝对路径 ,因为当根路径变化是 绝对路径也会变化
测试
- Jest babel-jest babel-preset-env允许import export async await
2.使用 Node.js API 和 memory-fs 去执行 webpack 允许我们访问获取转换模块的统计数据 stats
- 测试