Nodejs interactive tool library -- webpack merge and webpack chain

Fried chicken Superman 2020-11-09 19:54:40
nodejs interactive tool library webpack


nodejs Interactive tool library series

library effect
chalk-pipe Create a chalk style scheme using simpler style strings
chalk Handle terminal string style correctly
Commander.js complete node.js Command line solutions
Inquirer.js A common set of interactive command line user interfaces .
slash System path character processing
minimist Parse parameter options
dotenv Change the environment variable from .env File loading to process.env in
dotenv-expand Expand the environment variables that already exist on the computer
hash-sum Very fast unique hash generator
deepmerge Deep merge enumerable properties of two or more objects .
yaml-front-matter analysis yaml or json
resolve Realization node Of require.resolve() Algorithm , So you can use it asynchronously and synchronously require.resolve() For documents
semver npm Semantic versioner for
leven Measure the difference between two strings <br/> One of the fastest JS Implementation one
lru cache Delete the cache object of the least recently used item
portfinder Automatic search 8000 to 65535 Available port number in
ora Elegant terminal wheel
envinfo Generate troubleshooting software problems ( Such as operating system 、 Binary version 、 browser 、 Installed language, etc ) General details required when reporting
memfs Memory file system and Node's fs API The same implementation
execa Process execution for humans
webpack-merge Used to join arrays and merge objects , To create a new object
webpack-chain Use chain API To generate simplification webpack Version configuration changes

nodejs Interactive tool library -- chalk-pipe and chalk

nodejs Interactive tool library -- commander and Inquirer

nodejs Interactive tool library -- slash, minimist and dotenv, dotenv-expand

nodejs Interactive tool library -- hash-sum, deepmerge and yaml-front-matter

nodejs Interactive tool library -- resolve and semver

nodejs Interactive tool library -- leven, lru cache and portfinder

nodejs Interactive tool library -- ora and envinfo

nodejs Interactive tool library -- memfs and execa

nodejs Interactive tool library -- webpack-merge and webpack-chain

webpack-merge - Merge designed for Webpack

webpack-merge Provide merge Function is used to join arrays and merge objects , To create a new object . If a function is encountered , It will execute them , Run results by algorithm , Then wrap the return value into the function again .

This behavior is configuring webpack Especially useful when , Although it can be used for more than that . Whenever you need to merge configuration objects ,webpack-merge They all come in handy .

merge(...configuration | [...configuration])

merge yes API At the heart of , And the most important thought . Usually this is what you need , Unless you want to further customize

const { merge } = require('webpack-merge');
// Default API
const output = merge(object1, object2, object3, ...);
// You can pass an array of objects directly .
// This applies to all available features .
const output = merge([object1, object2, object3]);
// The key that matches the right takes precedence :
const output = merge(
{ fruit: "apple", color: "red" },
{ fruit: "strawberries" }
);
console.log(output);
// { color: "red", fruit: "strawberries"}

Limitations

Be careful Promises Is not supported ! If you want to return a package configuration Promise, merge In one of them . for example : Promise.resolve(merge({ ... }, { ... })).

The same is true of the configuration level function in the following example :

webpack.config.js

const commonConfig = { ... };
const productionConfig = { ... };
const developmentConfig = { ... };
module.exports = env => {
switch(env) {
case 'development':
return merge(commonConfig, developmentConfig);
case 'production':
return merge(commonConfig, productionConfig);
default:
throw new Error('No matching configuration was found!');
}
}

You can go through webpack --env development Choose the configuration you want if you use webpack-cli.

mergeWithCustomize({ customizeArray, customizeObject })(...configuration | [...configuration])

If you need more flexibility ,merge The behavior can be customized for each field as follows :

const { mergeWithCustomize } = require('webpack-merge');
const output = mergeWithCustomize(
{
customizeArray(a, b, key) {
if (key === 'extensions') {
return _.uniq([...a, ...b]);
}
// Back to the default merge
return undefined;
},
customizeObject(a, b, key) {
if (key === 'module') {
// Custom merge
return _.merge({}, a, b);
}
// Back to the default merge
return undefined;
}
}
)(object1, object2, object3, ...);

for example , If the previous code only uses object1 and object2 call , and object1 by :

{
foo1: ['object1'],
foo2: ['object1'],
bar1: { object1: {} },
bar2: { object1: {} },
}

and object2 by

{
foo1: ['object2'],
foo2: ['object2'],
bar1: { object2: {} },
bar2: { object2: {} },
}

Then call... For each property of the array type customizeArray, namely :

customizeArray(["object1"], ["object2"], "foo1");
customizeArray(["object1"], ["object2"], "foo2");

