[front end Engineering] V: webpack5 quick start

Posted by freshrod on Sun, 20 Feb 2022 12:03:27 +0100

webpack-dev-server

To realize the automatic compilation and display of files modified during development, you can use the live server plug-in with webpack's watch attribute of true and vscode, that is, observation mode

// webpack.config.js
module.exports = {
    watch: true,
    ...
}

However, this has several disadvantages:

  • All source code is recompiled
  • Because we use the clean webpack plugin plug-in, we need to read and write the file after each successful compilation
  • live server is a vscode plug-in. We should use Webpack plug-in
  • live server cannot achieve local refresh

For the above reasons, we use webpack dev server, which writes all data in memory;

npm install webpack-dev-server -D

Note that the commands configured here are different from the yarn webpack dev server of webpack 4

// package.json
"scripts": {
	"serve": "webpack serve --config lg.webpack.js"
}

webpack-dev-middleware

Webpack dev middleware is a wrapper that can send files processed by webpack to a server. Webpack dev server uses it internally, but it can also be used as a separate package for more customization as needed. The following is an example of webpack dev middleware cooperating with express server.

const express = require('express')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpack = require('webpack')

const app = express()

// Get profile
const config = require('./webpack.config.js')
const compiler = webpack(config)

app.use(webpackDevMiddleware(compiler))

// Turn on the service on the port
app.listen(3000, () => {
  console.log('The service runs on port 3000')
})

HMR function usage

hot module replacement (HMR) is one of the most useful functions provided by webpack. It allows all types of modules to be updated at run time without a full refresh.

Note: because we configure the Mode as development in the development phase, it is different from our configuration The compatibility of the browserlistrc file is in conflict. The official suggests that we use taget: 'web' to solve it;

Configuring the hotOnly property will not refresh the browser whether it is updated or not.

// webpack.config.js
module.exports = {
  target: 'web',
  devServer: {
    hot: true,
    // hotOnly: true
  }
  ...
}

The hot update of the module needs to be manually configured in the file, as follows:

import './title'

if (module.hot) {
  module.hot.accept(['./title.js'], () => {
    console.log('title.js Module update')
  })
}

Title When an update occurs in JS, the console. Exe will be triggered Log ('title.js module update ') and has the effect of hot update;

React component supports hot update

In react, we need to compile jsx syntax

npm install @babel/preset-react -D

For the hot update of react component, we are officially required to download two plug-ins

npm install @pmmmwh/react-refresh-webpack-plugin react-refresh -D

// babel.config.js
module.exports = {
  presets: [
    ['@babel/preset-env'],
    ['@babel/preset-react'],
  ],
  plugins: [
    ['react-refresh/babel']
  ]
}
// webpack.config.js
...
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')

module.exports = {
  ...,
  target: 'web',
  devServer: {
    hot: true
  },
  module: {
    rules: [
      ...,
      {
        test: /\.jsx?$/,
        use: ['babel-loader']
      }
    ]
  },
  plugins: [
    ...,
    new ReactRefreshWebpackPlugin()
  ]
}

Question? The value in input was lost during hot update of React component

Vue components support hot updates

npm install vue-template-compiler vue-loader vue -D

vue2. Version 0 + Vue loader 15 consists of three steps: configure Vue loader, configure Vue loader plug-in, and install Vue template compiler plug-in;

compile. vue syntax. vue loader and vueLoaderPlugin plug-ins need to be configured

To solve the problem of Cannot read property 'parseComponent' of undefined error, you need to install Vue template compiler

reference material: https://vue-loader.vuejs.org/zh/guide/#vue-cli

...
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  ...,
  target: 'web',
  devServer: {
    hot: true
  },
  module: {
    rules: [
      ...,
      {
        test: /\.vue$/,
        use: ['vue-loader']
      }
    ]
  },
  plugins: [
    ...,
    new VueLoaderPlugin()
  ]
}

// "vue-template-compiler": "^2.6.14",

path in output

publicPath is to inform index Where will HTML go to find the resources you want to load in the future

localhost:8080 + '/' + 'js/main.js'

Local server + publicPath + filename

If publicPath is not configured, the browser will automatically spell '/', so it can be manually configured as' / ', but at this time, the packaged file after npm run build cannot be opened locally; In order to open the package file locally, you can configure '. /' for publicPath, However, npm run serve cannot run at this time, because it will start looking for JS / main from the current directory JS file cannot be found;

