preface

In daily development, we usually choose scaffolding vue-CLI, create-React-app, etc. However, it is a basic skill to understand and master Webpack to complete project engineering development

This paper is based on:

Webpack: 4.41.2 node: 10.15.1 YARN: 1.16.0

Webpack basic configuration

1.1 Initializing the React Project

  • In the new directory

yarn init

  • Install act-related packages

yarn add react react-dom axios

  • Install Babel

    We use ES6+ syntax a lot in development, but not all browsers have the ability to convert ES6+ syntax into javascript, so that’s why we use Babel, which converts ES6+ syntax into compatible JS syntax
    • The installationbabelCore package and command line tools

      yarn add @babel/core

      yarn add @babel/cli
    • The installationbabelPlugin for preset configuration and syntax

      yarn add @babel/preset-envES6 syntax is supported

      yarn add @babel/preset-reactReact syntax support

      yarn add @babel/plugin-proposal-class-propertiesSupport for class attributes
    • The editor.babelrcMake the installed plug-ins and configurations take effect
      {
          "presets": [
              [
                  "@babel/preset-env",
                  {
                      "useBuiltIns": "entry",
                      "corejs": 3
                  }
              ],
              "@babel/preset-react"
          ],
          "plugins": [
              "@babel/plugin-proposal-class-properties"
          ]
      }
      Copy the code
    • The installationbabel-polyfill
      • By default, Babel only converts syntax, but not objects. Since the original browser did not have the syntax for objects such as Promise and Symbol, we had to adjust the configuration of Babel when we needed to use it
      • We can usebabel-polyfillTo solve this problem. The principle is that it implements all object and instance methods of ES6+, but the disadvantage is that it contaminates the global space and built-in objects, and may cause object conflicts with the same name

      yarn add @babel/polyfill

1.2 use webpack

  • The installationyarn add webpack webpack-cli
  • newsrc/index.jsAs a global entry
    import "@babel/polyfill"  // At the beginning
    import React from 'react'
    import ReactDOM from 'react-dom'
    import axios from 'axios'
    Copy the code
  • createwebpack.config.js
    const path = require('path');
    
    module.exports = {
        entry: './src/index.js'.// Import file
        output: {  // Export file (compiled)
            filename: 'bundle.js'.path: path.resolve(__dirname, 'dist')},// babel-loader will process files according to.babelrc
        module: {
            rules: [{test: /\.js$/, use: 'babel-loader'}}};Copy the code
  • yarn add babel-loader

1.3 integrated webapck – dev – server

  • yarn add webapck-dev-serverQuickly set up the local operating environment
  • yarn add html-webpack-pluginGenerate HTML in memory
  • Modify thepackage.json
    "scripts": {
        "dev": "webpack-dev-server --open --port 8081 --contentBase src --hot"."build": "webpack --mode production"."test": "echo \"Error: no test specified\" && exit 1"
     },
    Copy the code
  • Modify thewebpack.config.js
    const path = require('path');
    const htmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
        entry: path.join(__dirname, './src/index.js'),
        output: {
            filename: 'bundle.js'.path: path.resolve(__dirname, 'dist')},plugins: [
            new htmlWebpackPlugin({
                template: path.join(__dirname, './index.html'),
                filename: 'index.html'})].module: {
            rules: [{test: /\.js$/, use: 'babel-loader'}},mode: 'development' 
    };
    Copy the code
  • After integrating webpack-dev-server and http-webpack-plugin, accessing localhost:8081(HTML page in memory) will cause an error when importing CSS, images, less, fonts, etc files in HTML, which needs to be handled in a separate way
    • yarn add less less-loader css-loader style-loader file-loader
    • Modify thewebpack.config.js
      rules: [
         {test: /\.js$/, use: 'babel-loader'}, 
         {test: /\.css$/, use: ['style-loader'.'css-loader'] {},test: /\.less$/, use: ['style-loader'.'css-loader'.'less-loader'] {},test: /\.(eot|svg|ttf|woff|woff2|png)\w*/, use: 'file-loader'}]Copy the code
    • Modified index. HTML
      <script src="bundle.js"></script>
      Copy the code

1.4 Configuring the React Route

  • yarn add react-router react-router-dom
  • In the configurationreact-routerCannot access the page by entering the address or refreshing the child route

    Cause: We configure only front-end routes through the React-Router, but WebPack does not recognize the front-end routes. If the server cannot match the path, it automatically forwards it to the 404 interface

    Address:webpack.config.jsIn the configuration:
    // Webpack returns to the home page by default if the path cannot be matched
    // This is controlled by the front-end route
    devServer: {
        historyApiFallback: true,}Copy the code

1.5 Distinguish between development environment and production environment

  • inwebpack.config.jsTo distinguish between development mode and production mode:
    const path = require('path');
    
    module.exports = function(env, argv){
        // 1. Use argv to determine whether the environment is development or production
        const isEnvDevelopment = argv.mode === 'development'| |! argv.mode;const isEnvProduction = argv.mode === 'production'; 
        
        return{
            // 2. Configure mode and devtool according to the environment
            mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development'.devtool: isEnvProduction ? 'source-map' : isEnvDevelopment && 'cheap-module-source-map'.entry: './src/index.js'.output: {
                filename: 'bundle.js'.path: path.resolve(__dirname, 'dist')},module: {
                rules: [{
                    test: /\.js$/,
                    exclude: /node_modules/,
                    use: 'babel-loader'}}}}]Copy the code