Call... On each property of the object type customizeObject, namely :

customizeObject({ object1: {} }, { object2: {} }, bar1);
customizeObject({ object1: {} }, { object2: {} }, bar2);

customizeArray and customizeObject

customizeArray and customizeObject Provide small strategies mergeWithCustomize. They support field names append, prepend, replace, And wildcards .

const { mergeWithCustomize, customizeArray, customizeObject } = require('webpack-merge');
const output = mergeWithCustomize({
customizeArray: customizeArray({
'entry.*': 'prepend'
}),
customizeObject: customizeObject({
entry: 'prepend'
})
})(object1, object2, object3, ...);

unique(<field>, <fields>, field => field)

unique A policy is used to enforce uniqueness in the configuration . When you want to make sure there's only one plug-in , It's the most useful .

first <field> Is the configuration property used to find duplicates .

<fields> Indicates that you are running field =>field Function should be unique

const { mergeWithCustomize, unique } = require("webpack-merge");
const output = mergeWithCustomize({
customizeArray: unique(
"plugins",
["HotModuleReplacementPlugin"],
plugin => plugin.constructor && plugin.constructor.name
)
})(
{
plugins: [new webpack.HotModuleReplacementPlugin()]
},
{
plugins: [new webpack.HotModuleReplacementPlugin()]
}
);
// The output contains only one HotModuleReplacementPlugin Now and its
// It's going to be the last plug-in instance .

mergeWithRules

To support advanced consolidation requirements ( That is to merge ), mergeWithRules Contains additional syntax to allow matching fields and apply matching policies . Consider the complete example below :

const a = {
module: {
rules: [
{
test: /\.css$/,
use: [{ loader: "style-loader" }, { loader: "sass-loader" }]
}
]
}
};
const b = {
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: "style-loader",
options: {
modules: true
}
}
]
}
]
}
};
const result = {
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: "style-loader",
options: {
modules: true
}
},
{ loader: "sass-loader" }
]
}
]
}
};
assert.deepStrictEqual(
mergeWithRules({
module: {
rules: {
test: "match",
use: {
loader: "match",
options: "replace"
}
}
}
})(a, b),
result
);

The way it works is , You should use match( or CustomizeRule) Comment fields to match . matching ( If you are using TypeScript) Match your configuration structure , Then use specific policies to define how to convert specific fields .

Using with TypeScript

webpack-merge Support out of the box TypeScript. You should change the configuration type from webpack Pass it on :

import { Configuration } from "webpack";
import { merge } from "webpack-merge";
const config = merge<Configuration>({...}, {...});
...

Development

  1. nvm use
  2. npm i
  3. npm run build -- --watch in one terminal
  4. npm t -- --watch in another one

Before contributing, please open an issue where to discuss.

Further Information and Support

see SurviveJS - Webpack To dig deeper webpack. This free book is widely used webpack-merge, And shows you how to combine your configuration to keep it maintainable .

If you need specific help , I can also be a consultant . I can make a special contribution to improving the maintainability of settings , At the same time, speed it up and point out better practices . In addition to increasing developer productivity , This work will also have an impact on the end users of the product in terms of reducing application size and load time .

Reference resources

These are the basic common methods and scenarios , For more complete usage, you can refer to the document directly

webpack-merge

webpack-chain

Use chain API To generate simplification webpack edition 2-4 Configuration modification .

This document corresponds to webpack-chain Of v5 edition . About the previous version , see also :

Be careful : although webpack-chain stay Neutrino Is widely used in , But this package is completely independent , Can be used by any project

Introduction

webpack's The core configuration is based on creating and modifying a potentially clunky JavaScript object . Although this is possible for a single project configuration , But trying to share these objects between projects can make subsequent changes confusing , Because you need to have a deep understanding of the underlying object structure to make these changes .

webpack-chain Try to provide a linkable or coherent API To create and modify webpack Configuration to improve the process . API The key parts of can be referenced by user specified names , This helps to standardize how configuration changes across projects .

This can be explained more easily by the following example .

Installation

webpack-chain need Node.js v6.9 Or higher . webpack-chain It's only created for webpack edition 2, 3, and 4 Configuration objects for .

You can use Yarn or npm( Choose any one ) Install this package :

Yarn

yarn add --dev webpack-chain

npm

npm install --save-dev webpack-chain

Getting Started

Once you use webpack-chain replace , You can create a webpack To configure . For this guide , Our example base configuration webpack.config.js At the top level of the project

