Skip to content

Commit 653f2dc

Browse files
jsbugwangKimYangOfCatjacob-lcs
authored
docs(cn): translate src/content/contribute/writing-a-loader.mdx (#1339)
* 翻译 src/content/contribute/writing-a-loader.mdx ,webpack 5 和 4 这个文档有细微差异,因此主要参考 webpack 4 的翻译,原文未变化的地方保持一致。 * path.resolve加上代码引用,和原文做一定的对照。 * Apply suggestions from code review Co-authored-by: Kim Yang <Kim.Yang.GH@outlook.com> Co-authored-by: Jacob <jacob.lcs@qq.com>
1 parent c01a182 commit 653f2dc

File tree

1 file changed

+75
-73
lines changed

1 file changed

+75
-73
lines changed

src/content/contribute/writing-a-loader.mdx

Lines changed: 75 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Writing a Loader
2+
title: 编写 loader
33
sort: 2
44
contributors:
55
- asulaiman
@@ -9,15 +9,17 @@ contributors:
99
- jamesgeorge007
1010
- chenxsan
1111
- dev-itsheng
12+
translators:
13+
- jsbugwang
1214
---
1315

14-
A loader is a node module that exports a function. This function is called when a resource should be transformed by this loader. The given function will have access to the [Loader API](/api/loaders/) using the `this` context provided to it.
16+
loader 是导出为一个函数的 node 模块。该函数在 loader 转换资源的时候调用。给定的函数将调用 [Loader API](/api/loaders/),并通过 `this` 上下文访问。
1517

16-
## Setup $#setup$
18+
## 设置 $#setup$
1719

18-
Before we dig into the different types of loaders, their usage, and examples, let's take a look at the three ways you can develop and test a loader locally.
20+
在深入研究不同 loader 以及他们的用法和例子之前,我们先看三种本地开发测试的方法。
1921

20-
To test a single loader, you can use `path` to `resolve` a local file within a rule object:
22+
匹配(test)单个 loader,你可以通过在 rule 对象使用 `path.resolve` 指定一个本地文件:
2123

2224
**webpack.config.js**
2325

@@ -44,7 +46,7 @@ module.exports = {
4446
};
4547
```
4648

47-
To test multiple, you can utilize the `resolveLoader.modules` configuration to update where webpack will search for loaders. For example, if you had a local `/loaders` directory in your project:
49+
匹配(test)多个 loaders,你可以使用 `resolveLoader.modules` 配置,webpack 将会从这些目录中搜索这些 loaders。例如,如果你的项目中有一个 `/loaders` 本地目录:
4850

4951
**webpack.config.js**
5052

@@ -59,27 +61,27 @@ module.exports = {
5961
};
6062
```
6163

62-
By the way, if you've already created a separate repository and package for your loader, you could [`npm link`](https://docs.npmjs.com/cli/link) it to the project in which you'd like to test it out.
64+
顺便提一下,如果你已经为 loader 创建了独立的库和包,你可以使用 [`npm link`](https://docs.npmjs.com/cli/link) 来将其链接到你要测试的项目。
6365

64-
T> You can use [`webpack-defaults` package](https://github.com/webpack-contrib/webpack-defaults) to generate boilerplate code necessary to start writing your loader.
66+
T> 你可以用 [`webpack-defaults` package](https://github.com/webpack-contrib/webpack-defaults) 来生成开始编写 loader 必要的样板代码(boilerplate code)。
6567

66-
## Simple Usage $#simple-usage$
68+
## 简单用法 $#simple-usage$
6769

68-
When a single loader is applied to the resource, the loader is called with only one parameter – a string containing the content of the resource file.
70+
当一个 loader 在资源中使用,这个 loader 只能传入一个参数 - 一个包含资源文件内容的字符串。
6971

70-
Synchronous loaders can `return` a single value representing the transformed module. In more complex cases, the loader can return any number of values by using the `this.callback(err, values...)` function. Errors are either passed to the `this.callback` function or thrown in a sync loader.
72+
同步 loader 可以 `return` 一个代表已转换模块(transformed module)的单一值。在更复杂的情况下,loader 也可以通过使用 `this.callback(err, values...)` 函数,返回任意数量的值。错误要么传递给这个 `this.callback` 函数,要么抛给(thrown in)同步 loader
7173

72-
The loader is expected to give back one or two values. The first value is a resulting JavaScript code as string or buffer. The second optional value is a SourceMap as JavaScript object.
74+
loader 会返回一个或者两个值。第一个值的类型是 JavaScript 代码的字符串或者 buffer。第二个可选值是 SourceMap,它是个 JavaScript 对象。
7375

74-
## Complex Usage $#complex-usage$
76+
## 复杂用法 $#complex-usage$
7577

76-
When multiple loaders are chained, it is important to remember that they are executed in reverse order – either right to left or bottom to top depending on array format.
78+
当链式调用多个 loader 的时候,请记住它们是反方向执行的。取决于数组写法格式,从右向左或者从下向上执行。
7779

78-
- The last loader, called first, will be passed the contents of the raw resource.
79-
- The first loader, called last, is expected to return JavaScript and an optional source map.
80-
- The loaders in between will be executed with the result(s) of the previous loader in the chain.
80+
- 最后的 loader 最早调用,将会传入原始资源(raw resource)内容。
81+
- 第一个 loader 最后调用,期望值是传出 JavaScript source map(可选)。
82+
- 中间的 loader 执行时,会传入前一个 loader 的结果。
8183

82-
In the following example, the `foo-loader` would be passed the raw resource and the `bar-loader` would receive the output of the `foo-loader` and return the final transformed module and a source map if necessary.
84+
在下例中,`foo-loader` 被传入原始资源,`bar-loader` 将接收 `foo-loader` 的产出,返回最终转化后的模块和一个 source map(可选)
8385

8486
**webpack.config.js**
8587

@@ -97,48 +99,48 @@ module.exports = {
9799
};
98100
```
99101

100-
## Guidelines $#guidelines$
102+
## 用法准则(Guidelines) $#guidelines$
101103

102-
The following guidelines should be followed when writing a loader. They are ordered in terms of importance and some only apply in certain scenarios, read the detailed sections that follow for more information.
104+
编写 loader 时应该遵循以下准则。它们按重要程度排序,有些仅适用于某些场景,请阅读下面详细的章节以获得更多信息。
103105

104-
- Keep them **simple**.
105-
- Utilize **chaining**.
106-
- Emit **modular** output.
107-
- Make sure they're **stateless**.
108-
- Employ **loader utilities**.
109-
- Mark **loader dependencies**.
110-
- Resolve **module dependencies**.
111-
- Extract **common code**.
112-
- Avoid **absolute paths**.
113-
- Use **peer dependencies**.
106+
- 保持 **简单**
107+
- 使用 **链式** 传递。
108+
- **模块化** 的输出。
109+
- 确保 **无状态**
110+
- 使用 **loader utilities**
111+
- 记录 **loader 的依赖**
112+
- 解析 **模块依赖关系**
113+
- 提取 **通用代码**
114+
- 避免 **绝对路径**
115+
- 使用 **peer dependencies**
114116

115-
### Simple $#simple$
117+
### 简单(simple) $#simple$
116118

117-
Loaders should do only a single task. This not only makes the job of maintaining each loader easier, but also allows them to be chained for usage in more scenarios.
119+
loaders 应该只做单一任务。这不仅使每个 loader 易维护,也可以在更多场景链式调用。
118120

119-
### Chaining $#chaining$
121+
### 链式(chaining) $#chaining$
120122

121-
Take advantage of the fact that loaders can be chained together. Instead of writing a single loader that tackles five tasks, write five simpler loaders that divide this effort. Isolating them not only keeps each individual loader simple, but may allow for them to be used for something you hadn't thought of originally.
123+
利用 loader 可以链式调用的优势。写五个简单的 loader 实现五项任务,而不是一个 loader 实现五项任务。功能隔离不仅使 loader 更简单,可能还可以将它们用于你原先没有想到的功能。
122124

123-
Take the case of rendering a template file with data specified via loader options or query parameters. It could be written as a single loader that compiles the template from source, executes it and returns a module that exports a string containing the HTML code. However, in accordance with guidelines, an `apply-loader` exists that can be chained with other open source loaders:
125+
以通过 loader 选项或者查询参数得到的数据渲染模板为例。可以把源代码编译为模板,执行并输出包含 HTML 代码的字符串写到一个 loader 中。但是根据用法准则,已经存在这样一个 `apply-loader`,可以将它和其他开源 loader 串联在一起调用。
124126

125-
- `pug-loader`: Convert template to a module that exports a function.
126-
- `apply-loader`: Executes the function with loader options and returns raw HTML.
127-
- `html-loader`: Accepts HTML and outputs a valid JavaScript module.
127+
- `pug-loader`: 导出一个函数,把模板转换为模块。
128+
- `apply-loader`: 根据 loader 选项执行函数,返回原生 HTML
129+
- `html-loader`: 接收 HTML,输出一个合法的 JS 模块。
128130

129-
T> The fact that loaders can be chained also means they don't necessarily have to output JavaScript. As long as the next loader in the chain can handle its output, the loader can return any type of module.
131+
T> loader 可以被链式调用意味着不一定要输出 JavaScript。只要下一个 loader 可以处理这个输出,这个 loader 就可以返回任意类型的模块。
130132

131-
### Modular $#modular$
133+
### 模块化(modular) $#modular$
132134

133-
Keep the output modular. Loader generated modules should respect the same design principles as normal modules.
135+
保证输出模块化。loader 生成的模块与普通模块遵循相同的设计原则。
134136

135-
### Stateless $#stateless$
137+
### 无状态(stateless) $#stateless$
136138

137-
Make sure the loader does not retain state between module transformations. Each run should always be independent of other compiled modules as well as previous compilations of the same module.
139+
确保 loader 在不同模块转换之间不保存状态。每次运行都应该独立于其他编译模块以及相同模块之前的编译结果。
138140

139-
### Loader Utilities $#loader-utilities$
141+
### loader 工具库(Loader Utilities) $#loader-utilities$
140142

141-
Take advantage of the [`loader-utils`](https://github.com/webpack/loader-utils) package which provides a variety of useful tools. Along with `loader-utils`, the [`schema-utils`](https://github.com/webpack-contrib/schema-utils) package should be used for consistent JSON Schema based validation of loader options. Here's a brief example that utilizes both:
143+
充分利用 [`loader-utils`](https://github.com/webpack/loader-utils) 包。它提供了许多有用的工具,但最常用的一种工具是获取传递给 loader 的选项。[`schema-utils`](https://github.com/webpack-contrib/schema-utils) 包配合 `loader-utils`,用于保证 loader 选项,进行与 JSON Schema 结构一致的校验。这里有一个简单使用两者的例子:
142144

143145
**loader.js**
144146

@@ -165,15 +167,15 @@ export default function (source) {
165167

166168
console.log('The request path', urlToRequest(this.resourcePath));
167169

168-
// Apply some transformations to the source...
170+
// 对资源应用一些转换……
169171

170172
return `export default ${JSON.stringify(source)}`;
171173
}
172174
```
173175

174-
### Loader Dependencies $#loader-dependencies$
176+
### loader 依赖(loader dependencies) $#loader-dependencies$
175177

176-
If a loader uses external resources (i.e. by reading from filesystem), they **must** indicate it. This information is used to invalidate cacheable loaders and recompile in watch mode. Here's a brief example of how to accomplish this using the `addDependency` method:
178+
如果一个 loader 使用外部资源(例如,从文件系统读取),**必须**声明它。这些信息用于使缓存 loaders 无效,以及在观察模式(watch mode)下重编译。下面是一个简单示例,说明如何使用 `addDependency` 方法实现上述声明:
177179

178180
**loader.js**
179181

@@ -193,24 +195,24 @@ export default function (source) {
193195
}
194196
```
195197

196-
### Module Dependencies $#module-dependencies$
198+
### 模块依赖(module dependencies) $#module-dependencies$
197199

198-
Depending on the type of module, there may be a different schema used to specify dependencies. In CSS for example, the `@import` and `url(...)` statements are used. These dependencies should be resolved by the module system.
200+
根据模块类型,可能会有不同的模式指定依赖关系。例如在 CSS 中,使用 `@import` `url(...)` 语句来声明依赖。这些依赖关系应该由模块系统解析。
199201

200-
This can be done in one of two ways:
202+
可以通过以下两种方式中的一种来实现:
201203

202-
- By transforming them to `require` statements.
203-
- Using the `this.resolve` function to resolve the path.
204+
- 通过把它们转化成 `require` 语句。
205+
- 使用 `this.resolve` 函数解析路径。
204206

205-
The `css-loader` is a good example of the first approach. It transforms dependencies to `require`s, by replacing `@import` statements with a `require` to the other stylesheet and `url(...)` with a `require` to the referenced file.
207+
`css-loader` 是第一种方式的一个例子。它将 `@import` 语句替换为 `require` 其他样式文件,将 `url(...)` 替换为 `require` 引用文件,从而实现将依赖关系转化为 `require` 声明。
206208

207-
In the case of the `less-loader`, it cannot transform each `@import` to a `require` because all `.less` files must be compiled in one pass for variables and mixin tracking. Therefore, the `less-loader` extends the less compiler with custom path resolving logic. It then takes advantage of the second approach, `this.resolve`, to resolve the dependency through webpack.
209+
对于 `less-loader`,无法将每个 `@import` 转化为 `require`,因为所有 `.less` 的文件中的变量和混合跟踪必须一次编译。因此,`less-loader` `less` 编译器进行了扩展,自定义路径解析逻辑。然后,利用第二种方式,通过 webpack 的 `this.resolve` 解析依赖。
208210

209-
T> If the language only accepts relative urls (e.g. `url(file)` always refers to `./file`), you can use the `~` convention to specify references to installed modules (e.g. those in `node_modules`). In the case of `url`, that would look something like `url('~some-library/image.jpg')`.
211+
T> 如果语言只支持相对 url(例如 `url(file)` 总是指向 `./file`),通过使用 `~` 来指定已安装模块(例如,引用 `node_modules` 中的那些模块)。所以对于 `url`,相当于 `url('~some-library/image.jpg')`
210212

211-
### Common Code $#common-code$
213+
### 通用代码(common code) $#common-code$
212214

213-
Avoid generating common code in every module the loader processes. Instead, create a runtime file in the loader and generate a `require` to that shared module:
215+
避免在 loader 处理的每个模块中生成通用代码。相反,你应该在 loader 中创建一个运行时文件,并生成 `require` 语句以引用该共享模块:
214216

215217
**src/loader-runtime.js**
216218

@@ -230,7 +232,7 @@ module.exports = function runtime(params) {
230232
import runtime from './loader-runtime.js';
231233

232234
export default function loader(source) {
233-
// Custom loader logic
235+
// 自定义的 loader 逻辑
234236

235237
return `${runtime({
236238
source,
@@ -239,15 +241,15 @@ export default function loader(source) {
239241
}
240242
```
241243

242-
### Absolute Paths $#absolute-paths$
244+
### 绝对路径(absolute paths) $#absolute-paths$
243245

244-
Don't insert absolute paths into the module code as they break hashing when the root for the project is moved. There's a [`stringifyRequest`](https://github.com/webpack/loader-utils#stringifyrequest) method in `loader-utils` which can be used to convert an absolute path to a relative one.
246+
不要在模块代码中插入绝对路径,因为当项目根路径变化时,文件绝对路径也会变化。`loader-utils` 中的 [`stringifyRequest`](https://github.com/webpack/loader-utils#stringifyrequest) 方法,可以将绝对路径转化为相对路径。
245247

246-
### Peer Dependencies $#peer-dependencies$
248+
### 同等依赖(peer dependencies) $#peer-dependencies$
247249

248-
If the loader you're working on is a simple wrapper around another package, then you should include the package as a `peerDependency`. This approach allows the application's developer to specify the exact version in the `package.json` if desired.
250+
如果你的 loader 简单包裹另外一个包,你应该把这个包作为一个 `peerDependency` 引入。这种方式允许应用程序开发者在必要情况下,在 `package.json` 中指定所需的确定版本。
249251

250-
For instance, the `sass-loader` [specifies `node-sass`](https://github.com/webpack-contrib/sass-loader/blob/master/package.json) as peer dependency like so:
252+
例如,`sass-loader` [指定 `node-sass`](https://github.com/webpack-contrib/sass-loader/blob/master/package.json) 作为同等依赖,引用如下:
251253

252254
```json
253255
{
@@ -257,9 +259,9 @@ For instance, the `sass-loader` [specifies `node-sass`](https://github.com/webpa
257259
}
258260
```
259261

260-
## Testing $#testing$
262+
## 测试 $#testing$
261263

262-
So you've written a loader, followed the guidelines above, and have it set up to run locally. What's next? Let's go through a unit testing example to ensure our loader is working the way we expect. We'll be using the [Jest](https://jestjs.io/) framework to do this. We'll also install `babel-jest` and some presets that will allow us to use the `import` / `export` and `async` / `await`. Let's start by installing and saving these as a `devDependencies`:
264+
当你遵循上面的用法准则编写了一个 loader,并且可以在本地运行。下一步该做什么呢?让我们用一个简单的单元测试,来保证 loader 能够按照我们预期的方式正确运行。我们将使用 [Jest](https://jestjs.io/) 框架。然后还需要安装 `babel-jest` 和允许我们使用 `import` / `export` `async` / `await` 的一些预设环境(presets)。让我们开始安装,并且将这些依赖保存为 `devDependencies`
263265

264266
```bash
265267
npm install --save-dev jest babel-jest @babel/core @babel/preset-env
@@ -282,7 +284,7 @@ module.exports = {
282284
};
283285
```
284286

285-
Our loader will process `.txt` files and replace any instance of `[name]` with the `name` option given to the loader. Then it will output a valid JavaScript module containing the text as its default export:
287+
我们的 loader 将会处理 `.txt` 文件,并且将任何实例中的 `[name]` 直接替换为 loader 选项中设置的 `name`。然后返回包含默认导出文本的 JavaScript 模块:
286288

287289
**src/loader.js**
288290

@@ -296,15 +298,15 @@ export default function loader(source) {
296298
}
297299
```
298300

299-
We'll use this loader to process the following file:
301+
我们将会使用这个 loader 处理以下文件:
300302

301303
**test/example.txt**
302304

303305
```bash
304306
Hey [name]!
305307
```
306308

307-
Pay close attention to this next step as we'll be using the [Node.js API](/api/node) and [`memfs`](https://github.com/streamich/memfs) to execute webpack. This lets us avoid emitting `output` to disk and will give us access to the `stats` data which we can use to grab our transformed module:
309+
请注意留心接下来的步骤,我们将会使用 [Node.js API](/api/node) [`memfs`](https://github.com/streamich/memfs) 去执行 webpack。这让我们避免向磁盘产生 `输出文件`,并允许我们访问获取转换模块的统计数据 `stats`
308310

309311
```bash
310312
npm install --save-dev webpack memfs
@@ -352,9 +354,9 @@ export default (fixture, options = {}) => {
352354
};
353355
```
354356

355-
T> In this case, we've inlined our webpack configuration but you can also accept a configuration as a parameter to the exported function. This would allow you to test multiple setups using the same compiler module.
357+
T> 这种情况下,我们可以内联 webpack 配置,也可以把配置作为参数传给导出的函数。这允许我们使用相同的编译模块测试多个设置。
356358

357-
And now, finally, we can write our test and add an npm script to run it:
359+
最后,我们来编写测试,并且添加 npm script 运行它:
358360

359361
**test/loader.test.js**
360362

@@ -385,7 +387,7 @@ test('Inserts name and outputs JavaScript', async () => {
385387
}
386388
```
387389

388-
With everything in place, we can run it and see if our new loader passes the test:
390+
准备就绪后,我们可以运行它,然后看新的 loader 是否能通过测试:
389391

390392
```bash
391393
PASS test/loader.test.js
@@ -398,4 +400,4 @@ Time: 1.853s, estimated 2s
398400
Ran all test suites.
399401
```
400402

401-
It worked! At this point you should be ready to start developing, testing, and deploying your own loaders. We hope that you'll share your creations with the rest of the community!
403+
一切正常!现在,你应该准备开始开发、测试、部署你的 loaders 了。我们希望你可以在社区分享你的 loader!

0 commit comments

Comments
 (0)