webpack常用的性能优化方案

HMR

HMR:模块热替换,可以在运行的时候,不刷新页面,直接更换与删除模块

webpack4

  1.   plugins: [
        new webpack.DefinePlugin({
          'process.env': require('../config/dev.env')
        }),
        // 开启全局的 HMR 能力
        new webpack.HotModuleReplacementPlugin(),
      ]
    
  2. 开发环境开启HMR

        devServer: {
    
         	//开启HMR   
            hot:true
        },
    

webpack5默认开启了HMR

Source-map

source-map:一种提供源代码到构建后代码的映射技术(如果构建后代码出错了,可以通过映射追踪代码出错位置)

最常用的三种:[inline-|hidden-|eval-]source-map

不常用的:[nosources-|cheap-[module]]source-map

内联:inline-、eval-

外部:source-map、hidden-、nosources-、cheap-[module]

  • source-map:错误代码准确信息 和 源代码的错误位置
  • inline-source-map:错误代码准确信息 和 源代码的错误位置
  • hidden-source-map:错误代码的错误原因,但是没有错误位置,不能追踪源代码错误,只能提示到构建后代码的错误位置
  • eval-source-map:错误代码的准确信息 和 源代码的错误位置
  • nosource-source-map:错误代码准确信息,但是没有任何源代码
  • cheap-source-map:错误代码的准确信息 和 源代码的错误位置,只能精确到行
  • cheap-module-source-map:错误代码的准确信息 和 源代码的错误位置

source-map选择

  • 开发环境:速度快,调试友好

    速度:eval>inline>cheap…

    1. eval-cheap-source-map

    2. eval-source-map

    调试友好:

    1. source-map

    2. cheap-module-source-map

    3. cheap-source-map

    –>eval-source-map

    –>eval-cheap-module-source-map

  • 生产环境:源代码要不要隐藏 调试

    内联会让代码体积十分庞大,所以在生产环境中不考虑使用内联

    –>source-map

    –>cheap-module-source-map

    –>hidden-source-map

oneOf

rules: [
            {
                // js兼容性
                test: /\.js$/,
                exclude: /node_module/,
                loader: "babel-loader",
                options: {
                    // 预设:指示babel怎么做兼容性处理
                    presets: [
                        [
                            '@babel/preset-env',
                            {
                                // 按需加载
                                useBuiltIns: "usage",
                                corejs: {
                                    version:3
                                },
                            }
                        ]
                    ]
                }
            },
            {
                // 一下loader只会匹配一个
                // 一个类型的文件只会被处理一次
                //所以js文件需要单独提取出来
                oneOf: [
                    
            {
                // css
                test: /\.css$/,
                use: [...commonCssLoader]
            },
            {
                // less
                test: /\.less$/,
                use: [...commonCssLoader,"less-loader"]
            },
            /*
            当一个文件被多个laoder处理时,要指定loader执行的先后顺序
            */ 
            {
                // js
                test: /\.js$/,
                exclude: /node_module/,
                // 优先执行
                enforce:'pre',
                loader: "eslint-loader",
                options: {
                    fix:true
                }
            },
                ]
            }
        ]

缓存

babel缓存

babel缓存会使第二次打包构建速度更快

rules:[
            {
                // js兼容性
                test: /\.js$/,
                exclude: /node_module/,
                loader: "babel-loader",
                options: {
                    // 预设:指示babel怎么做兼容性处理
                    presets: [
                        [
                            '@babel/preset-env',
                            {
                                // 按需加载
                                useBuiltIns: "usage",
                                corejs: {
                                    version:3
                                },
                            }
                        ]
                    ],
                    // 开启babel缓存
                    // 第二次构建时,会读取之前的缓存,加快构建速度
                    cacheDiretory:true
                }
            },
]

文件资源缓存

给文件名加上hash值

  • hash:每次修改打包后会给新的hash值
    • js和css使用同一个hash值,重新打包会使所有缓存失效
  • chunkhash:根据chunk生成的hash值
    • 如果打包来源于同一个trunk,那么hash值一样
  • contenthash:根据文件内容生成hash值
    • 不同文件的contenthash一定不同

文件资源缓存使代码上线运行缓存更好使用

tree shaking

使用前提:

  1. 必须使用es6模块化
  2. 开启production环境

作用:减少代码体积

在package.json中配置sideEffects

​ sideEffects:false 所有代码都没有副作用(都可以进行tree shaking)可能会把css/@babel/polyfill…文件干掉

​ 推荐自己设置sideEffects

{
    "sideEffects":["*.css","*.less",...]
}

code split

  • 多入口

    module.exports={
        entry: {
            main: "./src/js/index.js",
            test: "./src/js/test.js",
        },
    }
    

    webpack会按照入口生成对应的built.js

  • optimization.splitChunks

    	/*
         1.可以将node_module中代码单独打包一个chunk最终输出
         2.自动分析多入口chunk中,有没有公共文件。如果有,会打包成一个单独的chunk
        */ 
        optimization: {
            splitChunks: {
                chunks:"all"
            }
        },
    
  • import

    /*
      通过js代码,让某个文件被单独打包成一个chunk
      import动态导入语法:能将某个文件单独打包
      单入口y
    */
    import(/* webpackChunkName:'test' */ './test').then((result) => {
      console.log("文件加载成功",result);
    }).catch(() => {
      console.log("文件加载失败");
    })
    