// need webpack-chain modular . This module exports a single
// Used to create configuration API Constructor for
const Config = require('webpack-chain');
// Use the new API Instantiation configuration
const config = new Config();
// Use chain API Make configuration changes .
// Every API Call to track changes to the storage configuration .
config
// Interact with entry points
.entry('index')
.add('src/index.js')
.end()
// Modify output settings
.output
.path('dist')
.filename('[name].bundle.js');
// Create naming rules that can be modified later
config.module
.rule('lint')
.test(/\.js$/)
.pre()
.include
.add('src')
.end()
// Even create named uses ( loader )
.use('eslint')
.loader('eslint-loader')
.options({
rules: {
semi: 'off'
}
});
config.module
.rule('compile')
.test(/\.js$/)
.include
.add('src')
.add('test')
.end()
.use('babel')
.loader('babel-loader')
.options({
presets: [
['@babel/preset-env', { modules: false }]
]
});
// Also create named plug-ins !
config
.plugin('clean')
.use(CleanPlugin, [['dist'], { root: '/dir' }]);
// Export the completed configuration object for webpack Use
module.exports = config.toConfig();

Sharing configuration is also very simple . Just export the configuration and call .toConfig() It can be delivered to webpack Before

// webpack.core.js
const Config = require('webpack-chain');
const config = new Config();
// Make configuration shared between targets
// ...
module.exports = config;
// webpack.dev.js
const config = require('./webpack.core');
// Dev-specific configuration
// ...
module.exports = config.toConfig();
// webpack.prod.js
const config = require('./webpack.core');
// Production-specific configuration
// ...
module.exports = config.toConfig();

ChainedMap

stay webpack-chain The core API One of the interfaces is ChainedMap. One ChainedMap The operation is similar to JavaScript Map, You can easily link and generate configurations . If an attribute is marked as ChainedMap, It will have the following API And methods :

Unless otherwise stated , These methods will return ChainedMap, Allows you to link these methods .

// Remove all entries from the map .
clear()
// Remove a single entry from the map given its key
// key: *
delete(key)
// Get the value from the map at the corresponding key .
// key: *
// returns: value
get(key)
// Get the value from the map at the corresponding key .
// If the key is missing , Set the key to function fn Result .
// key: *
// fn: Function () -> value
// returns: value
getOrCompute(key, fn)
// stay `key` Location cache Map Set the value .
// key: *
// value: *
set(key, value)
// return `true` or `false` Depending on Map Whether a specific key.
// key: *
// returns: Boolean
has(key)
// Returns an array of all the values stored in the map .
// returns: Array
values()
// Returns the object of all entries in the backup map , Where the key is the object property , And the value corresponding to the key . If the support mapping is empty , Will return “undefined”.
// This will be sorted by the name of the attribute , If the value is used .before() perhaps .after() Of ChainedMap.
// returns: Object, undefined if empty
entries()
// Provides an object that maps its properties and values
// Import backup maps as keys and values .
// You can also provide an array as the second parameter
// Property name used to avoid merging
// obj: Object
// omit: Optional Array
merge(obj, omit)
// Execute the function according to the current configuration context
// handler: Function -> ChainedMap
// to ChainedMap Instance a function with an argument
batch(handler)
// Conditionally execute functions to continue configuration
// condition: Boolean
// whenTruthy: Function -> ChainedMap
// Call when the condition is true , Given ChainedMap A single parameter of the instance
// whenFalsy: Optional Function -> ChainedMap
// Call when the condition is unreliable , Given ChainedMap A single parameter of the instance
when(condition, whenTruthy, whenFalsy)

ChainedSet

webpack-chain Another core in API Interface is ChainedSet. ChainedSet The operation is similar to JavaScript Set, Easy to link and generate configuration . If an attribute is marked as ChainedSet, It will have a API And the method is described as follows :

Unless otherwise stated , These methods will return ChainedMap, Allows you to link these methods .

// Set Add... At the end / Add a value .
// value: *
add(value)
// Set Add... At the beginning / Add a value .
// value: *
prepend(value)
// Set Delete all values .
clear()
// Set Remove specific values .
// value: *
delete(value)
// return `true` or `false` Depending on Map Whether a specific key
// value: *
// returns: Boolean
has(value)
// return backing Set An array containing values
// returns: Array
values()
// Connect the given array to backing Set.
// arr: Array
merge(arr)
// Execute the function according to the current configuration context
// handler: Function -> ChainedSet
// to ChainedSet Instance a function with an argument
batch(handler)
// Conditionally execute functions to continue configuration
// condition: Boolean
// whenTruthy: Function -> ChainedSet
// Call when the condition is true , Given ChainedSet A single parameter of the instance
// whenFalsy: Optional Function -> ChainedSet
// Call when the condition is unreliable , Given ChainedSet A single parameter of the instance
when(condition, whenTruthy, whenFalsy)

