// 在webpack.config.js中配置  hot : true
devServer : {
    contentBase : path.resolve(__dirname,"build"),
    compress : true,
    port : 3000,
    open : true,
    //开启HMR热模块替换
    hot : true,
}  
/**
 * HMR : hot moudle replacement  热模块替换/模块热替换
 * 作用:一个模块发生改变,只会重新打包当前一个模块,不会影响其他模块,极大提高打包速度
 * 
 *
 *样式文件:可以使用HMR功能,因为style-loader内部已经做了功能实现
 *
 *
 *js文件 : 默认情况下js文件是不能使用HMR功能的
 *  注意:HMR功能对js的处理只能处理非入口js的其他文件。(依赖都在入口文件引入)
 *  在入口文件做一下逻辑
    ```js
        if(module.hot){
            //当module.hot为true 说明开启了HMR功能,
            module.hot.accept(‘xxxxx.js‘,function(){
                // module.hot.accept 监听xxxxx.js 文件的变化,不会影响其他文件的打包构建。
                执行方法
            })
        }
    ```js
 * 
 *
 *html文件:默认情况下htm;文件是不能使用HMR功能的,同时会导致html不能热更新,(不建议做HMR)
 *  解决方案: 修改entry入口 将html文件引入
*/
    //在webpack.config.js中
    devtool : ‘source-map‘,
    /*
        source-map 提供源代码到构建后代码 映射
         通俗解释:如果构建后代码报错,通过映射可以追踪到源代码报错地方。
    */
    /*
        devtool后面参数汇总:
            source-map : 外部
                错误代码准确信息 和 源代码的准确位置
            inline-source-map : 内联
                只会生成一个内联 source-map
                错误代码准确信息 和 源代码的准确位置
            hidden-source-map : 外部
                错误代码的原因  但是 不会追踪到源代码的错误的位置
            eval-source-map : 内联
                每一个文件都生成对应的source-map  都在eval
                错误代码准确信息 和 源代码的准确位置  文件会多了一个hash值
            nosoureces-source-map : 外部
                错误代码准确信息  但是  没有源代码信息
            cheap-source-map : 外部
                错误代码准确信息 和 源代码的准确位置  但是 整行都会报错,不会具体的那一段代码
            cheap-module-source-map : 外部
                错误代码准确信息 和 源代码的准确位置 
            内联  和   外部的区别 : 
                a: 外部生成了文件,内联没有生成文件
                b: 内联构建速度更快
        怎么使用source-map:
            开发环境:
                速度快,调试更加方便友好,
                    速度:
                        eval > inline > cheao > ...
                        可以组合应用:
                        eval-cheap-source-map
                        eval-source-map
                    调试:
                        source-map
                        cheap-module-source-map
                        cheap-source-map
            比较好----->  eval-source-map / eval-cheap-module-source-map
            生产环境:
                源代码要不要隐藏?调试要不要友好
                内联会让代码体积变大,所有在生产环境尽量不要使用内联
                 nosoureces-source-map   全部隐藏
                 hidden-source-map   只隐藏源代码,会提示构建后代码错误信息
            比较好----->  source-map   /  cheap-module-source-map 
            
    */
优化打包构建速度
优化代码运行性能
oneOf优化
    moudle : {
        rules : [
            {
                //以下loader只会匹配以下
                //执行逻辑:匹配成功之后就不会再往下匹配
                //注意不能有两个配置处理同一种类型文件
                //如果有两个配置处理一个文件(例如:js eslint babel ) 可以把优先执行的配置单独拎出来,{ } 放在rules里面。
                onnOf : [
                    {...配置}
                ]
            }
        ]
    }
缓存
    //对bable缓存
    {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: ‘babel-loader‘,
        //开启缓存
        cacheDirectory : true
    }
    //文件资源缓存:
        /*
            filename : ‘css/built.[hash:10].css‘
            hash : 每次webpack构建时会生成一个唯一的hash值
                问题:因为js和css同时使用一个hash值
                    如果重新打包会导致所有缓存失败,
            filename : ‘css/built.[chunkhash:10].css‘
            chunkhash : 根据chunk 生成的hash值,如果打包来源于同一个chunk  那么hash值就一样
                问题:因为js和css同时使用一个hash值
            filename : ‘css/built.[contenthash:10].css‘
            contenthash : 根据文件内容生成的hash值,不同文件hash值不一样
            
        */
tree shaking 去除无用的代码
    //当webpack.config.js mode:‘production‘ 则开启 tree shaking
    /*
        前提条件:
            a: 必须使用es6模块化
            b: 开启production环境
            
        作用:减少代码体积
        在package.json中配置
            "sideEffects" : false,
            所有代码没有副作用(都可以进行 tree shaking)
            问题:可能会把css/ @babel/polyfill 文件干掉
            "sideEffects" : ["*.css","*.scss"],
    */
    
