Use webpack to build projects

Posted by acey99 on Wed, 09 Feb 2022 03:41:34 +0100

 
1. You can see on the official website of webpack that webpack is a File packaging tool, which packages complex File Dependencies into independent resource files. let me put it another way, In webpack, all files are modules. Load files through loader, inject hooks through plugin, and finally output files combined by multiple modules. So what is loader? Loader is used to read various resources, such as css, js, etc. Module loaders can be called in a chain. Each loader in the chain summary will convert resources, and then pass the results to the next loader.
 
That is to say, webpack uses loader to manage all kinds of resources.
 
2. Use webpack to manage resources config. js
 
const path = require('path');


module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(csv|tsv)$/i,
        use: ['csv-loader'],
      },
      {
        test: /\.xml$/i,
        use: ['xml-loader'],
      },
    ],
  },
};

 

 
It should be noted that the order of loader s should be ensured: 'style loader 'comes first and' CSS loader 'comes last. If this Convention is not followed, webpack may throw an error
 
According to the above configuration, the corresponding file will be processed as a module when webpack is executed, and you can import the corresponding resources for use.
 
 
2, When installing a package to be packaged into the production environment bundle, you should use npm install --save. If you are installing a package for the development environment (for example, linker, test library, etc.), you should use npm install --save dev
 
3. What we know is that webpack generates bundles JS file, then, when an error occurs in a source file, we cannot locate which source file is wrong during development. At this time, we use it under the development environment source map to locate the problem. The configuration is as follows
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  mode: 'development',//Environment: development \ production \ none; Corresponding to development environment, production environment and indifference
  devtool: 'inline-source-map',
  entry: {//Entry can have multiple entry files
    index: './src/index.js',
    print: './src/print.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,//The output folder is cleaned up before each new build
  },
 
  module: {
    
  },
};

 

 
4. When we use vue to build a project, does vue automatically help us recompile, build and refresh the browser every time we modify a file? This is because vue has a built-in configuration of webpack. What if we don't use vue to develop projects and want to automatically compile and refresh? Here, we can use webpack dev server to configure and build to meet this requirement.
 
First, we install the plug-in
npm install --save-dev webpack-dev-server

 

 
Then add the following code to the configuration file
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  mode: 'development',//Environment: development \ production \ none; Corresponding to development environment, production environment and indifference
  devtool: 'inline-source-map',
  entry: {//Entry can have multiple entry files
    index: './src/index.js',
    print: './src/print.js',
  },
  plugins: [
     new HtmlWebpackPlugin({
       title: 'Development',
     }),
   ],
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,//The output folder is cleaned up before each new build
  },
  devServer: {
    contentBase: './dist',
    hot:true
  },
  module: {
    
  },
};

stay package.json Add the following srcipt
{
  "name": "wepack-demo",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "start": "webpack serve --open"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "css-loader": "^5.2.4",
    "html-webpack-plugin": "^5.3.1",
    "style-loader": "^2.0.0",
    "webpack": "^5.4.0",
    "webpack-cli": "^4.2.0",
    "webpack-dev-server": "^3.11.2"
  },
  "dependencies": {
    "loadash": "^1.0.0",
    "lodash": "^4.17.21"
  }
}

 

 
 
 
 
Execute npm run start to see that the browser is automatically compiled and opened. At this time, modifying any file will refresh the file again
 
This is because the configuration tells the webpack dev server plug-in that the files under the dist directory can be accessed through the address localhost:8080, and the webpack dev server will not be written to any output file after compilation. Instead, keep the bundle files in memory and treat them as accessible files.
 
 
5. From the above example, we can know that webpack can package all your js files into a bundle file, but in some cases, we don't want to import all the files at one time, and some plug-ins can be imported when needed. At this time, what we think of is to separate the bundle file into different bundles, and then load it as needed. At this time, we need to use the code separation feature of webpack.
 