Shorthand methods

There are many shortcuts that can be set with the same key as the shortcut name ChainedMap Value on . for example ,devServer.hot It's a shorthand , So it can be used as :

// stay ChainedMap A shorthand method of setting values on the
devServer.hot(true);
// This is equal to :
devServer.set('hot', true);

The quick way is chainable , Therefore, calling it returns the original instance , This allows you to continue with the chain operation

Config

Create a new configuration object .

const Config = require('webpack-chain');
const config = new Config();

stay API Moving to a deeper point will change the context of the modified content . You can refer to the top-level configuration again or call .end() Move one level up to a higher context . If you are familiar with jQuery, that .end() It works similarly . Unless otherwise specified , Otherwise all API Calls will return in the current context API example . such , if necessary , Then you can continuously put API Call chain .

Details about specific values that are valid for all shorthand and low-level methods , Please refer to the webpack docs hierarchy.

Config : ChainedMap
Config shorthand methods
config
.amd(amd)
.bail(bail)
.cache(cache)
.devtool(devtool)
.context(context)
.externals(externals)
.loader(loader)
.name(name)
.mode(mode)
.parallelism(parallelism)
.profile(profile)
.recordsPath(recordsPath)
.recordsInputPath(recordsInputPath)
.recordsOutputPath(recordsOutputPath)
.stats(stats)
.target(target)
.watch(watch)
.watchOptions(watchOptions)
Config entryPoints
// Backed at config.entryPoints : ChainedMap
config.entry(name) : ChainedSet
config
.entry(name)
.add(value)
.add(value)
config
.entry(name)
.clear()
// Using low-level config.entryPoints:
config.entryPoints
.get(name)
.add(value)
.add(value)
config.entryPoints
.get(name)
.clear()
Config output: shorthand methods
config.output : ChainedMap
config.output
.auxiliaryComment(auxiliaryComment)
.chunkFilename(chunkFilename)
.chunkLoadTimeout(chunkLoadTimeout)
.crossOriginLoading(crossOriginLoading)
.devtoolFallbackModuleFilenameTemplate(devtoolFallbackModuleFilenameTemplate)
.devtoolLineToLine(devtoolLineToLine)
.devtoolModuleFilenameTemplate(devtoolModuleFilenameTemplate)
.filename(filename)
.hashFunction(hashFunction)
.hashDigest(hashDigest)
.hashDigestLength(hashDigestLength)
.hashSalt(hashSalt)
.hotUpdateChunkFilename(hotUpdateChunkFilename)
.hotUpdateFunction(hotUpdateFunction)
.hotUpdateMainFilename(hotUpdateMainFilename)
.jsonpFunction(jsonpFunction)
.library(library)
.libraryExport(libraryExport)
.libraryTarget(libraryTarget)
.path(path)
.pathinfo(pathinfo)
.publicPath(publicPath)
.sourceMapFilename(sourceMapFilename)
.sourcePrefix(sourcePrefix)
.strictModuleExceptionHandling(strictModuleExceptionHandling)
.umdNamedDefine(umdNamedDefine)
Config resolve: shorthand methods
config.resolve : ChainedMap
config.resolve
.cachePredicate(cachePredicate)
.cacheWithContext(cacheWithContext)
.enforceExtension(enforceExtension)
.enforceModuleExtension(enforceModuleExtension)
.unsafeCache(unsafeCache)
.symlinks(symlinks)
Config resolve alias
config.resolve.alias : ChainedMap
config.resolve.alias
.set(key, value)
.set(key, value)
.delete(key)
.clear()
Config resolve modules
config.resolve.modules : ChainedSet
config.resolve.modules
.add(value)
.prepend(value)
.clear()
Config resolve aliasFields
config.resolve.aliasFields : ChainedSet
config.resolve.aliasFields
.add(value)
.prepend(value)
.clear()
Config resolve descriptionFields
config.resolve.descriptionFields : ChainedSet
config.resolve.descriptionFields
.add(value)
.prepend(value)
.clear()
Config resolve extensions
config.resolve.extensions : ChainedSet
config.resolve.extensions
.add(value)
.prepend(value)
.clear()
Config resolve mainFields
config.resolve.mainFields : ChainedSet
config.resolve.mainFields
.add(value)
.prepend(value)
.clear()
Config resolve mainFiles
config.resolve.mainFiles : ChainedSet
config.resolve.mainFiles
.add(value)
.prepend(value)
.clear()
Config resolveLoader

