Webpack development environment optimization [practice]

Previous blog: Development environment packaging

Practice results

package.json

{
    
    
  "name": "webpack_dev_test_better",
  "version": "1.0.0",
  "devDependencies": {
    
    
    "css-loader": "^3.4.2",
    "file-loader": "^5.1.0",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "less": "^3.11.1",
    "less-loader": "^5.0.0",
    "style-loader": "^1.1.3",
    "url-loader": "^3.0.0",
    "webpack": "^4.42.0",
    "webpack-cli": "^3.3.11",
    "webpack-dev-server": "^3.10.3"
  }
}

entry.js (code example of hot replacement of js module)

import {
    
    status} from  './test.js'
console.log('status:'+status);
if (module.hot) {
    
    
    // test.js模块热更新开启,替换后触发回调(其它模块不会重新打包构建)。
    module.hot.accept('./test.js', function() {
    
    
        console.log('js HMR success');
        console.log('status:'+status);
    });
}

webpack.config.js

const {
    
     resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    
    
    entry:["./src/js/entry.js","./src/index.html"],
    output:{
    
    
        path:resolve(__dirname,'build'),
        filename:'js/built.js'
    },
    module:{
    
    
        rules:[
            {
    
    
                test:/\.less$/,
                use:['style-loader','css-loader','less-loader']
            },
            {
    
    
                test:/\.css$/,
                use:['style-loader','css-loader']
            },
            {
    
    
                test: /\.(jpg|png|gif)$/,
                loader: 'url-loader',
                options: {
    
    
                    limit: 8 * 1024,
                    name: '[hash:10].[ext]',
                    esModule:false,
                    outputPath: 'images'
                }
            },
            {
    
    
                test: /\.html$/,
                loader: 'html-loader'
            },
            {
    
    
                exclude: /\.(html|js|css|less|jpg|png|gif)/,
                loader: 'file-loader',
                options: {
    
    
                    name: '[hash:10].[ext]',
                    outputPath: 'media'
                }
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
    
    
            template:'./src/index.html'
        })
    ],
    mode:'development',
    devServer: {
    
    
        contentBase: resolve(__dirname, 'build'),// 项目构建后路径
        compress: true,// 启动gzip压缩
        port: 3000,// 端口号
        open: true,// 自动打开浏览器
        hot: true  // 启动模块热替换HMR
    },
    // 开发环境优选:'eval-source-map',生产环境视情况而定(源代码是否要隐藏?调试是否要更友好?)。
    // eval:内联source-map,速度最快。source-map:定位源代码报错位置,调试最优。
    devtool: 'eval-source-map'
};

Practice preparation

Development environment packaging [not optimized]

Create project: webpack_dev_test_better
initialization
npm init
npm i webpack webpack-cli -D
// 上篇博客编译打包功能涉及到的所有依赖
npm i css-loader file-loader html-loader html-webpack-plugin less less-loader style-loader url-loader -D
const {
    
     resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    
    
  entry:"./src/js/entry.js",
    output:{
    
    
        path:resolve(__dirname,'build'),
        filename:'js/built.js'
    },
    module:{
    
    
        rules:[
            {
    
    
                test:/\.less$/,
                use:['style-loader','css-loader','less-loader']
            },
            {
    
    
                test:/\.css$/,
                use:['style-loader','css-loader']
            },
            {
    
    
                test: /\.(jpg|png|gif)$/,
                loader: 'url-loader',
                options: {
    
    
                    limit: 8 * 1024,
                    name: '[hash:10].[ext]',
                    esModule:false,
                    outputPath: 'images'
                }
            },
            {
    
    
                test: /\.html$/,
                loader: 'html-loader'
            },
            {
    
    
                exclude: /\.(html|js|css|less|jpg|png|gif)/,
                loader: 'file-loader',
                options: {
    
    
                    name: '[hash:10].[ext]',
                    outputPath: 'media'
                }
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
    
    
            template:'./src/index.html'
        })
    ],
    mode:'development'
};

Practice process

One: Automatically build (devServer) [After code modification]

1. Solve the problem
  • If any module changes, you need to manually perform the repetitive steps such as packaging and refreshing the browser again.