1.6 Development and Configuration

  • Source Map: maps object code to source code

    After passing through the wrapper, the browser executes object code. In development, when an error occurs, we want the error reported to be directly located in the original code, rather than display the target code, so we need to configuresource map
    const path = require('path');
    const htmlWebpackPlugin = require('html-webpack-plugin');
    const webpack = require('webpack');
    
    module.exports = function(env, argv){
        const isEnvDevelopment = argv.mode === 'development'| |! argv.mode;const isEnvProduction = argv.mode === 'production'; 
        
        return{
            mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development'.devtool: isEnvProduction ? 'source-map' : isEnvDevelopment && 'cheap-module-source-map'./ / modify
            entry: path.join(__dirname, './src/index.js'),
            output: {
                filename: 'bundle.js'.path: path.resolve(__dirname, 'dist'),},plugins: [
                new htmlWebpackPlugin({
                    template: path.join(__dirname, './public/index.html'),
                    filename: 'index.html'})].module: {
                rules: [{test: /\.js$/, use: 'babel-loader'}, 
                   {test: /\.css$/, use: ['style-loader'.'css-loader'] {},test: /\.less$/, use: ['style-loader'.'css-loader'.'less-loader'] {},test: /\.(eot|svg|ttf|woff|woff2|png)\w*/, use: 'file-loader'}},devServer: {
                historyApiFallback: true.contentBase: './dist'.hot: true}}}Copy the code
  • Eslint and Prettier
    • The purpose of Eslint is to check that code is conforming to the specification and give a hint
    • 3, Prettier usually works with ESlints, where Prettier can detect code specification but not completely, while Prettier does not detect code specification
    • yarn add eslint babel-eslint
    • yarn add eslint-config-airbnb
    • yarn add eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react
    • create.eslintrc.js
      module.exports = {
          // Parser is used to specify a parser. Eslint cannot parse ES6 syntax by itself and needs to be converted to babel-esLint
          "parser": "babel-eslint".// extends represents an Airbnb based specification
          "extends": ["airbnb"].// env tells ESLint not to use undefined if browser and ES6 objects are encountered
          "env": {  
              browser: true.es6: true,},// rules is used to specify extended specification rules that override the configuration of Airbnb rules
          "rules": {
              'react/jsx-filename-extension': [1, {extensions: ['.js']}],
              'react/prop-types': 0.'react/prefer-stateless-function': 0.'react/no-array-index-key': 0.'no-console': 0.'jsx-ally/anchor-is-valid': 0.'react/destructuring-assignment': 0.'react/jsx-one-expression-per-line': 0}}Copy the code
    • Performed manuallyeslint yarn eslint src/Check the js file under SRC /npx eslint --fix src/Autofix is not standardized and only lists those that cannot be autofixed
  • Configuring a Path Alias

    In development, we often configure path aliases to quickly locate files, improve efficiency and file import accuracy, usually with@To represent thesrcdirectory
    resolve: {
       alias: {
         The '@': path.resolve('src')}}Copy the code
  • Modular CSS
    • Simple to useStyle - loader, CSS - loaderWhile it is possible to introduce CSS style files in JS, the following problems arise:
      • Global pollution:CSSFile selectors are global, different file selectors of the same name, according tobuildThe sequence in the generated file, the later style overrides the previous style
      • The selector is complex and the naming rules are confusing
    • After the use of CSS Module Module processing, for each JS file, its introduced CSS file is only effective for this file, which is similar to VUEscopedAttributes play a role
    • Modify thewebpack.config.js
      {test: /\.css$/, use: ['style-loader'.'css-loader? modules']},
      Copy the code
    • Example:
    • Principles of the CSS Module: each className is converted (plus hash value) according to certain rules to ensure its uniqueness, but only className and id can be converted
  • CSS compatibility Processing Enables the CSS to add different prefixes for different browsers, resolving browser compatibility problems
    • yarn add postcss-loader autoprefixer
    • configurationpostcss.config.js
      module.exports = {
          plugins: {
              'autoprefixer': {}}};Copy the code
    • Modify thewebpack.config.js
      // The postCSs-loader should be placed before the less-loader, and converted from less to CSS, and then processed with postCSS
      module: {
          rules: [{test: /\.js$/, exclude: /node_modules/, enforce: "pre".use: 'babel-loader'}, 
              {test: /\.css$/, include: [path.resolve(__dirname, 'src/styles'), /node_modules/].use: ['style-loader'.'css-loader'.'postcss-loader'] {},test: /\.css$/, exclude: [path.resolve(__dirname, 'src/styles'), /node_modules/].use: ['style-loader'.'css-loader? modules'.'postcss-loader'] {},test: /\.less$/, include: [path.resolve(__dirname, 'src/styles'), /node_modules/].use: ['style-loader'.'css-loader'.'postcss-loader'.'less-loader'] {},test: /\.less$/, exclude: [path.resolve(__dirname, 'src/styles'), /node_modules/].use: ['style-loader'.'css-loader? modules'.'postcss-loader'.'less-loader'] {},test: /\.(eot|svg|ttf|woff|woff2|png)\w*/, use: 'file-loader'},     
              {
                  test: [/\.bmp$/./\.gif$/./\.jpe?g$/./\.png$/./\.svg$/].loader: 'url-loader'.options: {
                      limit: 10000}}],},Copy the code

1.7 Production Environment Configuration

  • copywebpack.config.js, rename towebpack.config.prod.js
  • The editorpackage.json
    "scripts": {
        "dev": "webpack-dev-server --port 8081 --mode development"."build": "webpack --config webpack.prod.config.js --mode production"."watch": "webpack --watch"."test": "echo \"Error: no test specified\" && exit 1"
    },
    Copy the code
  • Modify thewebpack.prod.jsdeletedevServerconfiguration

At the end

To do this, we can use the following commands: yarn Run dev development environment to start the project, on port 8081 access yarn Run Build package compile project file, generate dist directory for some optimization configuration of Webpack, such as: Code separation, file volume compression, configuration caching, and hot updates using HMR modules in development environments are not covered, or will continue to be updated