config.resolveLoaderAPI and config.resolve identical , Added the following :

Config resolveLoader moduleExtensions
config.resolveLoader.moduleExtensions : ChainedSet
config.resolveLoader.moduleExtensions
.add(value)
.prepend(value)
.clear()
Config resolveLoader packageMains
config.resolveLoader.packageMains : ChainedSet
config.resolveLoader.packageMains
.add(value)
.prepend(value)
.clear()
Config performance: shorthand methods
config.performance : ChainedMap
config.performance
.hints(hints)
.maxEntrypointSize(maxEntrypointSize)
.maxAssetSize(maxAssetSize)
.assetFilter(assetFilter)
Configuring optimizations: shorthand methods
config.optimization : ChainedMap
config.optimization
.concatenateModules(concatenateModules)
.flagIncludedChunks(flagIncludedChunks)
.mergeDuplicateChunks(mergeDuplicateChunks)
.minimize(minimize)
.namedChunks(namedChunks)
.namedModules(namedModules)
.nodeEnv(nodeEnv)
.noEmitOnErrors(noEmitOnErrors)
.occurrenceOrder(occurrenceOrder)
.portableRecords(portableRecords)
.providedExports(providedExports)
.removeAvailableModules(removeAvailableModules)
.removeEmptyChunks(removeEmptyChunks)
.runtimeChunk(runtimeChunk)
.sideEffects(sideEffects)
.splitChunks(splitChunks)
.usedExports(usedExports)
Config optimization minimizers
// Backed at config.optimization.minimizers
config.optimization
.minimizer(name) : ChainedMap
Config optimization minimizers: adding

Be careful : Do not use new Create minimal plug-ins , Because it will be done for you .

config.optimization
.minimizer(name)
.use(WebpackPlugin, args)
// Examples
config.optimization
.minimizer('css')
.use(OptimizeCSSAssetsPlugin, [{ cssProcessorOptions: { safe: true } }])
// Minimization plug-ins can also be specified according to their path , So in the plug-in or webpack In the case that the configuration will not eventually be used , You can skip expensive require().
config.optimization
.minimizer('css')
.use(require.resolve('optimize-css-assets-webpack-plugin'), [{ cssProcessorOptions: { safe: true } }])
Config optimization minimizers: modify arguments
config.optimization
.minimizer(name)
.tap(args => newArgs)
// Example
config.optimization
.minimizer('css')
.tap(args => [...args, { cssProcessorOptions: { safe: false } }])
Config optimization minimizers: modify instantiation
config.optimization
.minimizer(name)
.init((Plugin, args) => new Plugin(...args));
Config optimization minimizers: removing
config.optimization.minimizers.delete(name)
Config plugins
// Backed at config.plugins
config.plugin(name) : ChainedMap
Config plugins: adding

Be careful : Do not use new To create plug-ins , Because it will be done for you .

config
.plugin(name)
.use(WebpackPlugin, args)
// Examples
config
.plugin('hot')
.use(webpack.HotModuleReplacementPlugin);
// Minimization plug-ins can also be specified according to their path , So in the plug-in or webpack In the case that the configuration will not eventually be used , You can skip expensive require().
config
.plugin('env')
.use(require.resolve('webpack/lib/EnvironmentPlugin'), [{ 'VAR': false }]);
Config plugins: modify arguments
config
.plugin(name)
.tap(args => newArgs)
// Example
config
.plugin('env')
.tap(args => [...args, 'SECRET_KEY']);
Config plugins: modify instantiation
config
.plugin(name)
.init((Plugin, args) => new Plugin(...args));
Config plugins: removing
config.plugins.delete(name)
Config plugins: ordering before

Specifies that the current plug-in context should operate before another named plug-in . Cannot be used on the same plug-in at the same time .before() and .after().

config
.plugin(name)
.before(otherName)
// Example
config
.plugin('html-template')
.use(HtmlWebpackTemplate)
.end()
.plugin('script-ext')
.use(ScriptExtWebpackPlugin)
.before('html-template');
Config plugins: ordering after

Specifies that the current plug-in context should operate after another named plug-in . Cannot be used on the same plug-in at the same time .before() and .after().

config
.plugin(name)
.after(otherName)
// Example
config
.plugin('html-template')
.after('script-ext')
.use(HtmlWebpackTemplate)
.end()
.plugin('script-ext')
.use(ScriptExtWebpackPlugin);
Config resolve plugins
// Backed at config.resolve.plugins
config.resolve.plugin(name) : ChainedMap
Config resolve plugins: adding

Be careful : Do not use new To create plug-ins , Because it will be done for you .

