preface

Create-react-app is a great scaffolding tool, but as a front-end developer, you can’t build your own scaffolding tools. So, I began to learn the road to Webpack.

First, get a general idea of the WebPack workflow

Packaging is the ability to package a file into another file. Webpack treats the packaging process as input and output, including entries, modules, chunks, chunk combinations, and many other parts. Starting at the entry point, WebPack creates a dependency diagram that contains all the modules needed in the application and then bundles them.

With that in mind, we started building the scaffolding tool.

  1. Start with the basic configuration, setting up the entrance and exit.

NPM install webpack webpack-cli webpack-dev-server. I’m using the webpack4 version here. Guys, please adjust as needed.

const path = require('path')
module.exports = {
    entry: 'src/index.js'./ / the entry
    output: {
        path: path.resolve(__dirname, 'dist'), // Output directory
        publicPath: '/dist/'.// The directory to load the resource
        filename: 'bundle.js' // Output the file name}}Copy the code

Our directory structure is:

--public
----index.html
----logo.jpeg
--src
-----index.js
-----App.jsx
-----App.css
--webpack.config.js
--.babelrc
Copy the code
  1. Configure WebPack to package CSS, JPEG, and JSX files.

Webpack only packs JS files by default. We need different loaders to enhance its packaging capability. Use stley-loader(automatically generating style labels) and CSS-loader to package CSS files. Use url-loader and file-loader to package image resource files. In order to use es6 syntax, use babel-loader to package JS and JSX files. The Webpack configuration is as follows:

module.exports = { ... .module: {
    rules: [{test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      },
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'] {},test: /\.(png|jpeg|gif)$/i,
        use: [
          {
            loader: 'url-loader'.options: {
              limit: 8192}}]}]},resolve: {
      extensions: [The '*'.'.js'.'.jsx'] // Set file names to be resolved in order}}Copy the code

The meaning of configuring the resolve.extensions attribute is:

When import * from 'SRC /App' is used, the file is matched by the unsuffixed name first, then app.js, or app.jsx if not found.Copy the code

Babel is configured as follows:

{
  "presets": ["@babel/env"."@babel/preset-react"]."plugins": [
    "@babel/plugin-proposal-optional-chaining"]}Copy the code
  1. Automatically generate HTML files

The bundle.js file is generated after each packaging. If you change the packaging path, you need to manually change the SRC attribute of the script tag in the HTML file. For convenience, the html-webpack-plugin automatically generates the HTML file. npm install html-webpack-plugin –save-dev

.const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    ...
    plugins: [
        new HtmlWebpackPlugin({
            title: 'webpack for react'.// Set the title variable, which can be read in index.html
            template: 'public/index.html' // Template file}})]Copy the code

The HTML-webpack-plugin also has many useful configurations, such as setting variables. Set the title variables here, in the HTML file you can use the < % = htmlWebpackPlugin. Options. The title % > to read the value of this variable.

  1. Clean up the package files using the clean-webpack-plugin.

If you don’t clean up the package files, there will be a lot of extra files in the folder dist directory after each package build. No more instructions on how to install plug-ins.

.const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
    / /...
    plugins: [
        / /...
        new CleanWebpackPlugin()
    ]
}
Copy the code
  1. Set webpack-dev-server to start the local service

Most of the development time is spent debugging locally, and webpack-dev-server provides a way to start the service locally.

/ /...
devServer: {
    contentBase: path.join(__dirname, 'dist'), // Set the proxy directory
    port: 3000.publicPath: 'http://localhost:3000/dist/'.// Set the url of the package file. You can write /dist/ directly
    hotOnly: true./ / hot update
    compress: true./ / compression
    open: true.// Automatically open the browser
    writeToDisk: true.// webpack-dev-server saves files in memory by default
    proxy: { // Set the proxy
      api: 'http://localhost:3000'
      /* 'api': { target: 'http://localhost:3000', pathRewrite: { '^/api': '' } } */
    }
    // host: '127.0.0.1' // Change the host of dev server
  },
Copy the code
  1. Set the index. HTML file to be retained every time webpack-dev-server is repackaged

The clean-webpack-plugin does not generate the index.html file every time the webpack-dev-server is repackaged. The clean-webpack-plugin removes the original HTML file. The index.html file is not deleted each time it is cleaned after packaging.

module.exports = {
 // ...
 plugins: [
   new CleanWebpackPlugin({
      /* The index. HTML file remains */ after each webpack-dev-server package
      cleanStaleWebpackAssets: false}})]Copy the code
  1. Extract the CSS file

CSS -loader will package CSS into JS, and style-loader will generate the style label. Now I use the mini-CSs-extract-plugin to extract CSS into a separate file. There are two steps:

  1. Replace loader
  2. Increase the plugin
module.exports = {
 // ...
 module: {
     rules: {{test: /\.css$/./ / will style - loader is replaced by MiniCssExtractPlugin. Loader
        use: [MiniCssExtractPlugin.loader, 'css-loader']}// ...}},plugins: [
   new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: 'css/[name].css'.chunkFilename: 'css/[id].css'}})]Copy the code
  1. Configuring hot Update

The HMR-Hot Module replacement function replaces, adds, or removes modules while the application is running without reloading the entire page. However, module hot updates should never be used in a production environment. Therefore, check whether it is a production environment. If so, enable it. Otherwise, it is disabled.

// Set the operating environment
const mode = process.env.NODE_ENV
const plugins = []
if(mode ! = ='production') {
  // Set the hot update plugin to be enabled only in development mode. HMR should never be used in production
  const hotModuleReplacementPlugin = new webpack.HotModuleReplacementPlugin()
  plugins.push(hotModuleReplacementPlugin)
}
module.exports = {
    plugins: [
        ..plugins,
        // ...]}Copy the code
  1. Enable sourceMap

In general, production and development environments have different considerations, so the requirements for sourceMap are different. The sourceMap I configured here for the development environment is mainly for accuracy. The sourceMap is not configured for the production environment.

/ /...
module.exports = {
    // ...
    devtool: mode === 'development' ? 'eval-source-map' : 'none'
}
Copy the code
  1. Process hot update auxiliary files

Each hot update generates auxiliary files with suffixes.hot-update.js and.hot-update.json. As the number of hot updates increases, so do the auxiliary files. We configure and keep only the latest auxiliary files.

module.exports = {
    output: {
        // ...
        / * avoid HotModuleReplacementPlugin every time describing the json and patch file generated js * /
    hotUpdateChunkFilename: 'hot/hot-update.js'.hotUpdateMainFilename: 'hot/hot-update.json'}}Copy the code

At this point, the simple scaffolding is completed, of course, there are many missing, such as the processing of the font, the extraction of the same module and so on, but the skeleton is out, you can follow this simple learning. Git address

Your comments are welcome.