This is the 29th day of my participation in the August More Text Challenge

A, resolve

Resolve is used to modify the Module Resolution rule of Webpack. Webpack provides the default Module Resolution rule, but it can be modified further. For details on Module Resolution, please refer to the official Webpack document Module Resolution.

1.1 resolve. Alias

When you import (import/require) a module with a deeper path level, configuring alias maps a short name (alias) to the deeper path.

1.1.1 withoutalias

import 'bootstrap/dist/css/bootstrap.min.css'
Copy the code

1.1.2 configurationalias

const webpack= require('webpack'); module.exports = { mode: 'development', devtool: 'eval-source-map', entry: { home: './src/index.js', other: './src/other.js', x: './src/x.js' }, output: { path: path.resolve(__dirname, 'dist'), filename: DevServer: {}, module: {}, plugins: [}, plugins: [}, devServer: {}, module: {}, plugins: [},+ // Module parsing rules
+ resolve: {
+ alias: {
+ bootstrapCss: 'bootstrap/dist/css/bootstrap.min.css'
+}
+},

}

Copy the code
  • Modifying the Import Mode
import 'bootstrapCss' // bootstrapCss is the alias of the resolve. Alias configuration above
Copy the code

1.2 resolve. Extensions

We often import modules in the following way when developing, that is, omit the extension of the module:

import {x, y} from 'sth/b' // stands for b.js, but.js is omitted
Copy the code

But here we see an error reported:

Why is that? To omit module extensions when importing modules, we need to configure a module extension priority order, resolve.extensions;

  • Modifying a Configuration File
const webpack= require('webpack'); module.exports = { mode: 'production', devtool: 'eval-source-map', entry: { home: './src/index.js', other: './src/other.js', x: './src/x.js' }, output: { path: path.resolve(__dirname, 'dist'), filename: DevServer: {}, module: {}, plugins: {}, devServer: {}, module: {}, plugins: {}, devServer: {}, module: {}, plugins: [], / / configuration optimization configuration optimization: {}, / / module parsing rules resolve: {alias: {bootstrapCss: 'the bootstrap/dist/CSS/bootstrap. Min. CSS'},+ extensions: ['.js', '.css', '.json', '.vue']}},Copy the code

The Extensions array specifies the order in which files will be found when the import module does not write extensions. For example, when importing STHJS /b webpack above, it will first search modules from STHJS directory in the order of B.js, B.cs, B.son and B.ue. If one is found, it will stop searching. After configuring extension, be careful not to name the file repeatedly, such as x.js and x. son. This may cause your code to not work as expected.

1.3 resolve. Modules

Tell WebPack which directories to look up when parsing modules; It can be set to a relative path or an absolute path, but setting relative and relative paths behaves slightly differently; If a relative path is set, webpack behaves in the same way node.js behaves in node_modules lookup: first in the current directory, if not in the parent directory; If it is an absolute path, then it will only look up the specified directory;

  • Modifying a Configuration File
const webpack= require('webpack');

module.exports = {
  mode: 'production'.devtool: 'eval-source-map'.entry: {
    home: './src/index.js'.other: './src/other.js'.x: './src/x.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[hash].js' // With the multi-page application [name] represents the file name, and [hash:5] generates the file name followed by a 5-bit hash stamp
  },
  devServer: {},module: {].// Configure the optimized configuration item
  optimization: {},// The module resolves the rules
  resolve: {
    alias: {
      bootstrapCss: 'bootstrap/dist/css/bootstrap.min.css'
    },
    extensions: ['.js'.'.css'.'.json'.'.vue'],
+   modules: [path.resolve('node_modules')] // Set webpack to look up from node_modules in the current directory}}Copy the code

HMR (hot-module-replacement)

Adding, modifying and deleting modules in the development process without refreshing the page can quickly improve the development efficiency; If you are developing a single page application and there are many states in the page, if the page is refreshed, all states are lost. But HMR can take care of your pain by replacing the parts that have been modified, leaving the parts that have not been modified untouched, thus saving valuable development time.

2.1 use HMR

2.1.1 indevServerenableHMRTo set uphot: true

module.exports = { ... , devServer: {+ hot: true},... }Copy the code

2.1.2 inpluginsIn the configurationwebpack.HotModuleReplacementPlugin()

module.exports = { ... , plugins: [+ new webpack.HotModuleReplacementPlugin(),. ] . }Copy the code

2.1.3 The update of the judgment and subscription module needs to be added in the code

  • Add the following code to index.js
async function renderX(e) {
  let p = await import('./test-hmr')
  console.log(p)
  let getP = document.getElementById('px1');
  if (getP) return getP.innerText = p.p;
  let newP = document.createElement('p');
  newP.innerText = p.p;
  newP.id = 'px1';
  document.body.appendChild(newP);
}
renderX();

Hot: true if HMR module is enabled
if (module.hot) {
  // hot.accept() The first argument indicates that you want to subscribe to module changes, and the second argument is the callback that will be called when the module is updated
  module.hot.accept('./test-hmr', renderX)
}
Copy the code
  • Add it in the SRC directorytest-hmr.js
export const p = '1234446666'
Copy the code

Then we modify the contents of test-hmr.js, and we find that the contents of the P tag in the page are automatically updated;

Webpack-merge Merge webpack files

In the daily development process, the packaging configuration of the development environment is often different from that of the production environment. If you always modify the same configuration file, the development experience will be poor. So a common solution is to have multiple profiles, such as Dev (development), QA (testing), PROD (production); You can write multiple of these profiles, or you can have a basic one, and then make specific configurations for your specific environment. Here we will use a smart function of -merge. This function can merge configuration files and produce merged configuration objects.

3.1 installation webpack – merge

yarn add webpack-merge -D
Copy the code

3.2 Create a config folder in the root directory and split configuration files

Extract the base configuration from the file into webpack.base.config.js, but note that devServer.contentBase and output.path are changed to.. /dist This is because __dirname has changed;

const path = require('path');

const HTMLWebpackPlugin = require('html-webpack-plugin');
const MiniCSSExtractPlugin = require('mini-css-extract-plugin'); // Remove the CSS file

const OptimizeCSSAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin'); // Compress and merge CSS files
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin'); // Compress obfuscated js files

const webpack= require('webpack');

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');


module.exports = {
  devtool: 'eval-source-map'.entry: {
    home: './src/index.js'.other: './src/other.js'.x: './src/x.js'
  },
  output: {
    path: path.resolve(__dirname, '.. /dist'),
    filename: '[name].[hash].js' // With the multi-page application [name] represents the file name, and [hash:5] generates the file name followed by a 5-bit hash stamp
  },
  devServer: {
    // Configure the development server
    hot: true./ / enable HMR
    contentBase: '.. /dist'.// Static resource file directory
    port: 8081.// The port on which the development server starts
    open: true.// Whether to automatically start the browser
    progress: true./ / the progress bar
    proxy: { // Configure the proxy
      '/api': { // Forwards the request with/API to the target domain
        target: 'http://domain.com/somet/api'.changeOrigin: true.secure: false}}},module: {
    rules: [{test: /.(js|jsx)$/,
        use: {
          loader: 'babel-loader'.options: {
            presets: ['@babel/preset-env'.'@babel/preset-react'].plugins: [['@babel/plugin-proposal-decorators', { legacy: true}].// Use decorators
              ['@babel/plugin-proposal-class-properties', { loose: true}]./ / use the class - properties
              ['@babel/plugin-transform-runtime'] / / use the async/await/generator]}},exclude: /node_modules/
      },
      {
        test: /.css$/,
        use: [
          MiniCSSExtractPlugin.loader,
          'css-loader'] {},test: /.less$/,
        use: [
          MiniCSSExtractPlugin.loader,
          'css-loader'.'postcss-loader'.'less-loader'] {},test: /.(jpeg|png|jpg|ttf|woff(\d?) |eot|svg)$/,
        use: {
          loader: 'url-loader'.options: {
            limit: 5 * 1024.outputPath: 'img/'.name: '[name].[hash:5].[ext]'.publicPath: '/img/' // This can solve the problem of using relative paths to reference images in CSS files. This is because it will concatenate the publicPath in front of the reference path of the image}}}, {test: /.(htm|html)$/,
        use:  'html-withimg-loader' // Process images referenced by img in HTML
      },
      {
        test: require.resolve('jquery'),
        use: 'expose-loader? $' // Equivalent inline import $from 'expose-loader? $! jquery'; ? $! Jquery is the argument passed to expose-loader}},plugins: [
    new HTMLWebpackPlugin({
      template: './src/index.html'.filename: "index.html".trunks: ['home']}),new HTMLWebpackPlugin({
      template: './src/other.html'.filename: "other.html".trunks: ['other']}),// Remove the CSS file
    new MiniCSSExtractPlugin({
      filename: 'css/main.[hash:5].css'
    }),

    // Inject module: Key is the variable accessible in the module, value is the corresponding module
    new webpack.ProvidePlugin({
      The $1: 'jquery'._: 'lodash'
    }),

    // Define data
    new webpack.DefinePlugin({
      // In this object key will become a variable and value will be a JS code expression
      DEV: JSON.stringify('dev')}),// Empty the contents of the package
    new CleanWebpackPlugin(),

    // Copy the contents of the file: Receives an array of items. The items in the array are objects. In the object, from represents the directory or file to be copied, and to represents the output directory
    new CopyWebpackPlugin([
      {
        from: './src/doc'.to: path.resolve(__dirname, './dist/doc')}]),// Print the necessary information in the packaged code
    new webpack.BannerPlugin('Make the best vows, tie the middle vows, and enjoy the lower blessings; Choose a high place to stand, find a flat place to live, want to go wide ')].// Configure the optimized configuration item
  optimization: {
    minimizer: [
      new OptimizeCSSAssetsWebpackPlugin(), // Compress the CSS file. After configuring the plug-in, configure the UglifyjsWebpackPlugin as follows
      new UglifyjsWebpackPlugin({
        cache: true.// Whether to cache
        parallel: true.// Whether to pack concurrently
        sourceMap: true // Whether to enable sourceMap}})],// The module resolves the rules
  resolve: {
    alias: {
      bootstrapCss: 'bootstrap/dist/css/bootstrap.min.css'
    },
    extensions: ['.js'.'.css'.'.json'.'.vue'].modules: [path.resolve('node_modules')] // Set webpack to look up from node_modules in the current directory
  },

  / / configuration externals
  externals: {
    vue: 'Vue' // When import Vue from 'Vue', it looks for window.vue}}Copy the code

3.2 Create webpack.dev.config.js in the config directory

let webpackMerge = require('webpack-merge');
let base= require('./webpack.base.config');

Merge configuration files using the smart method of webpackMerge
module.exports = webpackMerge.smart(base, {
  mode: 'development' // The mode in the exported configuration file is development
})

Copy the code

3.3 Create webpack.prod.config.js in the config directory

let webpackMerge = require('webpack-merge');
let base= require('./webpack.base.config');
module.exports = webpackMerge.smart(base, {
  mode: 'production'
})
Copy the code

3.4 modify the package. The json

Earlier we customized the configuration files, remember we configured dev and build scripts in package.json earlier? At this time we want to execute dev script according to the config/webpack. Dev. Config. Js package, and performing the build according to the config/webpack. Prod. Config. Js configuration package, You need to specify the configuration file after the corresponding name (the default configuration file for webpack packaging is webpack.config.js)

{
  "name": "test"."version": "1.0.0"."main": "index.js"."license": "MIT"."scripts": {+"dev": "webpack-dev-server --config ./config/webpack.dev.config.js",
+    "build": "webpack --config ./config/webpack.prod.config.js"
  },
  "devDependencies": {... },"dependencies": {... }}Copy the code