config.resolve
.plugin(name)
.use(WebpackPlugin, args)
Config resolve plugins: modify arguments
config.resolve
.plugin(name)
.tap(args => newArgs)
Config resolve plugins: modify instantiation
config.resolve
.plugin(name)
.init((Plugin, args) => new Plugin(...args))
Config resolve plugins: removing
config.resolve.plugins.delete(name)
Config resolve plugins: ordering before

Specifies that the current plug-in context should operate before another named plug-in . Cannot be used on the same parsing plug-in at the same time .before() and .after().

config.resolve
.plugin(name)
.before(otherName)
// Example
config.resolve
.plugin('beta')
.use(BetaWebpackPlugin)
.end()
.plugin('alpha')
.use(AlphaWebpackPlugin)
.before('beta');
Config resolve plugins: ordering after

Specifies that the current plug-in context should operate after another named plug-in . Cannot be used on the same parsing plug-in at the same time .before() and .after().

config.resolve
.plugin(name)
.after(otherName)
// Example
config.resolve
.plugin('beta')
.after('alpha')
.use(BetaWebpackTemplate)
.end()
.plugin('alpha')
.use(AlphaWebpackPlugin);
Config node
config.node : ChainedMap
config.node
.set('__dirname', 'mock')
.set('__filename', 'mock');
Config devServer
config.devServer : ChainedMap
Config devServer allowedHosts
config.devServer.allowedHosts : ChainedSet
config.devServer.allowedHosts
.add(value)
.prepend(value)
.clear()
Config devServer: shorthand methods
config.devServer
.bonjour(bonjour)
.clientLogLevel(clientLogLevel)
.color(color)
.compress(compress)
.contentBase(contentBase)
.disableHostCheck(disableHostCheck)
.filename(filename)
.headers(headers)
.historyApiFallback(historyApiFallback)
.host(host)
.hot(hot)
.hotOnly(hotOnly)
.https(https)
.inline(inline)
.info(info)
.lazy(lazy)
.noInfo(noInfo)
.open(open)
.openPage(openPage)
.overlay(overlay)
.pfx(pfx)
.pfxPassphrase(pfxPassphrase)
.port(port)
.progress(progress)
.proxy(proxy)
.public(public)
.publicPath(publicPath)
.quiet(quiet)
.setup(setup)
.socket(socket)
.staticOptions(staticOptions)
.stats(stats)
.stdin(stdin)
.useLocalIp(useLocalIp)
.watchContentBase(watchContentBase)
.watchOptions(watchOptions)
Config module
config.module : ChainedMap
Config module: shorthand methods
config.module : ChainedMap
config.module
.noParse(noParse)
Config module rules: shorthand methods
config.module.rules : ChainedMap
config.module
.rule(name)
.test(test)
.pre()
.post()
.enforce(preOrPost)
Config module rules uses (loaders): creating
config.module.rules{}.uses : ChainedMap
config.module
.rule(name)
.use(name)
.loader(loader)
.options(options)
// Example
config.module
.rule('compile')
.use('babel')
.loader('babel-loader')
.options({ presets: ['@babel/preset-env'] });
Config module rules uses (loaders): modifying options
config.module
.rule(name)
.use(name)
.tap(options => newOptions)
// Example
config.module
.rule('compile')
.use('babel')
.tap(options => merge(options, {
plugins: ['@babel/plugin-proposal-class-properties']
}));
Config module rules oneOfs (conditional rules):
config.module.rules{}.oneOfs : ChainedMap<Rule>
config.module
.rule(name)
.oneOf(name)
// Example
config.module
.rule('css')
.oneOf('inline')
.resourceQuery(/inline/)
.use('url')
.loader('url-loader')
.end()
.end()
.oneOf('external')
.resourceQuery(/external/)
.use('file')
.loader('file-loader')
Config module rules oneOfs (conditional rules): ordering before

The current context of the specified context should operate before another named context ..before() and .after() Can't be used at the same time .

config.module
.rule(name)
.oneOf(name)
.before()
// Example
config.module
.rule('scss')
.test(/\.scss$/)
.oneOf('normal')
.use('sass')
.loader('sass-loader')
.end()
.end()
.oneOf('sass-vars')
.before('normal')
.resourceQuery(/\?sassvars/)
.use('sass-vars')
.loader('sass-vars-to-js-loader')
Config module rules oneOfs (conditional rules): ordering after

The current context of the specified context should operate after another named context ..before() and .after() Can't be used at the same time .

