One, foreword

The core configuration of WebPack is created and modified based on a potentially difficult JavaScript object. Although it is no problem for the configuration of a single project, but when you have more project team, and to attempt to all projects share webpack configuration file, you will feel difficult to start, because you need to consider the scalability build configuration, such as a component has its own unique features, need to do some personalized configuration, It gets tricky.

Webpack-chain attempts to create and modify WebPack configurations by providing a chained or downstream API, the Key portion of which can be referenced by a user-specified name, which helps standardize the way configurations are modified across projects. Webpack-chain has been used in VUE-CLI3 and some open source builders, so this article will help you get familiar with the preparation and use of Webpack-chain from the beginning to the proficient.

Second, grammar introduction

1. Webpack instance creation

You can install the Webpack-chain package in NPM or YARN mode, as shown below

npm i --save-dev webpack-chain
or
yarn add --dev webpack-chain
Copy the code

Once you have webpack-chain installed, you can start creating an instance of Webpack, as shown below

// Imports the Webpack-chain module, which exports a single constructor for creating a WebPack configuration API.
const Config = require('webpack-chain');

// Create a new configuration instance for the single constructor
const config = new Config();

/ /... There are a number of WebPack configurations that we will cover in subsequent chapters and omit here

// Export the modified configuration object to be used by WebPack
module.exports = config.toConfig();
Copy the code

2, ChainedMap

One of the core APIS in Webpack-chain is ChainedMap. A ChainedMap operates like a JavaScript Map, providing some convenience for chained and generated configurations. If a property is marked as a ChainedMap, it will have the following APIS and methods: Unless otherwise noted, these methods return a ChainedMap, allowing the methods to be invoked chained.

// 1. Remove all configurations from Map
clear()

// 2. Remove a single configuration from the Map by key
delete(key)

// 3. Obtain the corresponding key value in Map
// Note: the return value is the corresponding value of the key
get(key)

// get the Map key value
// If the key does not exist in the Map, the value of the key in the ChainedMap will be configured as the return value of the FN.
// Note: the return value is the corresponding value of the key, or the value returned by fn
getOrCompute(key, fn)

// 5. Set the values of the existing keys in the Map
set(key, value)

// If there is a specific key configured in Map,
// Note: Return Boolean
has(key)

// return an array of all values stored in the Map
// Note: An Array is returned
values()

// return an object configured in the Map, where the key is the object attribute and the value is the corresponding key value.
entries()

// 9. Provide an object whose properties and values will be mapped into the Map
merge(obj, omit)

// execute the handler function for the current configuration context
batch(handler)

Condition executes a function to continue the configuration
// condition: Boolean
// whenTruthy: When the condition is true, call the function that passes in the ChainedMap instance as a single argument
// whenFalsy: When the condition is false, call the function passing in the ChainedMap instance as a single argument
when(condition, whenTruthy, whenFalsy)

Copy the code

3, ChainedSet

The other core API in Webpack-chain is a ChainedSet, which operates like a JavaScript Set and provides some convenience for chained and generated configurations. If a property is marked with a ChainedSet, it will have the following API and methods: unless otherwise specified, the methods will return a ChainedSet, allowing the methods to be called chained.

// 1, add/append a value to the end of Set
add(value)

// 2, add a value to the start of Set
prepend(value)

// 3, remove all values from Set
clear()

// remove a specified value from Set
delete(value)

// check if there is a value in Set
// Note: Return Boolean
has(value)

// 6, return an array of values in Set.
// Note: An Array is returned
values()

// connect the given array to the end of the Set.
merge(arr)

// Execute the handler function for the current configuration context
batch(handler)

Condition executes a function to continue the configuration
// whenTruthy: When the condition is true, call the function that passes in the ChainedSet instance as a single argument
// whenFalsy: When the condition is false, call the function that passes in the ChainedSet instance as a single argument
when(condition, whenTruthy, whenFalsy)
Copy the code

4. Method shorthand

In addition to the ChainedMap and ChainedSet syntax mentioned above, webpack-chain provides a number of shorthand methods, which are not listed here. You can refer to the webpack-chain Github documentation. For example, devServer.hot is a shorthand method written as follows

// devServer is abbreviated as follows
devServer.hot(true);

// The above method is equivalent to
devServer.set('hot'.true);
Copy the code

Like ChainedMap and ChainedSet syntaxes, abbreviations support chained syntax because they return the original instance unless otherwise specified.

5. Merge configurations

Webpack-chain supports merging objects into configuration instances, but note that this is not a WebPack configuration object, and if we need to merge webpack-chain objects, we need to transform them before merging them.

/ / merge
config.merge({ devtool: 'source-map' });
/ / to get "the source - the map"
config.get('devtool')
Copy the code

6. Check the generated configuration

We can use the syntax config.toString() method to convert the Webpack object into a string that contains naming rules, usage, and plug-in comment tips, as shown below