Write multiple interfaces in the entry, and then use the split chunksplugin plug-in to prevent repeated loading of common modules
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  mode: 'development',//Environment: development \ production \ none; Corresponding to development environment, production environment and indifference
  devtool: 'inline-source-map',
  entry: {//Entry can have multiple entry files
    index: './src/index.js',
    print: './src/print.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,//The output folder is cleaned up before each new build
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
  plugins: [
    new HtmlWebpackPlugin({//html files used to manage new builds
      title: 'Management output',
    }),
  ],

  devServer: {
    contentBase: './dist',
  },
};

 

Then execute npm run build
You can see that the loadash file is built only once
 
 
6. When the browser accesses the resources of the website, it uses caching technology to speed up the loading of resources. But there will be another problem. It's like we have changed a lot of things in the project, but our file name has not changed. At this time, the browser will think that the file has not changed and use the cached version. Therefore, we can use the substitution method of webpack to output the name of the file. This method will create a unique hash according to the content of the resource, and then add this part of the hash to the back of the file. Moreover, this method is super simple. We only need to modify the following code in the configuration file of webpack:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  mode: 'development',//Environment: development \ production \ none; Corresponding to development environment, production environment and indifference
  devtool: 'inline-source-map',
  entry: {//Entry can have multiple entry files
    index: './src/index.js',
    print: './src/print.js',
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,//The output folder is cleaned up before each new build
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
  plugins: [
    new HtmlWebpackPlugin({//html files used to manage new builds
      title: 'Management output',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(csv|tsv)$/i,
        use: ['csv-loader'],
      },
      {
        test: /\.xml$/i,
        use: ['xml-loader'],
      },
    ],
  },
  devServer: {
    contentBase: './dist',
  },
};

 

 
Now let's build again without changing the contents of the file
 
You can see that cache is used at this time, and the file has not changed
 
In addition, we hope that some bundle s that reference external plug-ins will not change during construction, so that when the project changes every time, we will not build these external plug-ins that do not change frequently.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  mode: 'development',//Environment: development \ production \ none; Corresponding to development environment, production environment and indifference
  devtool: 'inline-source-map',
  entry: {//Entry can have multiple entry files
    index: './src/index.js',
    print: './src/print.js',
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,//The output folder is cleaned up before each new build
  },
  optimization: {
    runtimeChunk: 'single',
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
  },
  plugins: [
    new HtmlWebpackPlugin({//html files used to manage new builds
      title: 'Management output',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(csv|tsv)$/i,
        use: ['csv-loader'],
      },
      {
        test: /\.xml$/i,
        use: ['xml-loader'],
      },
    ],
  },
  devServer: {
    contentBase: './dist',
  },
};

 

 
At this time, we can see that the built vendor and runtime modules are independent, and the volume of other self written code modules becomes smaller. When browsing such resources for the second time, it greatly improves the loading speed! Cow glass~
 
 
 
6. Suppose we write a plug-in and want to publish it to npm. How can we use webpack to package and build this plug-in?
Other parts are the same as above. In addition, the introduction method should be stated:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: {
    index: './src/index.js',
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,//The output folder is cleaned up before each new build
    library: {
      name: 'webpackNumbers',
      type: 'umd',
    },
  },
};

 

 
 
 
7. webpack 4 began to introduce tree shaking, which is mainly used to eliminate useless code in the project. In this way, the volume of the project will be greatly increased. You may ask, will there be useless code in the project? It's not useful to write!
That's not true. In the process of project development, the requirements will change constantly. The components introduced in a page may be useful in this stage, but in the next stage, this function may be abandoned. The longer the maintenance time, the more code may be discarded.
In this way, tree shaking greatly compresses the packed volume. Maybe you will ask, how does this thing identify the code internally? Is it useful? Tree shaking depends on the characteristics of the module, that is, import and export.. Webpack tracks the import/export statements of the entire application, so if it sees that the imported thing is not used in the end, it will think it is "dead code" and tree shaking it
 
So what kind of code is considered unused? Let's start with an example
import _ form  'lodash';//For such import, webpack will think that you have used the whole lodash library, so you won't touch the code of the whole library, so it's not recommended to introduce the whole library.