config.module
.rule(name)
.oneOf(name)
.after()
// Example
config.module
.rule('scss')
.test(/\.scss$/)
.oneOf('vue')
.resourceQuery(/\?vue/)
.use('vue-style')
.loader('vue-style-loader')
.end()
.end()
.oneOf('normal')
.use('sass')
.loader('sass-loader')
.end()
.end()
.oneOf('sass-vars')
.after('vue')
.resourceQuery(/\?sassvars/)
.use('sass-vars')
.loader('sass-vars-to-js-loader')

Merging Config

webpack-chain Supports merging objects into configuration instances similar to layout . Please note that , This is not a webpack Configuration object , But you can put a webpack Configuration objects are provided to webpack-chain Before converting it to match its layout .

config.merge({ devtool: 'source-map' });
config.get('devtool') // "source-map"
config.merge({
[key]: value,
amd,
bail,
cache,
context,
devtool,
externals,
loader,
mode,
parallelism,
profile,
recordsPath,
recordsInputPath,
recordsOutputPath,
stats,
target,
watch,
watchOptions,
entry: {
[name]: [...values]
},
plugin: {
[name]: {
plugin: WebpackPlugin,
args: [...args],
before,
after
}
},
devServer: {
[key]: value,
clientLogLevel,
compress,
contentBase,
filename,
headers,
historyApiFallback,
host,
hot,
hotOnly,
https,
inline,
lazy,
noInfo,
overlay,
port,
proxy,
quiet,
setup,
stats,
watchContentBase
},
node: {
[key]: value
},
optimization: {
concatenateModules,
flagIncludedChunks,
mergeDuplicateChunks,
minimize,
minimizer,
namedChunks,
namedModules,
nodeEnv,
noEmitOnErrors,
occurrenceOrder,
portableRecords,
providedExports,
removeAvailableModules,
removeEmptyChunks,
runtimeChunk,
sideEffects,
splitChunks,
usedExports,
},
performance: {
[key]: value,
hints,
maxEntrypointSize,
maxAssetSize,
assetFilter
},
resolve: {
[key]: value,
alias: {
[key]: value
},
aliasFields: [...values],
descriptionFields: [...values],
extensions: [...values],
mainFields: [...values],
mainFiles: [...values],
modules: [...values],
plugin: {
[name]: {
plugin: WebpackPlugin,
args: [...args],
before,
after
}
}
},
resolveLoader: {
[key]: value,
alias: {
[key]: value
},
aliasFields: [...values],
descriptionFields: [...values],
extensions: [...values],
mainFields: [...values],
mainFiles: [...values],
modules: [...values],
moduleExtensions: [...values],
packageMains: [...values],
plugin: {
[name]: {
plugin: WebpackPlugin,
args: [...args],
before,
after
}
}
},
module: {
[key]: value,
rule: {
[name]: {
[key]: value,
enforce,
issuer,
parser,
resource,
resourceQuery,
test,
include: [...paths],
exclude: [...paths],
oneOf: {
[name]: Rule
},
use: {
[name]: {
loader: LoaderString,
options: LoaderOptions,
before,
after
}
}
}
}
}
})

Conditional configuration

In the use of ChainedMap and ChainedSet When an instance , have access to When Execute condition configuration . You must when() Specify an expression , The expression will be evaluated as true or false . If the expression is true , The first function parameter is called with the instance of the current linked instance . You can choose to provide a second function , So that if the condition is falsy Called when the , This function also provides the current link .

// Example : Only add... In the production process minify plug-in unit
config
.when(process.env.NODE_ENV === 'production', config => {
config
.plugin('minify')
.use(BabiliWebpackPlugin);
});
// Example : Only add... In the production process minify plug-in unit
// Otherwise set devtool by source-map
config
.when(process.env.NODE_ENV === 'production',
config => config.plugin('minify').use(BabiliWebpackPlugin),
config => config.devtool('source-map')
);

Inspecting generated configuration

You can use the following config.toString() The command checks the generated webpack To configure . This will generate a stringified Version configuration , With about naming rules 、 Note tips for using methods and plug-ins :

config
.module
.rule('compile')
.test(/\.js$/)
.use('babel')
.loader('babel-loader');
config.toString();
/*
{
module: {
rules: [
/* config.module.rule('compile') */
{
test: /\.js$/,
use: [
/* config.module.rule('compile').use('babel') */
{
loader: 'babel-loader'
}
]
}
]
}
}
*/

By default , The generated string cannot be used directly as real webpack To configure , If it contains the required objects and plug-ins . To generate available configurations , You can set a special __expression Properties to customize how objects and plug-ins are layered