lazyload&preload

//通过异步函数,来动态加载
document.querySelector("#btn").onclick = function () {
  // 懒加载
  import(/* webpackChunkName:'test'*/'./test').then(({mul}) => {
    console.log(mul(2,3));
  })
    // 预加载 prefetch:会在使用之前,提前加载js文件
    //预加载存在兼容性问题
  import(/* webpackChunkName:'test',webpackPrefetch:true*/'./test').then(({mul}) => {
    console.log(mul(2,3));
  })
}

PWA

PWA:离线访问技术,也就是当我们没有网络的时候也可以访问(有限资源)

  1. 安装 workbox-webpack-plugin 插件
npm i workbox-webpack-plugin -D
  1. 配置
//webpack.config.js
const WorkboxWebpackPlugin =require("workbox-webpack-plugin")

plugins:[
        new WorkboxWebpackPlugin.GenerateSW({
            /*
            1.帮助serviceworker快速启动
            2.删除旧的serviceworker
            组测serviceworker
            */ 
            clientsClaim: true,
            skipWaiting:true
        })
]
  1. 注册serviceworker
//src/js/index.js 也就是你的入口文件
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js').then(() => {
      console.log('sw 注册成功');
    }).catch(() => {
      console.log('sw注册失败');
    });
  });
}
  1. 使用

serviceWorker必须运行在服务器上所以可以自己用node.js搭建一个本地服务器

或者 使用 serve 第三方库快速搭建

在项目根目录键入以下指令,可以快速搭建一个本地服务器

npm i serve -g
serve -s build

serve -s build 启动服务器,将build目录下的所有资源全部暴露出去

多进程打包

使用多进程打包需要安装 thread-loader

npm i thread-loader -D

使用多进程打包时候需要考虑你的项目是否真的需要多进程打包。

进程启动大概600ms,进程通信也有开销,只有工作消耗时间比较长才需要多进程打包。

所以使用不恰当可能会使构建速度下降,我们要谨慎使用

modules:{
	rules:[
		{
		//babel中比较适合使用多进程打包
            // js兼容性
                test: /\.js$/,
                exclude: /node_module/,
                use: [
                    /*
                    开启多进程打包
                    进程启动大概600ms,进程通信也有开销
                    只有工作消耗时间比较长才需要多进程打包
                    */ 
                    {
                        loader: 'thread-loader',
                        options: {
                            workers:2//2个进程
                        }
                    },
                    {
                        loader: "babel-loader",
                        options: {
                            // 预设:指示babel怎么做兼容性处理
                            presets: [
                                [
                                    '@babel/preset-env',
                                    {
                                        // 按需加载
                                        useBuiltIns: "usage",
                                        corejs: {
                                            version:3
                                        },
                                    }
                                ]
                            ],
                            // 开启babel缓存
                            // 第二次构建时,会读取之前的缓存
                            cacheDirectory:true
                        }
                    }
                ],
		}
	]
}

externals

使用externals可以拒绝一些第三方包参与构建

module.exports={
        externals: {
        // 库名:npm包名
        jquery:"jQuery"
    }
}

dll

使用dll技术对某些库(第三方库:jquery,react,vue…)单独打包,避免第三方库重复打包,可以在第一次打包之后提高构建效率

//新建 webpack.dll.js
const { resolve } = require("path");
const webpack = require("webpack");
module.exports = {
    entry: {
		/*
		暴露的库名(自定义):tdLib,
		需要暴露的库:["jquery",......]
		*/
        tdLib:["jquery"]
    },
    output: {
        filename: '[name].js',
        path: resolve(__dirname, "dll"),
        library:'[name]_[hash]',//打包的库向外暴露出去的内容叫什么名字
    },
    plugins: [
        // 打包生成一个mainfest.json-->提供和jquery的映射
        new webpack.DllPlugin({
            name: '[name]_[hash]',//映射库的暴露的内容名称
            path:resolve(__dirname,'dll/mainfest.json')//输出文件路径
        })
    ],
    mode:"production"
}

运行 webpack.dll.js

webpack --config webpack.dll.js

运行之后会发现多出了一个dll目录,该目录中就包含打包的第三库以及与其对应的映射关系。

然后我们接着需要在webpack.config.js中做相应配置,然后正常打包就行。

npm i add-asset-html-webpack-plugin -D
//webpack.config.js
const webpack =require("webpack")
const AddAssetHtmlWebpackPlugin =require("add-asset-html-webpack-plugin")
module.exports={
        plugins: [
        // 告诉webpack那些库不参与打包,同时使用时的名称也得变
        new webpack.DllReferencePlugin({
            manifest:resolve(__dirname,"dll/mainfest.json")
        }),
        // 会将某个文件打包输出出去,并在html中自动引入该资源
        new AddAssetHtmlWebpackPlugin({
            filepath:resolve(__dirname,"dll/tdLib.js")
        })
    ],
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值