2. Solution
  • webpack configuration devServer (hot deployment)

Note: The hot deployment function cannot monitor the webpack.config.js file. When the webpack configuration is modified, the webpack service must be restarted for the new configuration to take effect.

3. Operation example
  • Download devServer
npm i webpack-dev-server -D
  • Deployment devServer: webpack.config.js
module.exports = {
    
    
...,
mode:'devlopment',
devServer: {
    
    
      contentBase: resolve(__dirname, 'build'),// 项目构建后路径
      compress: true,// 启动gzip压缩
      port: 3000,// 端口号
      open: true// 自动打开浏览器
  }
}
  • Start devServer
// 内存中编译打包,不会有build输出
npx webpack-dev-server

Insert picture description here

  • Start result:
    • Automatic compilation and packaging, and no build folder is output.
    • Automatically start the default browser and visit http://localhost:3000/ , the rendering is the same as when the browser opens build/index.html.
    • After the code is modified, the browser automatically refreshes and presents the modified code logic.

Two: Speed ​​up the construction (HMR) [After code modification]

1. Solve the problem
  • After the normal configuration of devServer is started, a module changes, all modules must be repackaged, and the construction speed is slow.
2. Solution
  • Start the HMR function of devServer (hot module replacement).
    Function: When a module changes, only this module will be repackaged, which greatly speeds up the construction speed.
3. Operation example

Different module types support different HMR functions. The following practice tests the support status and configuration of different types of modules.

  • Style file: HMR function can be used after configuration (the style-loader used in the development environment is implemented internally).
module.exports = {
    
    
entry:["./src/js/entry.js","./src/index.html"],
...,
mode:'devlopment',
devServer: {
    
    
      contentBase: resolve(__dirname, 'build'),
      compress: true,
      port: 3000,
      open: true,
      // 实践证明:
      // 1.配置后,样式类型模块成功HMR.
      // 2.但会让html文件热部署失效,需把index.html配置为entry)
      hot: true  // 启动模块热替换HMR。
  }
}

Insert picture description here

  • js file: HMR function cannot be used by default. It is necessary to add the code that supports the HMR function to the js file (not the entry file) that needs to support the HMR function.
    • Proof: HMR is not supported by default
      Insert picture description here
    • Proof: Support HMR of src/js/test.js file after adding code in src/js/entry.js
// entrt.js
import {
    
    status} from  './test.js'
console.log('status:'+status);
//let status2 = 1;
// 实验证明1:下段代码放在test.js中不能触发HMR。
if (module.hot) {
    
    
    // test.js模块热更新开启,替换后触发回调(其它模块不会重新打包构建)。
    module.hot.accept('./test.js', function() {
    
    
        console.log('js HMR success');
        console.log('status:'+status);
    });
// 实验证明2:入口文件entry.js不能支持HMR。
    //module.hot.accept('./entry.js', function() {
    
    
    //    console.log('js HMR success');
    //    console.log('status:'+status2);
    //});
}

Insert picture description here

  • html file: HMR function is not possible and not required by default.

Three: Convenient debugging (source-map) [After the code error]

1. Solve the problem
  • The code before and after packaging is very different. After packaging, the code error is difficult to locate the error location of the code before packaging, which is not convenient for debugging.
2. Solution
  • Configure devtool: all optional configuration items are [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
3. Operation example

-1. Error source file: src/js/test.js

export let status = 6;
status.fnTest();
  • 2. The error message and error file when the source-map is not used are interfered by packaging.
    Insert picture description here
    Insert picture description here
  • 3. Configure source-map
module.exports = {
    
    
...,
// 开发环境优选:'eval-source-map',生产环境视情况而定(源代码是否要隐藏?调试是否要更友好?)。
// eval:内联source-map,速度最快。source-map:定位源代码报错位置,调试最优。
devtool: 'eval-source-map'
}
  • 4. The error message and error file after using the source-map are free from interference after packaging, and the error source file and the error line of the source file are accurately located.
    Insert picture description here
    Insert picture description here

Guess you like

Origin blog.csdn.net/jw2268136570/article/details/104900182