code split ( 代码分割 )
    //单入口、多入口
    module.exports = {
        //entry : ‘./src/main.js‘ // 单入口
        //多入口 
        entry : {
            main : ‘./src/main.js‘,
            test : ‘./src/test.js‘
        },
        //输出配置
        output : {
            //name 给输出的文件命名,否则多入口输出都是一个文件名称。
            filename : js[name].js,
            path : path.resolve(__dirname,‘build‘)
        }
    }
    //webpack.config.js
    //将node_module中代码单独打包一个chunk输出
    //会分析多入口chunk中,有没有公共的文件。如果有只打包一个
     //例如 a.js  b.js都依赖jquery  这样单独拎出jquery打包
    module.exports = {
        optimization:{
            splitChunks : {
                chunks : ‘all‘
            }
        }
    }
    //通过js逻辑,完成文件被单独打包一个chunk
    import(/*webpacjChunkName:test*/‘.test‘)
        .then(() => {
            console.log(‘文件加载成功‘)
        })
        .catch(() => {
            console.log(‘文件加载失败‘)
        })
懒加载 预加载
    //懒加载
    //场景:当点击按钮的时候在调用某个模块、以及某个模块中的方法
    //不直接 import引入 而是把引入放在逻辑里面
    btn.addEventListener(‘click‘,() => {
        import(/*webpacjChunkName:test*/‘./text.js‘)
        .then((fn) => {
            fn()
        })
    })
    //预加载
    //会在模块使用之前去加载js文件
    // webpackPrefetch :true
    btn.addEventListener(‘click‘,() => {
        import(/*webpacjChunkName:test,webpackPrefetch :true*/‘./text.js‘)
        .then((fn) => {
            fn()
        })
    })
PWA 离线访问
    //webpack.config.js配置
    //安装
        // $ cnpm instal work-box-webpack-plugin -D
    //引入
        // const WorBoxWebpackPlugin = require(‘work-box-webpack-plugin‘);
    //配置
    module.exports = {
        plugins : [
            new WorBoxWebpackPlugin({
                /*
                    1: 使serviceworler快速启动
                    2:删除旧的serviceworker
                    生成有一个serviceworker 配置文件
                */
               clientsClaim : true,
               skipWaiting : true,
            })
        ]
    }
    //在入口文件js中注册serviceworker
    if(‘serviceworker‘ in navigator){
        window.addEventListener(‘load‘,() => {
            navigator.serviceworker
                .register(‘./serviceworker.js‘)
                .then(() => {
                    console.log(‘serviceworker注册成功‘)
                })
                .catch(() => {
                     console.log(‘serviceworker注册失败‘)
                })
        })
    }
    /*
        注意事项:
            1: eslint 不识别 window / navigator全局变量
                解决: 
                    在package.json中eslintConfig配置
                    "env" : {
                        "browser" : true
                        //支持浏览器端全局变量
                    }
            2: serviceworker 必须运行在服务器上
    */
多进程打包
    // cnpm install thread-loader -D
    //配置 : 在 babel中使用即可
    {
        test: /\.js$/,
        exclude: /node_modules/,
        use : [
            {
                /*
                    开启多个进程打包:
                    进程启动大概在600ms 进程通信也有开销
                    只有工作消耗比较大的时候才能使用多进程打包
                */
                loader : ‘thread-loader‘,
                options : {
                    workers : 2//进程2个
                }
            },
            {
                loader: ‘babel-loader‘,
                options: {
                    persets: [
                        [
                            ‘@babel/preset-env‘,
                            {
                                useBuildIns: ‘usage‘,
                                corejs: {
                                    version: 3
                                },
                                targets: {
                                    chrome: ‘60‘,
                                    firefox: ‘60‘,
                                    ie: ‘9‘,
                                    safari: ‘10‘,
                                    edge: ‘17‘
                                }
                            }
                        ]
                    ]
                }
            }
        ]
    }
externals (忽略某个包进行打包 : 例如忽略引入的jquery库)
    //配置:只需要在webpack.config.js 添加 externals即可
    externals : {
        //拒绝jQuery被打包进来
        //jQuery 为 npm包的名称
        jquery : ‘jQuery‘
    }
DLL打包
    // 创建 webpack.dll.js文件
    // 使用dll技术对某些库 (第三方库 : jquery、react、vue ...) 进行单独打包
    const {reslove} = require(‘path‘)
    const webpack = require(‘webpack‘)
    module.exports = {
        entry : {
            //最终打包成的[name] => jquery
            //[‘jquery‘]   要打包的库是 jquery
            jquery : [‘jquery‘]
        },
        output : {
            filename : ‘[name].js‘,
            path : resolve(__dirname,‘dll‘),
            library : ‘[name]_[hash]‘ //打包的库里面向外暴露出去的内容的名称
        },
        plugins : [
            new webpack.DllPlugin({
                name : ‘[name]_[hash]‘  //映射库的暴露的内容名称
                path : resolve(__dirname,‘dll/manifest.json‘) //输出文件的路径
            })
        ],
        mode : ‘production‘
    }
    //webpack.config.js中配置
    // 安装 引入 webpack   add-asset-html-webpack-plugin
    plugins : [
        // 告诉webpack哪些库不参与打包,同时使用时候的名称也需要变更
        new webpack.DllReferencePlugin({
            manifest : path.resolve(__dirname,‘dll/manifest.json‘)
        }),
        //将某个文件打包输出去,并在html中自动引入
        new AdAssetHtmlWebpackPlugin({
            filename : path.resolve(__dirname,‘dll/jquery.js‘)
        })
    ]
原文:https://www.cnblogs.com/bruce-w/p/14074156.html