path in devserver

When devserver runs, the files will be packaged in a virtual directory, and the public path of output is configured with index HTML to find the path after packaging (at this time, the resources not packaged by webpack cannot be found in the virtual directory, and the contentBase needs to be configured). The publicPath in devserver configures the directory where devserver will find, and the contentBase in devserver configures index Resource paths that are not packaged by webpack but are introduced in HTML;

publicPath: tells devServer which directory to look for, that is, the packaged files will be placed in a virtual '/ lg' (publicPath) directory;

The default value is' / '. It is strongly recommended that the publicPath in output and the publicPath of devServer be set to the same value; After configuration, you should access http://localhost:8080/lg ;

**contentBase: * * if our packaged resources depend on other resources, we will tell them where to find them (for example, if we introduce files not processed by webpack into index.html file, we will tell index.html where to find these dependent resources, generally using absolute path);

**watchContentBase: * * used in combination with contentBase. The default value is false. When we modify the resources that the packaged resources depend on, the page will change with it. The default is that the modified resource page will not be updated in time;

output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/lg'
},
target: 'web',
devServer: {
    hot: true,
    publicPath: '/lg',
    // contentBase: path.resolve(__dirname, 'public'),
    // watchContentBase: true,
    open: true
},

here http://localhost:8080 No access, but access http://localhost:8080/lg You can access the page, http://localhost:8080/lg/js/main.js You can find the packaged resources;

devServer common configuration

hotOnly: do not refresh anyway;

**compress: * * enable g-zip compression;

**historyApiFallback: * * when using browserRoute mode, refreshing may cause page 404;

Proxy proxy settings

When starting the local server, cross domain problems will occur in the access interface;

**pathRewrite: * * rewrite the path;

**changeOrigin: * * modify the host name;

devServer: {
    hot: true,
    hotOnly: true,
    port: 4000,
    open: false,
    compress: true,
    historyApiFallback: true,
    proxy: {
        // /api/users
        // http://localhost:4000/api/users
        // https://api.github.com/info/users
        // /API / users --- > Return
        '/api': {
            target: 'https://api.github.com',
            pathRewrite: { "^/api": "" },
            changeOrigin: true
        }
    }
},

resolve module parsing rules

File lookup has three mechanisms by default

  • Relative path
  • node_modules
  • Absolute path

extensions: file extension name. When we don't write the file suffix, we will look here;

Alias: path alias setting;

resolve: {
    extensions: [".js", ".json", '.ts', '.jsx', '.vue'], 
    alias: {
        '@': path.resolve(__dirname, 'src')
    }
},

Source map function

When the mode is development, the default devtool is eval

The mode is: [inline - | hidden - | eval -] [nosources -] [heap - [module -]] source map

Source map in vue

In react, it is a heap module source map

Compiling ts with TS loader

npm install typescript ts-loader -D

At this time, both TS loader and Babel loader can be used, but TS loader cannot plyfill;

Babel loader can't verify the data type, and if the syntax is wrong, it will be packaged successfully. However, when we use TS loader, it will be verified during packaging, so that we can find the problem earlier;

Official suggestion: just convert the syntax and use TS loader, but if we need to use polyfill, we can use Babel loader;

Using Babel loader, you can do a verification first in package Add ts syntax verification in JSON. tsc --noEmit can only verify, not package into js files; This will help us check the ts syntax before executing num run build. If there is an error, it will not be packaged;

// package.json
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "npm run ck && webpack",
    "serve": "webpack serve",
    "ck": "tsc --noEmit"
},
module: {
    rules: [
        {
            test: /\.jsx?$/,
            use: ['babel-loader']
        },
        {
            test: /\.ts$/,
            use: ['babel-loader']
        }
    ]
},
// babel.config.js is configured with polyfill and ts parsing
module.exports = {
    presets: [
        ['@babel/preset-env', {
            useBuiltIns: 'usage',
            corejs: 3
        }],
        ['@babel/preset-typescript']
    ]
}

Load vue file

Refer to Vue component support hot update section;

vue2. Version 0 + Vue loader 15 consists of three steps: configure Vue loader, configure Vue loader plug-in, and install Vue template compiler plug-in;

Topics: Javascript Front-end Webpack