> webpack-loader-demo@1.0.0 test
> jest
console.log
loader before: Hey [name]!
at Object.log (src/loader.js:4:11)
console.log
loader after: Hey Alice!
at Object.log (src/loader.js:8:11)
PASS test/loader.test.js
✓ Inserts name and outputs JavaScript (1226 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.859 s, estimated 2 s
Ran all test suites.
原文:https://webpack.js.org/contribute/writing-a-loader/#setup demo仓库:https://github.com/FrankKai/webpack-loader-demo
什么是loader
loader是导出了一个函数的node模块。 这个函数会在资源被这个loader转换时,调用。这个函数,通过this上下文,拥有Loader的API。
安装
在我们深入不同类型的loader之前,它们的用法,它们的示例前,先看看你可以在本地开发和测试的3种方式。
为了测试单个loader,你可以在rule对象中,使用path去解析一个本地文件:
如果想测试多个文件,可以利用resolveLoader.modules配置去升级webpack搜索多个loader。例如,如果你有本地的/loaders目录:
如果拆了仓库或者包出去,可以使用npm link测试。
简单用法
当一个loader应用到资源时,loader只会接收一个参数被调用-这个参数是一个包含了资源文件内容的字符串。
同步loader可以返回一个单值,这个值代表转化后的模块。在更复杂的场景中,loader可以通过this.callback(err, values...)函数返回任意数量的值。异常也可以传。
loader需要一个或者两个值。第一个值是string或者buffer类型的js代码。第二个值是SourceMap类型的js对象。
复杂用法
当多个loader链式处理时,有一点很重要,他们会以逆序执行,从右到左还是从下到上取决于数组的格式。
在下面这个例子中,foo-loader会被传入raw(生的)资源,并且bar-loader会接收foo-loader的输出,并且返回最终转化后的模块和source map。
指南
指南部分是写loader的详细部分。根据重要性排序,有一些仅在特定场景下使用,阅读详细章节去获得更多信息。
简约
loader应该只做一个任务。这不仅仅会让维护每个loader变得更容易,同样也可以允许它们被任意链式组合,在更多场景使用。
链式转化
用加载器可以链接在一起这一事实。不要在一个loader里对付5个任务,而是拆成5个简单loader各自分工。隔离它们不仅保持单个独立loader的简洁性,而且允许它们在一些你没有预料到的场景中使用。
假设现在有一个场景,通过loader选项或者查询参数渲染一个模板文件。可以通过写一个单loader,通过资源编译模板,执行它,并且返回一个模块,这个模块导出一个包含了HTML代码的字符串。
但是,根据指南,存在可以与其他开源加载器链接的应用加载器:
模块化
将输出模块化。loader生成的模块,需要尊重和常规模块一样的设计原则。
无状态
确保loader在转换模块时,不保持状态。每次运行都应始终独立于其他已编译的模块,以及同一模块的先前编译。
loader工具库
loader-utils提供了一系列有用的工具。schema-utils可用于对持续的用于loader配置的JSON Schema做校验。这里有一个简单的使用utilizes的例子:
loader 依赖
如果一loader使用了额外的资源,必须要标明它。此信息用于使可缓存加载程序无效并在监视模式下重新编译。这里有一个使用addDependency方法来添加loader依赖的例子:
模块依赖
取决于模块的类型,可以使用不同的schema去指明依赖。例如在CSS,@import和url(...)语句会用到。这些依赖应该被模块系统解析。
有下面两种实现方式:
css-loader就是第一种方法的典型例子。它将依赖转换为requires,通过替换@import语句为require另一个样式表以及url(...)也通过require去引用文件。
对于less-loader,它不能加个每个@import转换为require,因为所有的.less文件必须被编译一次,从而进行变量和mixin追踪。因此,less-loader使用自定义的路径解析逻辑,去扩展了less编译器。就是利用第二种方式,this.resolve去实现的,通过webpack去解析依赖。
抽离 通用代码
避免在每一个loader进行中都生成通用的代码。取而代之的是,在loader中创建一个运行时文件,并且为共享模块生成一个require:
铺垫了这么多,终于可以写loader了
绝对路径
不要插入绝对路径,因为如果项目根路径发生变化时,会导致哈希崩溃。有一个叫做stringifyRequest方法在loader-utils中,可用于转换绝对路径为相对路径。
对等依赖
如果loader是另一个包的简单包装器,你需要将这个包裹作为对等依赖。这个方法允许应用的开发者在package.json去声明精确的版本。
例如sass-loader声明了node-sass为对等依赖
测试
使用Jest测试loader,并且使用babel-jest是的我们可以用import/export以及async/await。
我们的loader将处理.txt类型的文件并且通过loader的name option去替换任意的[name]示例。然后它将输出一个包含了default export文本的有效的js模块:
我们将用这个loader去处理下面这个文件:
test/example.txt
请注意,我们后面将使用nodejs以及memfs去运行webpack。这可以允许我们不将output输出到磁盘上并且去观察状态。
现在,我们写一个测试和npm script去运行。
package.json
成功了! 现在开始,你可以去开发、测试、部署你自己的loader。我们期待在社区中分享你的灵感和创造!