import {join} from 'lodash';//In this way, if the subsequent code does not use the method of named introduction, it will be regarded as abandoned code, and then tree shaking

 

 
Next, we turn on tree shaking in the configuration of webpack
It should be noted that it is specified in the official website of webpack that tree shaking can only be started under the production mode. This is understandable because tree shaking can only be started when compressing and packaging code, so it can only be started under the production mode. Therefore, remember to change the mode to production when packaging finally
const path = require('path');


module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
 mode: 'development',
 optimization: {
   usedExports: true,//Webpack will identify the code that it believes is not being used and mark it in the initial packaging step
 },
};

 

 
 
Next, let's understand a concept: sideEffects, side effects
In the above configuration, we have asked webpack to filter the unused code, but the fact that some code is not used does not mean that it is an obsolete code. For example, we introduce styles, use global style sheets, or a configuration file that introduces global configuration. In this way, files that are not used but still work are introduced. webpack believes that such files have“ sideEffects ”, such files should not be tree shaking. In order to avoid files with side effects in the whole project, webpack regards all files as having side effects by default, so the whole project cannot be tree shaking, so let's configure sideEffects first and tell webpack that you can do tree shaking.
In package Configuration in JSON
// All files have side effects and cannot be tree shaken
 { 
    "sideEffects": true
 } 

// No files have side effects. All can be tree shaking
{ 
    "sideEffects": false 
} 


// Only these files have side effects. All other files can be tree shaking, but these files will be retained

{ 
    "sideEffects": [ 
        "./src/file1.js", 
        "./src/file2.js" 
    ] 
}

 

 
In addition, sideEffects can be configured in the loader
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  mode: 'development',//Environment: development \ production \ none; Corresponding to development environment, production environment and indifference
  devtool: 'inline-source-map',
  entry: {//Entry can have multiple entry files
    index: './src/index.js',
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    publicPath:'/',//Specify the directory of the resource
    clean: true,//The output folder is cleaned up before each new build
  },
  optimization: {
    runtimeChunk: 'single',
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
  },
  plugins: [
    new HtmlWebpackPlugin({//html files used to manage new builds
      title: 'Management output',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
        sideEffects:true,
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(csv|tsv)$/i,
        use: ['csv-loader'],
      },
      {
        test: /\.xml$/i,
        use: ['xml-loader'],
      },
    ],
  },
  devServer: {
    contentBase: './dist',
    hot: true,
  },
};


 

When the run NP code is executed, it is deleted. Let's take a look at the comparison of the previous and subsequent codes
 
This is the packaged code that I haven't used since I introduced lodash (before configuration)
 
You can clearly see that the final packaging is introduced by lodash. Next, we will package according to the above configuration
Remember! This step is very important. Change the mode to production and delete optimization
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  mode: 'production',//Environment: development \ production \ none; Corresponding to development environment, production environment and indifference
  devtool: 'inline-source-map',
  entry: {//Entry can have multiple entry files
    index: './src/index.js',
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    publicPath:'/',//Specify the directory of the resource
    clean: true,//The output folder is cleaned up before each new build
  },
  optimization: {
    runtimeChunk: 'single',
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
  },
  plugins: [
    new HtmlWebpackPlugin({//html files used to manage new builds
      title: 'Management output',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
        sideEffects:true,
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(csv|tsv)$/i,
        use: ['csv-loader'],
      },
      {
        test: /\.xml$/i,
        use: ['xml-loader'],
      },
    ],
  },
  devServer: {
    contentBase: './dist',
    hot: true,
  },
};

 

 
Execute npm run build to see
You can see that those useless codes are deleted at this time!
 
OK, after configuration, let's summarize
  • You need to use the module syntax (import, export)
  • It is not converted into commonjs by babel (Webpack does not support using commonjs module to complete tree shaking.)
  • package. Configuring sideEffects in JSON
  • Set mode to production and then package

 

Topics: Front-end IDE