@empjs/chain 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,1337 @@
1
+ # @empjs/chain
2
+
3
+
4
+
5
+ ## 介绍
6
+
7
+ webpack 的核心配置的创建和修改基于一个有潜在难于处理的 JavaScript 对象。虽然这对于配置单个项目来说还是 OK 的,但当你尝试跨项目共享这些对象并使其进行后续的修改就会变的混乱不堪,因为您需要深入了解底层对象的结构以进行这些更改。
8
+
9
+ `@empjs/chain` 尝试通过提供可链式或顺流式的 API 创建和修改webpack 配置。API的 Key 部分可以由用户指定的名称引用,这有助于 跨项目修改配置方式 的标准化。
10
+
11
+ 通过以下示例可以更容易地解释这一点。
12
+
13
+ ## 安装
14
+
15
+ `@empjs/chain` 需要 Node.js v18及更高版本.
16
+ `@empjs/chain` 也只创建并被设计于使用webpack的2,3,4版本的配置对象。
17
+
18
+ 你可以使用Yarn或者npm来安装此软件包(俩个包管理工具选一个就行):
19
+
20
+ ### **Yarn方式**
21
+
22
+ ```bash
23
+ yarn add --dev @empjs/chain
24
+ ```
25
+
26
+ ### **npm方式**
27
+
28
+ ```bash
29
+ npm install --save-dev @empjs/chain
30
+ ```
31
+
32
+ ## 入门
33
+
34
+ 当你安装了 `@empjs/chain`, 你就可以开始创建一个webpack的配置。 对于本指南,我们的示例基本配置 `webpack.config.js` 将位于我们项目的根目录。
35
+
36
+ ```js
37
+ // 导入 @empjs/chain 模块,该模块导出了一个用于创建一个webpack配置API的单一构造函数。
38
+ const Config = require('@empjs/chain');
39
+
40
+ // 对该单一构造函数创建一个新的配置实例
41
+ const config = new Config();
42
+
43
+ // 用链式API改变配置
44
+ // 每个API的调用都会跟踪对存储配置的更改。
45
+
46
+ config
47
+ // 修改 entry 配置
48
+ .entry('index')
49
+ .add('src/index.js')
50
+ .end()
51
+ // 修改 output 配置
52
+ .output
53
+ .path('dist')
54
+ .filename('[name].bundle.js');
55
+
56
+ // 创建一个具名规则,以后用来修改规则
57
+ config.module
58
+ .rule('lint')
59
+ .test(/\.js$/)
60
+ .pre()
61
+ .include
62
+ .add('src')
63
+ .end()
64
+ // 还可以创建具名use (loaders)
65
+ .use('eslint')
66
+ .loader('eslint-loader')
67
+ .options({
68
+ rules: {
69
+ semi: 'off'
70
+ }
71
+ });
72
+
73
+ config.module
74
+ .rule('compile')
75
+ .test(/\.js$/)
76
+ .include
77
+ .add('src')
78
+ .add('test')
79
+ .end()
80
+ .use('babel')
81
+ .loader('babel-loader')
82
+ .options({
83
+ presets: [
84
+ ['@babel/preset-env', { modules: false }]
85
+ ]
86
+ });
87
+
88
+ // 也可以创建一个具名的插件!
89
+ config
90
+ .plugin('clean')
91
+ .use(CleanPlugin, [['dist'], { root: '/dir' }]);
92
+
93
+ // 导出这个修改完成的要被webpack使用的配置对象
94
+ module.exports = config.toConfig();
95
+ ```
96
+
97
+ 共享配置也很简单。仅仅导出配置 和 在传递给webpack之前调用 `.toConfig()` 方法将配置导出给webpack使用。
98
+
99
+ ```js
100
+ // webpack.core.js
101
+ const Config = require('@empjs/chain');
102
+ const config = new Config();
103
+
104
+ // 跨目标共享配置
105
+ // Make configuration shared across targets
106
+ // ...
107
+
108
+ module.exports = config;
109
+
110
+ // webpack.dev.js
111
+ const config = require('./webpack.core');
112
+
113
+ // Dev-specific configuration
114
+ // 开发具体配置
115
+ // ...
116
+ module.exports = config.toConfig();
117
+
118
+ // webpack.prod.js
119
+ const config = require('./webpack.core');
120
+
121
+ // Production-specific configuration
122
+ // 生产具体配置
123
+ // ...
124
+ module.exports = config.toConfig();
125
+ ```
126
+
127
+ ## ChainedMap
128
+
129
+ @empjs/chain 中的核心API接口之一是 `ChainedMap`. 一个 `ChainedMap`的操作类似于JavaScript Map, 为链式和生成配置提供了一些便利。 如果一个属性被标记一个 `ChainedMap`, 则它将具有如下的API和方法:
130
+
131
+ **除非另有说明,否则这些方法将返回 `ChainedMap` , 允许链式调用这些方法。**
132
+
133
+ ```js
134
+ // 从 Map 移除所有 配置.
135
+ clear()
136
+ ```
137
+
138
+ ```js
139
+ // 通过键值从 Map 移除单个配置.
140
+ // key: *
141
+ delete(key)
142
+ ```
143
+
144
+ ```js
145
+ // 获取 Map 中相应键的值
146
+ // key: *
147
+ // returns: value
148
+ get(key)
149
+ ```
150
+
151
+ ```js
152
+ // 获取 Map 中相应键的值
153
+ // 如果键在Map中不存在,则ChainedMap中该键的值会被配置为fn的返回值.
154
+ // key: *
155
+ // fn: Function () -> value
156
+ // returns: value
157
+ getOrCompute(key, fn)
158
+ ```
159
+
160
+ ```js
161
+ // 配置Map中 已存在的键的值
162
+ // key: *
163
+ // value: *
164
+ set(key, value)
165
+ ```
166
+
167
+ ```js
168
+ // Map中是否存在一个配置值的特定键,返回 真或假
169
+ // key: *
170
+ // returns: Boolean
171
+ has(key)
172
+ ```
173
+
174
+ ```js
175
+ // 返回 Map中已存储的所有值的数组
176
+ // returns: Array
177
+ values()
178
+ ```
179
+
180
+ ```js
181
+ // 返回Map中全部配置的一个对象, 其中 键是这个对象属性,值是相应键的值,
182
+ // 如果Map是空,返回 `undefined`
183
+ // 使用 `.before() 或 .after()` 的ChainedMap, 则将按照属性名进行排序。
184
+ // returns: Object, undefined if empty
185
+ entries()
186
+ ````
187
+
188
+ ```js
189
+ // 提供一个对象,这个对象的属性和值将 映射进 Map。
190
+ // 你也可以提供一个数组作为第二个参数以便忽略合并的属性名称。
191
+ // obj: Object
192
+ // omit: Optional Array
193
+ merge(obj, omit)
194
+ ```
195
+
196
+ ```js
197
+ // 对当前配置上下文执行函数。
198
+ // handler: Function -> ChainedMap
199
+ // 一个把ChainedMap实例作为单个参数的函数
200
+ batch(handler)
201
+ ```
202
+
203
+ ```js
204
+ // 条件执行一个函数去继续配置
205
+ // condition: Boolean
206
+ // whenTruthy: Function -> ChainedMap
207
+ // 当条件为真,调用把ChainedMap实例作为单一参数传入的函数
208
+ // whenFalsy: Optional Function -> ChainedMap
209
+ // 当条件为假,调用把ChainedMap实例作为单一参数传入的函数
210
+ when(condition, whenTruthy, whenFalsy)
211
+ ```
212
+
213
+ ## ChainedSet
214
+
215
+ @empjs/chain 中的核心API接口另一个是 `ChainedSet`. 一个 `ChainedSet`的操作类似于JavaScript Map, 为链式和生成配置提供了一些便利。 如果一个属性被标记一个 `ChainedSet`, 则它将具有如下的API和方法:
216
+
217
+ **除非另有说明,否则这些方法将返回 `ChainedSet` , 允许链式调用这些方法。**
218
+
219
+ ```js
220
+ // 添加/追加 给Set末尾位置一个值.
221
+ // value: *
222
+ add(value)
223
+ ```
224
+
225
+ ```js
226
+ // 添加 给Set开始位置一个值.
227
+ // value: *
228
+ prepend(value)
229
+ ```
230
+
231
+ ```js
232
+ // 移除Set中全部值.
233
+ clear()
234
+ ```
235
+
236
+ ```js
237
+ // 移除Set中一个指定的值.
238
+ // value: *
239
+ delete(value)
240
+ ```
241
+
242
+ ```js
243
+ // 检测Set中是否存在一个值.
244
+ // value: *
245
+ // returns: Boolean
246
+ has(value)
247
+ ```
248
+
249
+ ```js
250
+ // 返回Set中值的数组.
251
+ // returns: Array
252
+ values()
253
+ ```
254
+
255
+ ```js
256
+ // 连接给定的数组到 Set 尾部。
257
+ // arr: Array
258
+ merge(arr)
259
+ ```
260
+
261
+ ```js
262
+
263
+ // 对当前配置上下文执行函数。
264
+ // handler: Function -> ChainedSet
265
+ // 一个把 ChainedSet 实例作为单个参数的函数
266
+ batch(handler)
267
+ ```
268
+
269
+ ```js
270
+ // 条件执行一个函数去继续配置
271
+ // condition: Boolean
272
+ // whenTruthy: Function -> ChainedSet
273
+ // 当条件为真,调用把 ChainedSet 实例作为单一参数传入的函数
274
+ // whenFalsy: Optional Function -> ChainedSet
275
+ // 当条件为假,调用把 ChainedSet 实例作为单一参数传入的函数
276
+ when(condition, whenTruthy, whenFalsy)
277
+ ```
278
+
279
+ ## 速记方法
280
+
281
+ 存在许多简写方法,用于 使用与简写方法名称相同的键在 ChainedMap 设置一个值
282
+ 例如, `devServer.hot` 是一个速记方法, 因此它可以用作:
283
+
284
+ ```js
285
+ // 在 ChainedMap 上设置一个值的 速记方法
286
+ devServer.hot(true);
287
+
288
+ // 上述方法等效于:
289
+ devServer.set('hot', true);
290
+ ```
291
+
292
+ 一个速记方法是可链式的,因此调用它将返回 原实例,允许你继续链式使用
293
+
294
+ ### 配置
295
+
296
+ 创建一个新的配置对象
297
+
298
+ ```js
299
+ const Config = require('@empjs/chain');
300
+
301
+ const config = new Config();
302
+ ```
303
+
304
+ 移动到API的更深层将改变你正在修改的内容的上下文。 你可以通过 `config`在此引用顶级配置或者通过调用 `.end()` 方法向上移动一级 使你移回更高的 上下文环境。
305
+ 如果你熟悉jQuery, 这里与其 `.end()` 工作原理类似。除非另有说明,否则全部的API调用都将在当前上下文中返回API实例。 这样,你可以根据需要连续 链式API调用.
306
+ 有关对所有速记和低级房费有效的特定值的详细信息,请参阅 [webpack文档层次结构](https://webpack.js.org/configuration/) 中的相应名词。
307
+
308
+ ```js
309
+ Config : ChainedMap
310
+ ```
311
+
312
+ #### 配置速记方法
313
+
314
+ ```js
315
+ config
316
+ .amd(amd)
317
+ .bail(bail)
318
+ .cache(cache)
319
+ .devtool(devtool)
320
+ .context(context)
321
+ .externals(externals)
322
+ .loader(loader)
323
+ .name(name)
324
+ .mode(mode)
325
+ .parallelism(parallelism)
326
+ .profile(profile)
327
+ .recordsPath(recordsPath)
328
+ .recordsInputPath(recordsInputPath)
329
+ .recordsOutputPath(recordsOutputPath)
330
+ .stats(stats)
331
+ .target(target)
332
+ .watch(watch)
333
+ .watchOptions(watchOptions)
334
+ ```
335
+
336
+ #### 配置 entryPoints
337
+
338
+ ```js
339
+ // 回到 config.entryPoints : ChainedMap
340
+ config.entry(name) : ChainedSet
341
+
342
+ config
343
+ .entry(name)
344
+ .add(value)
345
+ .add(value)
346
+
347
+ config
348
+ .entry(name)
349
+ .clear()
350
+
351
+ // 用低级别 config.entryPoints:
352
+
353
+ config.entryPoints
354
+ .get(name)
355
+ .add(value)
356
+ .add(value)
357
+
358
+ config.entryPoints
359
+ .get(name)
360
+ .clear()
361
+ ```
362
+
363
+ #### 配置 output: 速记 方法
364
+
365
+ ```js
366
+ config.output : ChainedMap
367
+
368
+ config.output
369
+ .auxiliaryComment(auxiliaryComment)
370
+ .chunkFilename(chunkFilename)
371
+ .chunkLoadTimeout(chunkLoadTimeout)
372
+ .crossOriginLoading(crossOriginLoading)
373
+ .devtoolFallbackModuleFilenameTemplate(devtoolFallbackModuleFilenameTemplate)
374
+ .devtoolLineToLine(devtoolLineToLine)
375
+ .devtoolModuleFilenameTemplate(devtoolModuleFilenameTemplate)
376
+ .filename(filename)
377
+ .hashFunction(hashFunction)
378
+ .hashDigest(hashDigest)
379
+ .hashDigestLength(hashDigestLength)
380
+ .hashSalt(hashSalt)
381
+ .hotUpdateChunkFilename(hotUpdateChunkFilename)
382
+ .hotUpdateFunction(hotUpdateFunction)
383
+ .hotUpdateMainFilename(hotUpdateMainFilename)
384
+ .jsonpFunction(jsonpFunction)
385
+ .library(library)
386
+ .libraryExport(libraryExport)
387
+ .libraryTarget(libraryTarget)
388
+ .path(path)
389
+ .pathinfo(pathinfo)
390
+ .publicPath(publicPath)
391
+ .sourceMapFilename(sourceMapFilename)
392
+ .sourcePrefix(sourcePrefix)
393
+ .strictModuleExceptionHandling(strictModuleExceptionHandling)
394
+ .umdNamedDefine(umdNamedDefine)
395
+ ```
396
+
397
+ #### 配置 resolve(解析): 速记方法
398
+
399
+ ```js
400
+ config.resolve : ChainedMap
401
+
402
+ config.resolve
403
+ .cachePredicate(cachePredicate)
404
+ .cacheWithContext(cacheWithContext)
405
+ .enforceExtension(enforceExtension)
406
+ .enforceModuleExtension(enforceModuleExtension)
407
+ .unsafeCache(unsafeCache)
408
+ .symlinks(symlinks)
409
+ ```
410
+
411
+ #### 配置 resolve 别名
412
+
413
+ ```js
414
+ config.resolve.alias : ChainedMap
415
+
416
+ config.resolve.alias
417
+ .set(key, value)
418
+ .set(key, value)
419
+ .delete(key)
420
+ .clear()
421
+ ```
422
+
423
+ #### 配置 resolve modules
424
+
425
+ ```js
426
+ config.resolve.modules : ChainedSet
427
+
428
+ config.resolve.modules
429
+ .add(value)
430
+ .prepend(value)
431
+ .clear()
432
+ ```
433
+
434
+ #### 配置 resolve aliasFields
435
+
436
+ ```js
437
+ config.resolve.aliasFields : ChainedSet
438
+
439
+ config.resolve.aliasFields
440
+ .add(value)
441
+ .prepend(value)
442
+ .clear()
443
+ ```
444
+
445
+ #### 配置 resolve descriptionFields
446
+
447
+ ```js
448
+ config.resolve.descriptionFields : ChainedSet
449
+
450
+ config.resolve.descriptionFields
451
+ .add(value)
452
+ .prepend(value)
453
+ .clear()
454
+ ```
455
+
456
+ #### 配置 resolve extensions
457
+
458
+ ```js
459
+ config.resolve.extensions : ChainedSet
460
+
461
+ config.resolve.extensions
462
+ .add(value)
463
+ .prepend(value)
464
+ .clear()
465
+ ```
466
+
467
+ #### 配置 resolve mainFields
468
+
469
+ ```js
470
+ config.resolve.mainFields : ChainedSet
471
+
472
+ config.resolve.mainFields
473
+ .add(value)
474
+ .prepend(value)
475
+ .clear()
476
+ ```
477
+
478
+ #### 配置 resolve mainFiles
479
+
480
+ ```js
481
+ config.resolve.mainFiles : ChainedSet
482
+
483
+ config.resolve.mainFiles
484
+ .add(value)
485
+ .prepend(value)
486
+ .clear()
487
+ ```
488
+
489
+ #### 配置 resolveLoader
490
+
491
+ 当前API `config.resolveLoader` 相同于 配置 `config.resolve` 用下面的配置:
492
+
493
+ ##### 配置 resolveLoader moduleExtensions
494
+
495
+ ```js
496
+ config.resolveLoader.moduleExtensions : ChainedSet
497
+
498
+ config.resolveLoader.moduleExtensions
499
+ .add(value)
500
+ .prepend(value)
501
+ .clear()
502
+ ```
503
+
504
+ ##### 配置 resolveLoader packageMains
505
+
506
+ ```js
507
+ config.resolveLoader.packageMains : ChainedSet
508
+
509
+ config.resolveLoader.packageMains
510
+ .add(value)
511
+ .prepend(value)
512
+ .clear()
513
+ ```
514
+
515
+ #### 配置 performance(性能): 速记方法
516
+
517
+ ```js
518
+ config.performance : ChainedMap
519
+
520
+ config.performance
521
+ .hints(hints)
522
+ .maxEntrypointSize(maxEntrypointSize)
523
+ .maxAssetSize(maxAssetSize)
524
+ .assetFilter(assetFilter)
525
+ ```
526
+
527
+ #### 配置 optimizations(优化): 速记方法
528
+
529
+ ```js
530
+ config.optimization : ChainedMap
531
+
532
+ config.optimization
533
+ .concatenateModules(concatenateModules)
534
+ .flagIncludedChunks(flagIncludedChunks)
535
+ .mergeDuplicateChunks(mergeDuplicateChunks)
536
+ .minimize(minimize)
537
+ .namedChunks(namedChunks)
538
+ .namedModules(namedModules)
539
+ .nodeEnv(nodeEnv)
540
+ .noEmitOnErrors(noEmitOnErrors)
541
+ .occurrenceOrder(occurrenceOrder)
542
+ .portableRecords(portableRecords)
543
+ .providedExports(providedExports)
544
+ .removeAvailableModules(removeAvailableModules)
545
+ .removeEmptyChunks(removeEmptyChunks)
546
+ .runtimeChunk(runtimeChunk)
547
+ .sideEffects(sideEffects)
548
+ .splitChunks(splitChunks)
549
+ .usedExports(usedExports)
550
+ ```
551
+
552
+ #### 配置 optimization minimizers(最小优化器)
553
+
554
+ ```js
555
+ // 回到 config.optimization.minimizers
556
+ config.optimization
557
+ .minimizer(name) : ChainedMap
558
+ ```
559
+
560
+ #### 配置 optimization minimizers: 添加
561
+
562
+ _注意: 不要用 `new` 去创建最小优化器插件,因为已经为你做好了。_
563
+
564
+ ```js
565
+ config.optimization
566
+ .minimizer(name)
567
+ .use(WebpackPlugin, args)
568
+
569
+ // 例如
570
+
571
+ config.optimization
572
+ .minimizer('css')
573
+ .use(OptimizeCSSAssetsPlugin, [{ cssProcessorOptions: { safe: true } }])
574
+
575
+ // Minimizer 插件也可以由它们的路径指定,从而允许在不使用插件或webpack配置的情况下跳过昂贵的 require s。
576
+ config.optimization
577
+ .minimizer('css')
578
+ .use(require.resolve('optimize-css-assets-webpack-plugin'), [{ cssProcessorOptions: { safe: true } }])
579
+
580
+ ```
581
+
582
+ #### 配置 optimization minimizers: 修改参数
583
+
584
+ ```js
585
+ config.optimization
586
+ .minimizer(name)
587
+ .tap(args => newArgs)
588
+
589
+ // 例如
590
+ config.optimization
591
+ .minimizer('css')
592
+ .tap(args => [...args, { cssProcessorOptions: { safe: false } }])
593
+ ```
594
+
595
+ #### 配置 optimization minimizers: 修改实例
596
+
597
+ ```js
598
+ config.optimization
599
+ .minimizer(name)
600
+ .init((Plugin, args) => new Plugin(...args));
601
+ ```
602
+
603
+ #### 配置 optimization minimizers: 移除
604
+
605
+ ```js
606
+ config.optimization.minimizers.delete(name)
607
+ ```
608
+
609
+ #### 配置插件
610
+
611
+ ```js
612
+ // 回到 config.plugins
613
+ config.plugin(name) : ChainedMap
614
+ ```
615
+
616
+ #### 配置插件: 添加
617
+
618
+ _注意: 不要用 `new` 去创建插件,因为已经为你做好了。_
619
+
620
+ ```js
621
+ config
622
+ .plugin(name)
623
+ .use(WebpackPlugin, args)
624
+
625
+ // 例如
626
+ config
627
+ .plugin('hot')
628
+ .use(webpack.HotModuleReplacementPlugin);
629
+
630
+ // 插件也可以由它们的路径指定,从而允许在不使用插件或webpack配置的情况下跳过昂贵的 require s。
631
+ config
632
+ .plugin('env')
633
+ .use(require.resolve('webpack/lib/EnvironmentPlugin'), [{ 'VAR': false }]);
634
+ ```
635
+
636
+ #### 配置插件: 修改参数
637
+
638
+ ```js
639
+ config
640
+ .plugin(name)
641
+ .tap(args => newArgs)
642
+
643
+ // 例如
644
+ config
645
+ .plugin('env')
646
+ .tap(args => [...args, 'SECRET_KEY']);
647
+ ```
648
+
649
+ #### 配置插件: 修改实例
650
+
651
+ ```js
652
+ config
653
+ .plugin(name)
654
+ .init((Plugin, args) => new Plugin(...args));
655
+ ```
656
+
657
+ #### 配置插件: 移除
658
+
659
+ ```js
660
+ config.plugins.delete(name)
661
+ ```
662
+
663
+ #### 配置插件: 在之前调用
664
+
665
+ 指定当前插件上下文应该在另一个指定插件之前执行,你不能在同一个插件上同时使用 `.before()` 和 `.after()`。
666
+
667
+ ```js
668
+ config
669
+ .plugin(name)
670
+ .before(otherName)
671
+
672
+ // 例如
673
+ config
674
+ .plugin('html-template')
675
+ .use(HtmlWebpackTemplate)
676
+ .end()
677
+ .plugin('script-ext')
678
+ .use(ScriptExtWebpackPlugin)
679
+ .before('html-template');
680
+ ```
681
+
682
+ #### Config plugins: 在之后调用
683
+
684
+ 指定当前插件上下文应该在另一个指定插件之后执行,你不能在同一个插件上同时使用 `.before()` 和 `.after()`。
685
+
686
+ ```js
687
+ config
688
+ .plugin(name)
689
+ .after(otherName)
690
+
691
+ // 例如
692
+ config
693
+ .plugin('html-template')
694
+ .after('script-ext')
695
+ .use(HtmlWebpackTemplate)
696
+ .end()
697
+ .plugin('script-ext')
698
+ .use(ScriptExtWebpackPlugin);
699
+ ```
700
+
701
+ #### 配置 resolve 插件
702
+
703
+ ```js
704
+ // 回到 config.resolve.plugins
705
+ config.resolve.plugin(name) : ChainedMap
706
+ ```
707
+
708
+ #### 配置 resolve 插件: 添加
709
+
710
+ _注意: 不要用 `new` 去创建插件,因为已经为你做好了。_
711
+
712
+ ```js
713
+ config.resolve
714
+ .plugin(name)
715
+ .use(WebpackPlugin, args)
716
+ ```
717
+
718
+ #### 配置 resolve 插件: 修改参数
719
+
720
+ ```js
721
+ config.resolve
722
+ .plugin(name)
723
+ .tap(args => newArgs)
724
+ ```
725
+
726
+ #### 配置 resolve 插件: 修改实例
727
+
728
+ ```js
729
+ config.resolve
730
+ .plugin(name)
731
+ .init((Plugin, args) => new Plugin(...args))
732
+ ```
733
+
734
+ #### 配置 resolve 插件: 移除
735
+
736
+ ```js
737
+ config.resolve.plugins.delete(name)
738
+ ```
739
+
740
+ #### 配置 resolve 插件: 在之前调用
741
+
742
+ 指定当前插件上下文应该在另一个指定插件之前执行,你不能在同一个插件上同时使用 `.before()` 和 `.after()`。
743
+
744
+ ```js
745
+ config.resolve
746
+ .plugin(name)
747
+ .before(otherName)
748
+
749
+ // 例如
750
+
751
+ config.resolve
752
+ .plugin('beta')
753
+ .use(BetaWebpackPlugin)
754
+ .end()
755
+ .plugin('alpha')
756
+ .use(AlphaWebpackPlugin)
757
+ .before('beta');
758
+ ```
759
+
760
+ #### 配置 resolve 插件: 在之后调用
761
+
762
+ 指定当前插件上下文应该在另一个指定插件之后执行,你不能在同一个插件上同时使用 `.before()` 和 `.after()`。
763
+
764
+ ```js
765
+ config.resolve
766
+ .plugin(name)
767
+ .after(otherName)
768
+
769
+ // 例如
770
+ config.resolve
771
+ .plugin('beta')
772
+ .after('alpha')
773
+ .use(BetaWebpackTemplate)
774
+ .end()
775
+ .plugin('alpha')
776
+ .use(AlphaWebpackPlugin);
777
+ ```
778
+
779
+ #### 配置 node
780
+
781
+ ```js
782
+ config.node : ChainedMap
783
+
784
+ config.node
785
+ .set('__dirname', 'mock')
786
+ .set('__filename', 'mock');
787
+ ```
788
+
789
+ #### 配置 devServer
790
+
791
+ ```js
792
+ config.devServer : ChainedMap
793
+ ```
794
+
795
+ #### 配置 devServer allowedHosts
796
+
797
+ ```js
798
+ config.devServer.allowedHosts : ChainedSet
799
+
800
+ config.devServer.allowedHosts
801
+ .add(value)
802
+ .prepend(value)
803
+ .clear()
804
+ ```
805
+
806
+ #### 配置 devServer: 速记方法
807
+
808
+ ```js
809
+ config.devServer
810
+ .bonjour(bonjour)
811
+ .clientLogLevel(clientLogLevel)
812
+ .color(color)
813
+ .compress(compress)
814
+ .contentBase(contentBase)
815
+ .disableHostCheck(disableHostCheck)
816
+ .filename(filename)
817
+ .headers(headers)
818
+ .historyApiFallback(historyApiFallback)
819
+ .host(host)
820
+ .hot(hot)
821
+ .hotOnly(hotOnly)
822
+ .https(https)
823
+ .inline(inline)
824
+ .info(info)
825
+ .lazy(lazy)
826
+ .noInfo(noInfo)
827
+ .open(open)
828
+ .openPage(openPage)
829
+ .overlay(overlay)
830
+ .pfx(pfx)
831
+ .pfxPassphrase(pfxPassphrase)
832
+ .port(port)
833
+ .progress(progress)
834
+ .proxy(proxy)
835
+ .public(public)
836
+ .publicPath(publicPath)
837
+ .quiet(quiet)
838
+ .setup(setup)
839
+ .socket(socket)
840
+ .staticOptions(staticOptions)
841
+ .stats(stats)
842
+ .stdin(stdin)
843
+ .useLocalIp(useLocalIp)
844
+ .watchContentBase(watchContentBase)
845
+ .watchOptions(watchOptions)
846
+ ```
847
+
848
+ #### 配置 module
849
+
850
+ ```js
851
+ config.module : ChainedMap
852
+ ```
853
+
854
+ #### 配置 module: 速记方法
855
+
856
+ ```js
857
+ config.module : ChainedMap
858
+
859
+ config.module
860
+ .noParse(noParse)
861
+ ```
862
+
863
+ #### 配置 module rules: 速记方法
864
+
865
+ ```js
866
+ config.module.rules : ChainedMap
867
+
868
+ config.module
869
+ .rule(name)
870
+ .test(test)
871
+ .pre()
872
+ .post()
873
+ .enforce(preOrPost)
874
+ ```
875
+
876
+ #### 配置 module rules uses (loaders): 创建
877
+
878
+ ```js
879
+ config.module.rules{}.uses : ChainedMap
880
+
881
+ config.module
882
+ .rule(name)
883
+ .use(name)
884
+ .loader(loader)
885
+ .options(options)
886
+
887
+ // Example
888
+
889
+ config.module
890
+ .rule('compile')
891
+ .use('babel')
892
+ .loader('babel-loader')
893
+ .options({ presets: ['@babel/preset-env'] });
894
+ ```
895
+
896
+ #### 配置 module rules uses (loaders): 修改选项
897
+
898
+ ```js
899
+ config.module
900
+ .rule(name)
901
+ .use(name)
902
+ .tap(options => newOptions)
903
+
904
+ // 例如
905
+
906
+ config.module
907
+ .rule('compile')
908
+ .use('babel')
909
+ .tap(options => merge(options, {
910
+ plugins: ['@babel/plugin-proposal-class-properties']
911
+ }));
912
+ ```
913
+
914
+ #### 配置 module rules oneOfs (条件 rules)
915
+
916
+ ```js
917
+ config.module.rules{}.oneOfs : ChainedMap<Rule>
918
+
919
+ config.module
920
+ .rule(name)
921
+ .oneOf(name)
922
+
923
+ // 例如
924
+
925
+ config.module
926
+ .rule('css')
927
+ .oneOf('inline')
928
+ .resourceQuery(/inline/)
929
+ .use('url')
930
+ .loader('url-loader')
931
+ .end()
932
+ .end()
933
+ .oneOf('external')
934
+ .resourceQuery(/external/)
935
+ .use('file')
936
+ .loader('file-loader')
937
+ ```
938
+
939
+ #### Config module rules oneOfs (conditional rules): ordering before
940
+ Specify that the current `oneOf` context should operate before another named
941
+ `oneOf`. You cannot use both `.before()` and `.after()` on the same `oneOf`.
942
+
943
+ ```js
944
+ config.module
945
+ .rule(name)
946
+ .oneOf(name)
947
+ .before()
948
+
949
+ // Example
950
+
951
+ config.module
952
+ .rule('scss')
953
+ .test(/\.scss$/)
954
+ .oneOf('normal')
955
+ .use('sass')
956
+ .loader('sass-loader')
957
+ .end()
958
+ .end()
959
+ .oneOf('sass-vars')
960
+ .before('normal')
961
+ .resourceQuery(/\?sassvars/)
962
+ .use('sass-vars')
963
+ .loader('sass-vars-to-js-loader')
964
+ ```
965
+
966
+ #### Config module rules oneOfs (conditional rules): ordering after
967
+ Specify that the current `oneOf` context should operate after another named
968
+ `oneOf`. You cannot use both `.before()` and `.after()` on the same `oneOf`.
969
+
970
+ ```js
971
+ config.module
972
+ .rule(name)
973
+ .oneOf(name)
974
+ .after()
975
+
976
+ // Example
977
+
978
+ config.module
979
+ .rule('scss')
980
+ .test(/\.scss$/)
981
+ .oneOf('vue')
982
+ .resourceQuery(/\?vue/)
983
+ .use('vue-style')
984
+ .loader('vue-style-loader')
985
+ .end()
986
+ .end()
987
+ .oneOf('normal')
988
+ .use('sass')
989
+ .loader('sass-loader')
990
+ .end()
991
+ .end()
992
+ .oneOf('sass-vars')
993
+ .after('vue')
994
+ .resourceQuery(/\?sassvars/)
995
+ .use('sass-vars')
996
+ .loader('sass-vars-to-js-loader')
997
+ ```
998
+
999
+ ---
1000
+
1001
+ ### 合并配置
1002
+
1003
+ @empjs/chain 支持将对象合并到配置实例,改实例类似于 @empjs/chain 模式 布局的布局。 请注意,这不是 webpack 配置对象,但您可以再将webpack配置对象提供给@empjs/chain 以匹配器布局之前对其进行转换。
1004
+
1005
+ ```js
1006
+ config.merge({ devtool: 'source-map' });
1007
+
1008
+ config.get('devtool') // "source-map"
1009
+ ```
1010
+
1011
+ ```js
1012
+ config.merge({
1013
+ [key]: value,
1014
+
1015
+ amd,
1016
+ bail,
1017
+ cache,
1018
+ context,
1019
+ devtool,
1020
+ externals,
1021
+ loader,
1022
+ mode,
1023
+ parallelism,
1024
+ profile,
1025
+ recordsPath,
1026
+ recordsInputPath,
1027
+ recordsOutputPath,
1028
+ stats,
1029
+ target,
1030
+ watch,
1031
+ watchOptions,
1032
+
1033
+ entry: {
1034
+ [name]: [...values]
1035
+ },
1036
+
1037
+ plugin: {
1038
+ [name]: {
1039
+ plugin: WebpackPlugin,
1040
+ args: [...args],
1041
+ before,
1042
+ after
1043
+ }
1044
+ },
1045
+
1046
+ devServer: {
1047
+ [key]: value,
1048
+
1049
+ clientLogLevel,
1050
+ compress,
1051
+ contentBase,
1052
+ filename,
1053
+ headers,
1054
+ historyApiFallback,
1055
+ host,
1056
+ hot,
1057
+ hotOnly,
1058
+ https,
1059
+ inline,
1060
+ lazy,
1061
+ noInfo,
1062
+ overlay,
1063
+ port,
1064
+ proxy,
1065
+ quiet,
1066
+ setup,
1067
+ stats,
1068
+ watchContentBase
1069
+ },
1070
+
1071
+ node: {
1072
+ [key]: value
1073
+ },
1074
+
1075
+ optimization: {
1076
+ concatenateModules,
1077
+ flagIncludedChunks,
1078
+ mergeDuplicateChunks,
1079
+ minimize,
1080
+ minimizer,
1081
+ namedChunks,
1082
+ namedModules,
1083
+ nodeEnv,
1084
+ noEmitOnErrors,
1085
+ occurrenceOrder,
1086
+ portableRecords,
1087
+ providedExports,
1088
+ removeAvailableModules,
1089
+ removeEmptyChunks,
1090
+ runtimeChunk,
1091
+ sideEffects,
1092
+ splitChunks,
1093
+ usedExports,
1094
+ },
1095
+
1096
+ performance: {
1097
+ [key]: value,
1098
+
1099
+ hints,
1100
+ maxEntrypointSize,
1101
+ maxAssetSize,
1102
+ assetFilter
1103
+ },
1104
+
1105
+ resolve: {
1106
+ [key]: value,
1107
+
1108
+ alias: {
1109
+ [key]: value
1110
+ },
1111
+ aliasFields: [...values],
1112
+ descriptionFields: [...values],
1113
+ extensions: [...values],
1114
+ mainFields: [...values],
1115
+ mainFiles: [...values],
1116
+ modules: [...values],
1117
+
1118
+ plugin: {
1119
+ [name]: {
1120
+ plugin: WebpackPlugin,
1121
+ args: [...args],
1122
+ before,
1123
+ after
1124
+ }
1125
+ }
1126
+ },
1127
+
1128
+ resolveLoader: {
1129
+ [key]: value,
1130
+
1131
+ alias: {
1132
+ [key]: value
1133
+ },
1134
+ aliasFields: [...values],
1135
+ descriptionFields: [...values],
1136
+ extensions: [...values],
1137
+ mainFields: [...values],
1138
+ mainFiles: [...values],
1139
+ modules: [...values],
1140
+ moduleExtensions: [...values],
1141
+ packageMains: [...values],
1142
+
1143
+ plugin: {
1144
+ [name]: {
1145
+ plugin: WebpackPlugin,
1146
+ args: [...args],
1147
+ before,
1148
+ after
1149
+ }
1150
+ }
1151
+ },
1152
+
1153
+ module: {
1154
+ [key]: value,
1155
+
1156
+ rule: {
1157
+ [name]: {
1158
+ [key]: value,
1159
+
1160
+ enforce,
1161
+ issuer,
1162
+ parser,
1163
+ resource,
1164
+ resourceQuery,
1165
+ test,
1166
+
1167
+ include: [...paths],
1168
+ exclude: [...paths],
1169
+
1170
+ oneOf: {
1171
+ [name]: Rule
1172
+ },
1173
+
1174
+ use: {
1175
+ [name]: {
1176
+ loader: LoaderString,
1177
+ options: LoaderOptions,
1178
+ before,
1179
+ after
1180
+ }
1181
+ }
1182
+ }
1183
+ }
1184
+ }
1185
+ })
1186
+ ```
1187
+
1188
+ ### 条件配置
1189
+
1190
+ 当使用的情况下工作ChainedMap和ChainedSet,则可以使用执行条件的配置when。您必须指定一个表达式 when(),以评估其真实性或虚假性。如果表达式是真实的,则将使用当前链接实例的实例调用第一个函数参数。您可以选择提供在条件为假时调用的第二个函数,该函数也是当前链接的实例。
1191
+
1192
+ ```js
1193
+ // 示例:仅在生产期间添加minify插件
1194
+ config
1195
+ .when(process.env.NODE_ENV === 'production', config => {
1196
+ config
1197
+ .plugin('minify')
1198
+ .use(BabiliWebpackPlugin);
1199
+ });
1200
+ ```
1201
+
1202
+ ```js
1203
+ // 例:只有在生产过程中添加缩小插件,否则设置devtool到源映射
1204
+ config
1205
+ .when(process.env.NODE_ENV === 'production',
1206
+ config => config.plugin('minify').use(BabiliWebpackPlugin),
1207
+ config => config.devtool('source-map')
1208
+ );
1209
+ ```
1210
+
1211
+ ### 检查生成的配置
1212
+
1213
+ 您可以使用检查生成的webpack配置config.toString()。这将生成配置的字符串化版本,其中包含命名规则,用法和插件的注释提示:
1214
+
1215
+ ``` js
1216
+ config
1217
+ .module
1218
+ .rule('compile')
1219
+ .test(/\.js$/)
1220
+ .use('babel')
1221
+ .loader('babel-loader');
1222
+
1223
+ config.toString();
1224
+
1225
+
1226
+ {
1227
+ module: {
1228
+ rules: [
1229
+ /* config.module.rule('compile') */
1230
+ {
1231
+ test: /\.js$/,
1232
+ use: [
1233
+ /* config.module.rule('compile').use('babel') */
1234
+ {
1235
+ loader: 'babel-loader'
1236
+ }
1237
+ ]
1238
+ }
1239
+ ]
1240
+ }
1241
+ }
1242
+
1243
+ ```
1244
+
1245
+ 默认情况下,如果生成的字符串包含需要的函数和插件,则不能直接用作真正的webpack配置。为了生成可用的配置,您可以通过__expression在其上设置特殊属性来自定义函数和插件的字符串化方式:
1246
+
1247
+ ``` js
1248
+ const sass = require('sass');
1249
+ sass.__expression = `require('sass');
1250
+
1251
+ class MyPlugin {}
1252
+ MyPlugin.__expression = `require('my-plugin')`;
1253
+
1254
+ function myFunction () {}
1255
+ myFunction.__expression = `require('my-function')`;
1256
+
1257
+ config
1258
+ .plugin('example')
1259
+ .use(MyPlugin, [{ fn: myFunction, implementation: sass, }]);
1260
+
1261
+ config.toString();
1262
+
1263
+ /*
1264
+ {
1265
+ plugins: [
1266
+ new (require('my-plugin'))({
1267
+ fn: require('my-function'),
1268
+ implementation: require('sass')
1269
+ })
1270
+ ]
1271
+ }
1272
+ */
1273
+ ```
1274
+
1275
+ 通过其路径指定的插件将require()自动生成其语句:
1276
+
1277
+ ``` js
1278
+ config
1279
+ .plugin('env')
1280
+ .use(require.resolve('webpack/lib/ProvidePlugin'), [{ jQuery: 'jquery' }])
1281
+
1282
+ config.toString();
1283
+
1284
+
1285
+ {
1286
+ plugins: [
1287
+ new (require('/foo/bar/src/node_modules/webpack/lib/EnvironmentPlugin.js'))(
1288
+ {
1289
+ jQuery: 'jquery'
1290
+ }
1291
+ )
1292
+ ]
1293
+ }
1294
+ ```
1295
+
1296
+ 您还可以调用toString静态方法Config,以便在字符串化之前修改配置对象。
1297
+
1298
+ ```js
1299
+ Config.toString({
1300
+ ...config.toConfig(),
1301
+ module: {
1302
+ defaultRules: [
1303
+ {
1304
+ use: [
1305
+ {
1306
+ loader: 'banner-loader',
1307
+ options: { prefix: 'banner-prefix.txt' },
1308
+ },
1309
+ ],
1310
+ },
1311
+ ],
1312
+ },
1313
+ })
1314
+ ```
1315
+
1316
+ ```
1317
+ {
1318
+ plugins: [
1319
+ /* config.plugin('foo') */
1320
+ new TestPlugin()
1321
+ ],
1322
+ module: {
1323
+ defaultRules: [
1324
+ {
1325
+ use: [
1326
+ {
1327
+ loader: 'banner-loader',
1328
+ options: {
1329
+ prefix: 'banner-prefix.txt'
1330
+ }
1331
+ }
1332
+ ]
1333
+ }
1334
+ ]
1335
+ }
1336
+ }
1337
+ ```