const sass = require('sass');
sass.__expression = `require('sass');
class MyPlugin {}
MyPlugin.__expression = `require('my-plugin')`;
function myFunction () {}
myFunction.__expression = `require('my-function')`;
config
.plugin('example')
.use(MyPlugin, [{ fn: myFunction, implementation: sass, }]);
config.toString();
/*
{
plugins: [
new (require('my-plugin'))({
fn: require('my-function'),
implementation: require('sass')
})
]
}
*/

Plug ins specified by path will automatically generate their require() sentence :

config
.plugin('env')
.use(require.resolve('webpack/lib/ProvidePlugin'), [{ jQuery: 'jquery' }])
config.toString();
/*
{
plugins: [
new (require('/foo/bar/src/node_modules/webpack/lib/EnvironmentPlugin.js'))(
{
jQuery: 'jquery'
}
)
]
}
*/

You can also toString Call static methods as configuration , To modify the configuration object before stringing .

Config.toString({
...config.toConfig(),
module: {
defaultRules: [
{
use: [
{
loader: 'banner-loader',
options: { prefix: 'banner-prefix.txt' },
},
],
},
],
},
})
{
plugins: [
/* config.plugin('foo') */
new TestPlugin()
],
module: {
defaultRules: [
{
use: [
{
loader: 'banner-loader',
options: {
prefix: 'banner-prefix.txt'
}
}
]
}
]
}
}

Reference resources

These are the basic common methods and scenarios , For more complete usage, you can refer to the document directly

webpack-chain

版权声明
本文为[Fried chicken Superman]所创,转载请带上原文链接,感谢

  1. [front end -- JavaScript] knowledge point (IV) -- memory leakage in the project (I)
  2. This mechanism in JS
  3. Vue 3.0 source code learning 1 --- rendering process of components
  4. Learning the realization of canvas and simple drawing
  5. gin里获取http请求过来的参数
  6. vue3的新特性
  7. Get the parameters from HTTP request in gin
  8. New features of vue3
  9. vue-cli 引入腾讯地图(最新 api,rocketmq原理面试
  10. Vue 学习笔记(3,免费Java高级工程师学习资源
  11. Vue 学习笔记(2,Java编程视频教程
  12. Vue cli introduces Tencent maps (the latest API, rocketmq)
  13. Vue learning notes (3, free Java senior engineer learning resources)
  14. Vue learning notes (2, Java programming video tutorial)
  15. 【Vue】—props属性
  16. 【Vue】—创建组件
  17. [Vue] - props attribute
  18. [Vue] - create component
  19. 浅谈vue响应式原理及发布订阅模式和观察者模式
  20. On Vue responsive principle, publish subscribe mode and observer mode
  21. 浅谈vue响应式原理及发布订阅模式和观察者模式
  22. On Vue responsive principle, publish subscribe mode and observer mode
  23. Xiaobai can understand it. It only takes 4 steps to solve the problem of Vue keep alive cache component
  24. Publish, subscribe and observer of design patterns
  25. Summary of common content added in ES6 + (II)
  26. No.8 Vue element admin learning (III) vuex learning and login method analysis
  27. Write a mini webpack project construction tool
  28. Shopping cart (front-end static page preparation)
  29. Introduction to the fluent platform
  30. Webpack5 cache
  31. The difference between drop-down box select option and datalist
  32. CSS review (III)
  33. Node.js学习笔记【七】
  34. Node.js learning notes [VII]
  35. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  36. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  37. 【JQuery框架,Java编程教程视频下载
  38. [jQuery framework, Java programming tutorial video download
  39. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  40. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  41. 【Vue,阿里P8大佬亲自教你
  42. 【Vue基础知识总结 5,字节跳动算法工程师面试经验
  43. [Vue, Ali P8 teaches you personally
  44. [Vue basic knowledge summary 5. Interview experience of byte beating Algorithm Engineer
  45. 【问题记录】- 谷歌浏览器 Html生成PDF
  46. [problem record] - PDF generated by Google browser HTML
  47. 【问题记录】- 谷歌浏览器 Html生成PDF
  48. [problem record] - PDF generated by Google browser HTML
  49. 【JavaScript】查漏补缺 —数组中reduce()方法
  50. [JavaScript] leak checking and defect filling - reduce() method in array
  51. 【重识 HTML (3),350道Java面试真题分享
  52. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  53. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  54. [re recognize HTML (3) and share 350 real Java interview questions
  55. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  56. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  57. 【重识 HTML ,nginx面试题阿里
  58. 【重识 HTML (4),ELK原来这么简单
  59. [re recognize HTML, nginx interview questions]
  60. [re recognize HTML (4). Elk is so simple