UNPKG

29.3 kBMarkdownView Raw
1# webpack-chain
2
3[![NPM version][npm-image]][npm-url]
4[![NPM downloads][npm-downloads]][npm-url]
5[![Build Status][travis-image]][travis-url]
6
7Use a chaining API to generate and simplify the modification of
8webpack version 2-4 configurations.
9
10This documentation corresponds to v5 of webpack-chain. For previous versions, see:
11
12* [v4 docs](https://github.com/neutrinojs/webpack-chain/tree/v4)
13* [v3 docs](https://github.com/neutrinojs/webpack-chain/tree/v3)
14* [v2 docs](https://github.com/neutrinojs/webpack-chain/tree/v2)
15* [v1 docs](https://github.com/neutrinojs/webpack-chain/tree/v1)
16
17_Note: while webpack-chain is utilized extensively in Neutrino, this package is
18completely standalone and can be used by any project._
19
20## Introduction
21
22webpack's core configuration is based on creating and modifying a
23potentially unwieldy JavaScript object. While this is OK for configurations
24on individual projects, trying to share these objects across projects and
25make subsequent modifications gets messy, as you need to have a deep
26understanding of the underlying object structure to make those changes.
27
28`webpack-chain` attempts to improve this process by providing a chainable or
29fluent API for creating and modifying webpack configurations. Key portions
30of the API can be referenced by user-specified names, which helps to
31standardize how to modify a configuration across projects.
32
33This is easier explained through the examples following.
34
35## Installation
36
37`webpack-chain` requires Node.js v6.9 and higher. `webpack-chain` also
38only creates configuration objects designed for use in webpack versions 2, 3,
39and 4.
40
41You may install this package using either Yarn or npm (choose one):
42
43**Yarn**
44
45```bash
46yarn add --dev webpack-chain
47```
48
49**npm**
50
51```bash
52npm install --save-dev webpack-chain
53```
54
55## Getting Started
56
57Once you have `webpack-chain` installed, you can start creating a
58webpack configuration. For this guide, our example base configuration will
59be `webpack.config.js` in the root of our project directory.
60
61```js
62// Require the webpack-chain module. This module exports a single
63// constructor function for creating a configuration API.
64const Config = require('webpack-chain');
65
66// Instantiate the configuration with a new API
67const config = new Config();
68
69// Make configuration changes using the chain API.
70// Every API call tracks a change to the stored configuration.
71
72config
73 // Interact with entry points
74 .entry('index')
75 .add('src/index.js')
76 .end()
77 // Modify output settings
78 .output
79 .path('dist')
80 .filename('[name].bundle.js');
81
82// Create named rules which can be modified later
83config.module
84 .rule('lint')
85 .test(/\.js$/)
86 .pre()
87 .include
88 .add('src')
89 .end()
90 // Even create named uses (loaders)
91 .use('eslint')
92 .loader('eslint-loader')
93 .options({
94 rules: {
95 semi: 'off'
96 }
97 });
98
99config.module
100 .rule('compile')
101 .test(/\.js$/)
102 .include
103 .add('src')
104 .add('test')
105 .end()
106 .use('babel')
107 .loader('babel-loader')
108 .options({
109 presets: [
110 ['@babel/preset-env', { modules: false }]
111 ]
112 });
113
114// Create named plugins too!
115config
116 .plugin('clean')
117 .use(CleanPlugin, [['dist'], { root: '/dir' }]);
118
119// Export the completed configuration object to be consumed by webpack
120module.exports = config.toConfig();
121```
122
123Having shared configurations is also simple. Just export the configuration
124and call `.toConfig()` prior to passing to webpack.
125
126```js
127// webpack.core.js
128const Config = require('webpack-chain');
129const config = new Config();
130
131// Make configuration shared across targets
132// ...
133
134module.exports = config;
135
136// webpack.dev.js
137const config = require('./webpack.core');
138
139// Dev-specific configuration
140// ...
141module.exports = config.toConfig();
142
143// webpack.prod.js
144const config = require('./webpack.core');
145
146// Production-specific configuration
147// ...
148module.exports = config.toConfig();
149```
150
151## ChainedMap
152
153One of the core API interfaces in webpack-chain is a `ChainedMap`. A
154`ChainedMap` operates similar to a JavaScript Map, with some conveniences for
155chaining and generating configuration. If a property is marked as being a
156`ChainedMap`, it will have an API and methods as described below:
157
158**Unless stated otherwise, these methods will return the `ChainedMap`, allowing
159you to chain these methods.**
160
161```js
162// Remove all entries from a Map.
163clear()
164```
165
166```js
167// Remove a single entry from a Map given its key.
168// key: *
169delete(key)
170```
171
172```js
173// Fetch the value from a Map located at the corresponding key.
174// key: *
175// returns: value
176get(key)
177```
178
179```js
180// Fetch the value from a Map located at the corresponding key.
181// If the key is missing, the key is set to the result of function fn.
182// key: *
183// fn: Function () -> value
184// returns: value
185getOrCompute(key, fn)
186```
187
188```js
189// Set a value on the Map stored at the `key` location.
190// key: *
191// value: *
192set(key, value)
193```
194
195```js
196// Returns `true` or `false` based on whether a Map as has a value set at a
197// particular key.
198// key: *
199// returns: Boolean
200has(key)
201```
202
203```js
204// Returns an array of all the values stored in the Map.
205// returns: Array
206values()
207```
208
209```js
210// Returns an object of all the entries in the backing Map
211// where the key is the object property, and the value
212// corresponding to the key. Will return `undefined` if the backing
213// Map is empty.
214// This will order properties by their name if the value is
215// a ChainedMap that used .before() or .after().
216// returns: Object, undefined if empty
217entries()
218````
219
220```js
221// Provide an object which maps its properties and values
222// into the backing Map as keys and values.
223// You can also provide an array as the second argument
224// for property names to omit from being merged.
225// obj: Object
226// omit: Optional Array
227merge(obj, omit)
228```
229
230```js
231// Execute a function against the current configuration context
232// handler: Function -> ChainedMap
233 // A function which is given a single argument of the ChainedMap instance
234batch(handler)
235```
236
237```js
238// Conditionally execute a function to continue configuration
239// condition: Boolean
240// whenTruthy: Function -> ChainedMap
241 // invoked when condition is truthy, given a single argument of the ChainedMap instance
242// whenFalsy: Optional Function -> ChainedMap
243 // invoked when condition is falsy, given a single argument of the ChainedMap instance
244when(condition, whenTruthy, whenFalsy)
245```
246
247## ChainedSet
248
249Another of the core API interfaces in webpack-chain is a `ChainedSet`. A
250`ChainedSet` operates similar to a JavaScript Set, with some conveniences for
251chaining and generating configuration. If a property is marked as being a
252`ChainedSet`, it will have an API and methods as described below:
253
254**Unless stated otherwise, these methods will return the `ChainedSet`, allowing
255you to chain these methods.**
256
257```js
258// Add/append a value to the end of a Set.
259// value: *
260add(value)
261```
262
263```js
264// Add a value to the beginning of a Set.
265// value: *
266prepend(value)
267```
268
269```js
270// Remove all values from a Set.
271clear()
272```
273
274```js
275// Remove a specific value from a Set.
276// value: *
277delete(value)
278```
279
280```js
281// Returns `true` or `false` based on whether or not the
282// backing Set contains the specified value.
283// value: *
284// returns: Boolean
285has(value)
286```
287
288```js
289// Returns an array of values contained in the backing Set.
290// returns: Array
291values()
292```
293
294```js
295// Concatenates the given array to the end of the backing Set.
296// arr: Array
297merge(arr)
298```
299
300```js
301// Execute a function against the current configuration context
302// handler: Function -> ChainedSet
303 // A function which is given a single argument of the ChainedSet instance
304batch(handler)
305```
306
307```js
308// Conditionally execute a function to continue configuration
309// condition: Boolean
310// whenTruthy: Function -> ChainedSet
311 // invoked when condition is truthy, given a single argument of the ChainedSet instance
312// whenFalsy: Optional Function -> ChainedSet
313 // invoked when condition is falsy, given a single argument of the ChainedSet instance
314when(condition, whenTruthy, whenFalsy)
315```
316
317## Shorthand methods
318
319A number of shorthand methods exist for setting a value on a `ChainedMap`
320with the same key as the shorthand method name.
321For example, `devServer.hot` is a shorthand method, so it can be used as:
322
323```js
324// A shorthand method for setting a value on a ChainedMap
325devServer.hot(true);
326
327// This would be equivalent to:
328devServer.set('hot', true);
329```
330
331A shorthand method is chainable, so calling it will return the original
332instance, allowing you to continue to chain.
333
334### Config
335
336Create a new configuration object.
337
338```js
339const Config = require('webpack-chain');
340
341const config = new Config();
342```
343
344Moving to deeper points in the API will change the context of what you
345are modifying. You can move back to the higher context by either referencing
346the top-level `config` again, or by calling `.end()` to move up one level.
347If you are familiar with jQuery, `.end()` works similarly. All API calls
348will return the API instance at the current context unless otherwise
349specified. This is so you may chain API calls continuously if desired.
350
351For details on the specific values that are valid for all shorthand and
352low-level methods, please refer to their corresponding name in the
353[webpack docs hierarchy](https://webpack.js.org/configuration/).
354
355```js
356Config : ChainedMap
357```
358
359#### Config shorthand methods
360
361```js
362config
363 .amd(amd)
364 .bail(bail)
365 .cache(cache)
366 .devtool(devtool)
367 .context(context)
368 .externals(externals)
369 .loader(loader)
370 .name(name)
371 .mode(mode)
372 .parallelism(parallelism)
373 .profile(profile)
374 .recordsPath(recordsPath)
375 .recordsInputPath(recordsInputPath)
376 .recordsOutputPath(recordsOutputPath)
377 .stats(stats)
378 .target(target)
379 .watch(watch)
380 .watchOptions(watchOptions)
381```
382
383#### Config entryPoints
384
385```js
386// Backed at config.entryPoints : ChainedMap
387config.entry(name) : ChainedSet
388
389config
390 .entry(name)
391 .add(value)
392 .add(value)
393
394config
395 .entry(name)
396 .clear()
397
398// Using low-level config.entryPoints:
399
400config.entryPoints
401 .get(name)
402 .add(value)
403 .add(value)
404
405config.entryPoints
406 .get(name)
407 .clear()
408```
409
410#### Config output: shorthand methods
411
412```js
413config.output : ChainedMap
414
415config.output
416 .auxiliaryComment(auxiliaryComment)
417 .chunkFilename(chunkFilename)
418 .chunkLoadTimeout(chunkLoadTimeout)
419 .crossOriginLoading(crossOriginLoading)
420 .devtoolFallbackModuleFilenameTemplate(devtoolFallbackModuleFilenameTemplate)
421 .devtoolLineToLine(devtoolLineToLine)
422 .devtoolModuleFilenameTemplate(devtoolModuleFilenameTemplate)
423 .filename(filename)
424 .hashFunction(hashFunction)
425 .hashDigest(hashDigest)
426 .hashDigestLength(hashDigestLength)
427 .hashSalt(hashSalt)
428 .hotUpdateChunkFilename(hotUpdateChunkFilename)
429 .hotUpdateFunction(hotUpdateFunction)
430 .hotUpdateMainFilename(hotUpdateMainFilename)
431 .jsonpFunction(jsonpFunction)
432 .library(library)
433 .libraryExport(libraryExport)
434 .libraryTarget(libraryTarget)
435 .path(path)
436 .pathinfo(pathinfo)
437 .publicPath(publicPath)
438 .sourceMapFilename(sourceMapFilename)
439 .sourcePrefix(sourcePrefix)
440 .strictModuleExceptionHandling(strictModuleExceptionHandling)
441 .umdNamedDefine(umdNamedDefine)
442```
443
444#### Config resolve: shorthand methods
445
446```js
447config.resolve : ChainedMap
448
449config.resolve
450 .cachePredicate(cachePredicate)
451 .cacheWithContext(cacheWithContext)
452 .enforceExtension(enforceExtension)
453 .enforceModuleExtension(enforceModuleExtension)
454 .unsafeCache(unsafeCache)
455 .symlinks(symlinks)
456```
457
458#### Config resolve alias
459
460```js
461config.resolve.alias : ChainedMap
462
463config.resolve.alias
464 .set(key, value)
465 .set(key, value)
466 .delete(key)
467 .clear()
468```
469
470#### Config resolve modules
471
472```js
473config.resolve.modules : ChainedSet
474
475config.resolve.modules
476 .add(value)
477 .prepend(value)
478 .clear()
479```
480
481#### Config resolve aliasFields
482
483```js
484config.resolve.aliasFields : ChainedSet
485
486config.resolve.aliasFields
487 .add(value)
488 .prepend(value)
489 .clear()
490```
491
492#### Config resolve descriptionFields
493
494```js
495config.resolve.descriptionFields : ChainedSet
496
497config.resolve.descriptionFields
498 .add(value)
499 .prepend(value)
500 .clear()
501```
502
503#### Config resolve extensions
504
505```js
506config.resolve.extensions : ChainedSet
507
508config.resolve.extensions
509 .add(value)
510 .prepend(value)
511 .clear()
512```
513
514#### Config resolve mainFields
515
516```js
517config.resolve.mainFields : ChainedSet
518
519config.resolve.mainFields
520 .add(value)
521 .prepend(value)
522 .clear()
523```
524
525#### Config resolve mainFiles
526
527```js
528config.resolve.mainFiles : ChainedSet
529
530config.resolve.mainFiles
531 .add(value)
532 .prepend(value)
533 .clear()
534```
535
536#### Config resolveLoader
537
538The API for `config.resolveLoader` is identical to `config.resolve` with
539the following additions:
540
541#### Config resolveLoader moduleExtensions
542
543```js
544config.resolveLoader.moduleExtensions : ChainedSet
545
546config.resolveLoader.moduleExtensions
547 .add(value)
548 .prepend(value)
549 .clear()
550```
551
552#### Config resolveLoader packageMains
553
554```js
555config.resolveLoader.packageMains : ChainedSet
556
557config.resolveLoader.packageMains
558 .add(value)
559 .prepend(value)
560 .clear()
561```
562
563#### Config performance: shorthand methods
564
565```js
566config.performance : ChainedMap
567
568config.performance
569 .hints(hints)
570 .maxEntrypointSize(maxEntrypointSize)
571 .maxAssetSize(maxAssetSize)
572 .assetFilter(assetFilter)
573```
574
575#### Configuring optimizations: shorthand methods
576
577```js
578config.optimization : ChainedMap
579
580config.optimization
581 .concatenateModules(concatenateModules)
582 .flagIncludedChunks(flagIncludedChunks)
583 .mergeDuplicateChunks(mergeDuplicateChunks)
584 .minimize(minimize)
585 .namedChunks(namedChunks)
586 .namedModules(namedModules)
587 .nodeEnv(nodeEnv)
588 .noEmitOnErrors(noEmitOnErrors)
589 .occurrenceOrder(occurrenceOrder)
590 .portableRecords(portableRecords)
591 .providedExports(providedExports)
592 .removeAvailableModules(removeAvailableModules)
593 .removeEmptyChunks(removeEmptyChunks)
594 .runtimeChunk(runtimeChunk)
595 .sideEffects(sideEffects)
596 .splitChunks(splitChunks)
597 .usedExports(usedExports)
598```
599
600#### Config optimization minimizers
601
602```js
603// Backed at config.optimization.minimizers
604config.optimization
605 .minimizer(name) : ChainedMap
606```
607
608#### Config optimization minimizers: adding
609
610_NOTE: Do not use `new` to create the minimizer plugin, as this will be done for you._
611
612```js
613config.optimization
614 .minimizer(name)
615 .use(WebpackPlugin, args)
616
617// Examples
618
619config.optimization
620 .minimizer('css')
621 .use(OptimizeCSSAssetsPlugin, [{ cssProcessorOptions: { safe: true } }])
622
623// Minimizer plugins can also be specified by their path, allowing the expensive require()s to be
624// skipped in cases where the plugin or webpack configuration won't end up being used.
625config.optimization
626 .minimizer('css')
627 .use(require.resolve('optimize-css-assets-webpack-plugin'), [{ cssProcessorOptions: { safe: true } }])
628
629```
630
631#### Config optimization minimizers: modify arguments
632
633```js
634config.optimization
635 .minimizer(name)
636 .tap(args => newArgs)
637
638// Example
639config
640 .minimizer('css')
641 .tap(args => [...args, { cssProcessorOptions: { safe: false } }])
642```
643
644#### Config optimization minimizers: modify instantiation
645
646```js
647config.optimization
648 .minimizer(name)
649 .init((Plugin, args) => new Plugin(...args));
650```
651
652#### Config optimization minimizers: removing
653
654```js
655config.optimization.minimizers.delete(name)
656```
657
658#### Config plugins
659
660```js
661// Backed at config.plugins
662config.plugin(name) : ChainedMap
663```
664
665#### Config plugins: adding
666
667_NOTE: Do not use `new` to create the plugin, as this will be done for you._
668
669```js
670config
671 .plugin(name)
672 .use(WebpackPlugin, args)
673
674// Examples
675
676config
677 .plugin('hot')
678 .use(webpack.HotModuleReplacementPlugin);
679
680// Plugins can also be specified by their path, allowing the expensive require()s to be
681// skipped in cases where the plugin or webpack configuration won't end up being used.
682config
683 .plugin('env')
684 .use(require.resolve('webpack/lib/EnvironmentPlugin'), [{ 'VAR': false }]);
685```
686
687#### Config plugins: modify arguments
688
689```js
690config
691 .plugin(name)
692 .tap(args => newArgs)
693
694// Example
695config
696 .plugin('env')
697 .tap(args => [...args, 'SECRET_KEY']);
698```
699
700#### Config plugins: modify instantiation
701
702```js
703config
704 .plugin(name)
705 .init((Plugin, args) => new Plugin(...args));
706```
707
708#### Config plugins: removing
709
710```js
711config.plugins.delete(name)
712```
713
714#### Config plugins: ordering before
715
716Specify that the current `plugin` context should operate before another named
717`plugin`. You cannot use both `.before()` and `.after()` on the same plugin.
718
719```js
720config
721 .plugin(name)
722 .before(otherName)
723
724// Example
725
726config
727 .plugin('html-template')
728 .use(HtmlWebpackTemplate)
729 .end()
730 .plugin('script-ext')
731 .use(ScriptExtWebpackPlugin)
732 .before('html-template');
733```
734
735#### Config plugins: ordering after
736
737Specify that the current `plugin` context should operate after another named
738`plugin`. You cannot use both `.before()` and `.after()` on the same plugin.
739
740```js
741config
742 .plugin(name)
743 .after(otherName)
744
745// Example
746
747config
748 .plugin('html-template')
749 .after('script-ext')
750 .use(HtmlWebpackTemplate)
751 .end()
752 .plugin('script-ext')
753 .use(ScriptExtWebpackPlugin);
754```
755
756#### Config resolve plugins
757
758```js
759// Backed at config.resolve.plugins
760config.resolve.plugin(name) : ChainedMap
761```
762
763#### Config resolve plugins: adding
764
765_NOTE: Do not use `new` to create the plugin, as this will be done for you._
766
767```js
768config.resolve
769 .plugin(name)
770 .use(WebpackPlugin, args)
771```
772
773#### Config resolve plugins: modify arguments
774
775```js
776config.resolve
777 .plugin(name)
778 .tap(args => newArgs)
779```
780
781#### Config resolve plugins: modify instantiation
782
783```js
784config.resolve
785 .plugin(name)
786 .init((Plugin, args) => new Plugin(...args))
787```
788
789#### Config resolve plugins: removing
790
791```js
792config.resolve.plugins.delete(name)
793```
794
795#### Config resolve plugins: ordering before
796
797Specify that the current `plugin` context should operate before another named
798`plugin`. You cannot use both `.before()` and `.after()` on the same resolve
799plugin.
800
801```js
802config.resolve
803 .plugin(name)
804 .before(otherName)
805
806// Example
807
808config.resolve
809 .plugin('beta')
810 .use(BetaWebpackPlugin)
811 .end()
812 .plugin('alpha')
813 .use(AlphaWebpackPlugin)
814 .before('beta');
815```
816
817#### Config resolve plugins: ordering after
818
819Specify that the current `plugin` context should operate after another named
820`plugin`. You cannot use both `.before()` and `.after()` on the same resolve
821plugin.
822
823```js
824config.resolve
825 .plugin(name)
826 .after(otherName)
827
828// Example
829
830config.resolve
831 .plugin('beta')
832 .after('alpha')
833 .use(BetaWebpackTemplate)
834 .end()
835 .plugin('alpha')
836 .use(AlphaWebpackPlugin);
837```
838
839#### Config node
840
841```js
842config.node : ChainedMap
843
844config.node
845 .set('__dirname', 'mock')
846 .set('__filename', 'mock');
847```
848
849#### Config devServer
850
851```js
852config.devServer : ChainedMap
853```
854
855#### Config devServer allowedHosts
856
857```js
858config.devServer.allowedHosts : ChainedSet
859
860config.devServer.allowedHosts
861 .add(value)
862 .prepend(value)
863 .clear()
864```
865
866#### Config devServer: shorthand methods
867
868```js
869config.devServer
870 .bonjour(bonjour)
871 .clientLogLevel(clientLogLevel)
872 .color(color)
873 .compress(compress)
874 .contentBase(contentBase)
875 .disableHostCheck(disableHostCheck)
876 .filename(filename)
877 .headers(headers)
878 .historyApiFallback(historyApiFallback)
879 .host(host)
880 .hot(hot)
881 .hotOnly(hotOnly)
882 .https(https)
883 .inline(inline)
884 .info(info)
885 .lazy(lazy)
886 .noInfo(noInfo)
887 .open(open)
888 .openPage(openPage)
889 .overlay(overlay)
890 .pfx(pfx)
891 .pfxPassphrase(pfxPassphrase)
892 .port(port)
893 .progress(progress)
894 .proxy(proxy)
895 .public(public)
896 .publicPath(publicPath)
897 .quiet(quiet)
898 .setup(setup)
899 .socket(socket)
900 .staticOptions(staticOptions)
901 .stats(stats)
902 .stdin(stdin)
903 .useLocalIp(useLocalIp)
904 .watchContentBase(watchContentBase)
905 .watchOptions(watchOptions)
906```
907
908#### Config module
909
910```js
911config.module : ChainedMap
912```
913
914#### Config module: shorthand methods
915
916```js
917config.module : ChainedMap
918
919config.module
920 .noParse(noParse)
921```
922
923#### Config module rules: shorthand methods
924
925```js
926config.module.rules : ChainedMap
927
928config.module
929 .rule(name)
930 .test(test)
931 .pre()
932 .post()
933 .enforce(preOrPost)
934```
935
936#### Config module rules uses (loaders): creating
937
938```js
939config.module.rules{}.uses : ChainedMap
940
941config.module
942 .rule(name)
943 .use(name)
944 .loader(loader)
945 .options(options)
946
947// Example
948
949config.module
950 .rule('compile')
951 .use('babel')
952 .loader('babel-loader')
953 .options({ presets: ['@babel/preset-env'] });
954```
955
956#### Config module rules uses (loaders): modifying options
957
958```js
959config.module
960 .rule(name)
961 .use(name)
962 .tap(options => newOptions)
963
964// Example
965
966config.module
967 .rule('compile')
968 .use('babel')
969 .tap(options => merge(options, {
970 plugins: ['@babel/plugin-proposal-class-properties']
971 }));
972```
973
974#### Config module rules oneOfs (conditional rules):
975
976```js
977config.module.rules{}.oneOfs : ChainedMap<Rule>
978
979config.module
980 .rule(name)
981 .oneOf(name)
982
983// Example
984
985config.module
986 .rule('css')
987 .oneOf('inline')
988 .resourceQuery(/inline/)
989 .use('url')
990 .loader('url-loader')
991 .end()
992 .end()
993 .oneOf('external')
994 .resourceQuery(/external/)
995 .use('file')
996 .loader('file-loader')
997```
998
999#### Config module rules oneOfs (conditional rules): ordering before
1000Specify that the current `oneOf` context should operate before another named
1001`oneOf`. You cannot use both `.before()` and `.after()` on the same `oneOf`.
1002
1003```js
1004config.module
1005 .rule(name)
1006 .oneOf(name)
1007 .before()
1008
1009// Example
1010
1011config.module
1012 .rule('scss')
1013 .test(/\.scss$/)
1014 .oneOf('normal')
1015 .use('sass')
1016 .loader('sass-loader')
1017 .end()
1018 .end()
1019 .oneOf('sass-vars')
1020 .before('normal')
1021 .resourceQuery(/\?sassvars/)
1022 .use('sass-vars')
1023 .loader('sass-vars-to-js-loader')
1024```
1025
1026#### Config module rules oneOfs (conditional rules): ordering after
1027Specify that the current `oneOf` context should operate after another named
1028`oneOf`. You cannot use both `.before()` and `.after()` on the same `oneOf`.
1029
1030```js
1031config.module
1032 .rule(name)
1033 .oneOf(name)
1034 .after()
1035
1036// Example
1037
1038config.module
1039 .rule('scss')
1040 .test(/\.scss$/)
1041 .oneOf('vue')
1042 .resourceQuery(/\?vue/)
1043 .use('vue-style')
1044 .loader('vue-style-loader')
1045 .end()
1046 .end()
1047 .oneOf('normal')
1048 .use('sass')
1049 .loader('sass-loader')
1050 .end()
1051 .end()
1052 .oneOf('sass-vars')
1053 .after('vue')
1054 .resourceQuery(/\?sassvars/)
1055 .use('sass-vars')
1056 .loader('sass-vars-to-js-loader')
1057```
1058
1059---
1060
1061### Merging Config
1062
1063webpack-chain supports merging in an object to the configuration instance which
1064matches a layout similar to how the webpack-chain schema is laid out. Note that
1065this is not a webpack configuration object, but you may transform a webpack
1066configuration object before providing it to webpack-chain to match its layout.
1067
1068```js
1069config.merge({ devtool: 'source-map' });
1070
1071config.get('devtool') // "source-map"
1072```
1073
1074```js
1075config.merge({
1076 [key]: value,
1077
1078 amd,
1079 bail,
1080 cache,
1081 context,
1082 devtool,
1083 externals,
1084 loader,
1085 mode,
1086 parallelism,
1087 profile,
1088 recordsPath,
1089 recordsInputPath,
1090 recordsOutputPath,
1091 stats,
1092 target,
1093 watch,
1094 watchOptions,
1095
1096 entry: {
1097 [name]: [...values]
1098 },
1099
1100 plugin: {
1101 [name]: {
1102 plugin: WebpackPlugin,
1103 args: [...args],
1104 before,
1105 after
1106 }
1107 },
1108
1109 devServer: {
1110 [key]: value,
1111
1112 clientLogLevel,
1113 compress,
1114 contentBase,
1115 filename,
1116 headers,
1117 historyApiFallback,
1118 host,
1119 hot,
1120 hotOnly,
1121 https,
1122 inline,
1123 lazy,
1124 noInfo,
1125 overlay,
1126 port,
1127 proxy,
1128 quiet,
1129 setup,
1130 stats,
1131 watchContentBase
1132 },
1133
1134 node: {
1135 [key]: value
1136 },
1137
1138 optimization: {
1139 concatenateModules,
1140 flagIncludedChunks,
1141 mergeDuplicateChunks,
1142 minimize,
1143 minimizer,
1144 namedChunks,
1145 namedModules,
1146 nodeEnv,
1147 noEmitOnErrors,
1148 occurrenceOrder,
1149 portableRecords,
1150 providedExports,
1151 removeAvailableModules,
1152 removeEmptyChunks,
1153 runtimeChunk,
1154 sideEffects,
1155 splitChunks,
1156 usedExports,
1157 },
1158
1159 performance: {
1160 [key]: value,
1161
1162 hints,
1163 maxEntrypointSize,
1164 maxAssetSize,
1165 assetFilter
1166 },
1167
1168 resolve: {
1169 [key]: value,
1170
1171 alias: {
1172 [key]: value
1173 },
1174 aliasFields: [...values],
1175 descriptionFields: [...values],
1176 extensions: [...values],
1177 mainFields: [...values],
1178 mainFiles: [...values],
1179 modules: [...values],
1180
1181 plugin: {
1182 [name]: {
1183 plugin: WebpackPlugin,
1184 args: [...args],
1185 before,
1186 after
1187 }
1188 }
1189 },
1190
1191 resolveLoader: {
1192 [key]: value,
1193
1194 alias: {
1195 [key]: value
1196 },
1197 aliasFields: [...values],
1198 descriptionFields: [...values],
1199 extensions: [...values],
1200 mainFields: [...values],
1201 mainFiles: [...values],
1202 modules: [...values],
1203 moduleExtensions: [...values],
1204 packageMains: [...values],
1205
1206 plugin: {
1207 [name]: {
1208 plugin: WebpackPlugin,
1209 args: [...args],
1210 before,
1211 after
1212 }
1213 }
1214 },
1215
1216 module: {
1217 [key]: value,
1218
1219 rule: {
1220 [name]: {
1221 [key]: value,
1222
1223 enforce,
1224 issuer,
1225 parser,
1226 resource,
1227 resourceQuery,
1228 test,
1229
1230 include: [...paths],
1231 exclude: [...paths],
1232
1233 oneOf: {
1234 [name]: Rule
1235 },
1236
1237 use: {
1238 [name]: {
1239 loader: LoaderString,
1240 options: LoaderOptions,
1241 before,
1242 after
1243 }
1244 }
1245 }
1246 }
1247 }
1248})
1249```
1250
1251### Conditional configuration
1252
1253When working with instances of `ChainedMap` and `ChainedSet`, you can perform
1254conditional configuration using `when`. You must specify an expression to
1255`when()` which will be evaluated for truthiness or falsiness. If the expression
1256is truthy, the first function argument will be invoked with an instance of the
1257current chained instance. You can optionally provide a second function to be
1258invoked when the condition is falsy, which is also given the current chained
1259instance.
1260
1261```js
1262// Example: Only add minify plugin during production
1263config
1264 .when(process.env.NODE_ENV === 'production', config => {
1265 config
1266 .plugin('minify')
1267 .use(BabiliWebpackPlugin);
1268 });
1269```
1270
1271```js
1272// Example: Only add minify plugin during production,
1273// otherwise set devtool to source-map
1274config
1275 .when(process.env.NODE_ENV === 'production',
1276 config => config.plugin('minify').use(BabiliWebpackPlugin),
1277 config => config.devtool('source-map')
1278 );
1279```
1280
1281### Inspecting generated configuration
1282
1283You can inspect the generated webpack config using `config.toString()`. This
1284will generate a stringified version of the config with comment hints for named
1285rules, uses and plugins:
1286
1287``` js
1288config
1289 .module
1290 .rule('compile')
1291 .test(/\.js$/)
1292 .use('babel')
1293 .loader('babel-loader');
1294
1295config.toString();
1296
1297/*
1298{
1299 module: {
1300 rules: [
1301 /* config.module.rule('compile') */
1302 {
1303 test: /\.js$/,
1304 use: [
1305 /* config.module.rule('compile').use('babel') */
1306 {
1307 loader: 'babel-loader'
1308 }
1309 ]
1310 }
1311 ]
1312 }
1313}
1314*/
1315```
1316
1317By default the generated string cannot be used directly as real webpack config
1318if it contains functions and plugins that need to be required. In order to
1319generate usable config, you can customize how functions and plugins are
1320stringified by setting a special `__expression` property on them:
1321
1322``` js
1323class MyPlugin {}
1324MyPlugin.__expression = `require('my-plugin')`;
1325
1326function myFunction () {}
1327myFunction.__expression = `require('my-function')`;
1328
1329config
1330 .plugin('example')
1331 .use(MyPlugin, [{ fn: myFunction }]);
1332
1333config.toString();
1334
1335/*
1336{
1337 plugins: [
1338 new (require('my-plugin'))({
1339 fn: require('my-function')
1340 })
1341 ]
1342}
1343*/
1344```
1345
1346Plugins specified via their path will have their `require()` statement generated
1347automatically:
1348
1349``` js
1350config
1351 .plugin('env')
1352 .use(require.resolve('webpack/lib/ProvidePlugin'), [{ jQuery: 'jquery' }])
1353
1354config.toString();
1355
1356/*
1357{
1358 plugins: [
1359 new (require('/foo/bar/src/node_modules/webpack/lib/EnvironmentPlugin.js'))(
1360 {
1361 jQuery: 'jquery'
1362 }
1363 )
1364 ]
1365}
1366*/
1367```
1368
1369You can also call `toString` as a static method on `Config` in order to
1370modify the configuration object prior to stringifying.
1371
1372```js
1373Config.toString({
1374 ...config.toConfig(),
1375 module: {
1376 defaultRules: [
1377 {
1378 use: [
1379 {
1380 loader: 'banner-loader',
1381 options: { prefix: 'banner-prefix.txt' },
1382 },
1383 ],
1384 },
1385 ],
1386 },
1387})
1388```
1389
1390```
1391{
1392 plugins: [
1393 /* config.plugin('foo') */
1394 new TestPlugin()
1395 ],
1396 module: {
1397 defaultRules: [
1398 {
1399 use: [
1400 {
1401 loader: 'banner-loader',
1402 options: {
1403 prefix: 'banner-prefix.txt'
1404 }
1405 }
1406 ]
1407 }
1408 ]
1409 }
1410}
1411```
1412
1413[npm-image]: https://img.shields.io/npm/v/webpack-chain.svg
1414[npm-downloads]: https://img.shields.io/npm/dt/webpack-chain.svg
1415[npm-url]: https://www.npmjs.com/package/webpack-chain
1416[travis-image]: https://api.travis-ci.org/neutrinojs/webpack-chain.svg?branch=master
1417[travis-url]: https://travis-ci.org/neutrinojs/webpack-chain