config
  .module
    .rule('compile')
      .test(/\.js$/)
      .use('babel')
        .loader('babel-loader');

config.toString();

// The converted output
{
  module: {
    rules: [
      /* config.module.rule('compile') */
      {
        test: /\.js$/,
        use: [
          /* config.module.rule('compile').use('babel') */
          {
            loader: 'babel-loader'}]}}Copy the code

Three, common examples

1. Configure entry entry

// Configure the compile entry file
config.entry('main').add('./src/main.js') 

// Equivalent to the following WebPack configuration
entry: {
  main: [
    './src/main.js']}Copy the code

2. Output export configuration

// Configure the export file
config.output
  .path(path.resolve(__dirname, './dist'))
  .filename('[name].[chunkhash].js')
  .chunkFilename('chunks/[name].[chunkhash].js')
  .libraryTarget('umd');

// Equivalent to the following WebPack configuration
output: {
  path: path.resolve(__dirname, './dist'),
  filename: '[name].[chunkhash].js'.chunkFilename: 'chunks/[name].[chunkhash].js'.libraryTarget: 'umd'
},
Copy the code

3. Alias Alias configuration

// Configure the directory alias
config.resolve.alias
  .set(The '@', path.resolve(__dirname, 'src'))
  .set('assets', path.resolve(__dirname, 'src/assets'))

// Equivalent to the following WebPack configuration
resolve: {
  alias: {
    The '@': path.resolve(__dirname, 'src'),
     assets: path.resolve(__dirname, 'src/assets'}})),Copy the code

4. Loader configuration is added

// Configure a new loader
config.module
.rule('babel')
.test(/\.(js|jsx|mjs|ts|tsx)$/)
.include
  .add(path.resolve(__dirname,  'src'))
  .end()
.use('babel-loader')
  .loader('babel-loader')
  .options({
    'presets': ['@babel/preset-env']})// Equivalent to the following WebPack configuration
module: {
  rules: [{test: /\.(js|jsx|mjs|ts|tsx)$/,
      include: [
        path.resolve(__dirname,  'src')].use: [{loader: 'babel-loader'.options: {
              presets: [
                '@babel/preset-env']}}]}Copy the code

5. Modify loader configuration

Different from the new loader, tap method is used. The callback parameter of this method is Options, which is the configuration option object of the loader. Therefore, we can change the options object to change the loader configuration.

config.module
.rule('babel')
.use('babel-loader')
  .tap(options= > {
    // Modify its options...
    options.include = path.resolve(__dirname,  'test')
    return options
  })
Copy the code

6. Remove the Loader configuration

config.module.rules.clear(); // Delete all loaders added.

config.module.rule('babel').uses.clear(); Delete rule added with useCopy the code

7. Plugin configuration is added

// Configure a new plugin
config.plugin('HtmlWebpackPlugin').use(HtmlWebpackPlugin, [
  {
    template: path.resolve(__dirname, './src/index.html'),
    minify: {
      collapseWhitespace: true.minifyJS: true.minifyCSS: true.removeComments: true.removeEmptyAttributes: true.removeRedundantAttributes: true.useShortDoctype: true}}]);// Equivalent to the following WebPack configuration
  plugins: [
    new HtmlWebpackPlugin(
      {
        template: path.resolve(__dirname, './src/index.html'),
        minify: {
          collapseWhitespace: true.minifyJS: true.minifyCSS: true.removeComments: true.removeEmptyAttributes: true.removeRedundantAttributes: true.useShortDoctype: true}})].Copy the code

8. Plugin configuration modification

Different from the new loader/plugin, the tap method is used, and the previously configured options are retained, and the changed options are overwritten.

// Modify the plugin HtmlWebpackPlugin
config.plugin('HtmlWebpackPlugin').tap((args) = > [
  {
    ...(args[0) | | {}),template: path.resolve(__dirname, './main.html'),}]);Copy the code

9. Use the when condition

// 1. Example: Add minify plugin only during production
config
  .when(process.env.NODE_ENV === 'production'.config= > {
    config
      .plugin('minify')
      .use(BabiliWebpackPlugin);
  });

// 2. Example: DevTool to source mapping is set only when miniaturing is added during production
config
  .when(process.env.NODE_ENV === 'production'.config= > config.plugin('minify').use(BabiliWebpackPlugin),
    config= > config.devtool('source-map'));Copy the code

10. Remove the plugin configuration

config.plugins.delete('HtmlWebpackPlugin');
Copy the code

Four,

In this article, we will introduce webpack-chain syntax to manual writing webpack common configuration and operation, help you familiar with the use of Webpack-chain, I hope it will be helpful to you.

Hard to sort out for a long time, but also hope to manually praise encouragement ~ blog github address: github.com/fengshi123/… , a summary of all the author’s blog, welcome to follow and star ~