关于前端:webpack-性能优化

38次阅读

共计 6104 个字符,预计需要花费 16 分钟才能阅读完成。

webpack 性能优化

  • 开发环境性能优化
  • 生产环境性能优化

开发环境性能优化

  • 优化打包构建速度

    • HMR
  • 优化代码调试

    • source-map

生产环境性能优化

  • 优化打包构建速度

    • oneOf
    • babel 缓存
    • 多过程打包
    • externals
    • dll
  • 优化代码运行的性能

    • 缓存(hash,chunkhash,contenthash)
    • tree shaking
    • code split
    • 懒加载和预加载
    • pwa

优化 开发环境 打包构建速度

HMR hot module replacement 热模块替换 / 模块热替换

作用:一个模块发生变化,只会从新打包这一个模块 而不是从新打包所有, 极大晋升构建速度

  • 款式文件: 能够应用 HMR 性能,因为 style-loader 外部实现了
  • js 文件: 默认不能应用 HMR 性能 –> 解决:须要批改 js 代码,增加反对 HMR 性能的代码。留神,HMR 性能对 js 的解决,只能解决非入口 js 文件的其余文件。
if(module.hot){
    // 一旦 module.hot 是 true,阐明开启 HMR 性能,让 HMR 性能代码失效
    module.hot.accept('./xxx.js',function(){
        // 此办法会监听 print.js 文件的变动,一旦发生变化,其余默认不会从新打包构建
        // 会执行前面的回调函数
        xxx();})
}
  • html 文件: 默认不能应用 HMR 性能,同时会导致问题:html 文件不能热更新了

    解决:改 entry:['入口 js','html'],但 html 文件只有一个,所以不必做 HMR 性能

    devServer:{
        // 我的项目构建后的目录
        contentBase: resolve(__dirname,'build'),
        // 启用 gzip 压缩
        compress:true,
        // 端口号
        port:3000,
        // 主动关上浏览器
        open:true
    }

优化 开发环境 代码调试

source-map 一种提供源代码到构建后代码映射的技术

如果构建后代码出错了,通过映射能够追踪到谬误的代码

webpack.config.js

devtools:'source-map'
// 其余 参数 [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

source-map : 内部
    错误代码的精确信息和谬误地位
inline-source-map : 内联
    错误代码的精确信息和谬误地位
hidden-source-map : 内部
    错误代码的谬误起因 但没有谬误地位,不能追踪到源代码的谬误,只能提醒到构建后代码的地位
eval-source-map : 内联
    每一个文件都生成对应的 source-map, 都在 eval
    错误代码的精确信息和谬误地位
nosources-source-map : 内部
    能找到错误代码的精确信息 但没有任何源代码信息
cheap-source-map : 内部
    错误代码的精确信息和谬误地位 只准确到行,不准确到列
cheap-module-source-map : 内部
    错误代码的精确信息和谬误地位
    module 会将 loader 的 source-map 退出
内联 和 内部的区别:1. 内部生成了文件但内联没有生成
    2. 内联构建速度更快
  • 开发环境:速度快,调试更敌对

    速度快 eval>inline>cheap>...
    调试更敌对 souce-map>cheap-module-souce-map>cheap-souce-map
    所以 个别用 eval-source-map
    
  • 生产环境:源代码要不要暗藏,调试要不要敌对?内联会让体积编码,所以个别不必内联

    nosources-source-map 暗藏源代码
    hidden-source-map 只暗藏源代码,会提醒构建购代码错误信息
    --> source-map /cheap-module-souce-map
    

优化生产环境

oneOf

rules 里中有许多个 loader,这样会导致每个文件都会被所有的 loader 过一遍,有些能解决,有些解决不了。所以能够利用 oneOf 达到以下 loader 只会匹配到第一个。但须要留神,不能有两个 loader 同时解决同一个文件

webpack.config
module.exports={
    //....
    module:{
        rule:[
            // 失常来讲,一个文件只能被一个 loader 解决
            // 当一个文件要被多个 loader 解决,那么肯定要指定 loader 的执行程序
            // 先执行 eslint 再执行 babel
            {
                test:/\.js$/,
                exclude:/node_modules/,
                // 优先执行
                enforce:'pre',
                loader:'eslint-loader',
                options:{fix:true}
            },
            {
              oneOf:[
                    {
                        test: /\.css$/,
                        use:[...commonCssLoader]
                    },
                    {
                        test:/\.less$/,
                        use:[...commonCssLoader,'less-loader']
                    },
                    {
                        test:/\.js$/,
                        exclude:/node_modules/,
                        loader:'babel-loader',
                        options:{
                            // 预设:批示 babel 做怎么的兼容性解决
                            presets:[
                            [
                                    '@babel/preset-env',
                                    {
                                        // 按需加载
                                        useBuiltIns:'usage',
                                        // 指定 core-js 版本
                                        corejs:{version:3},
                                        // 指定兼容性做到哪个版本的浏览器
                                        targerts:{
                                            chrome: '40',
                                            fixfox: '50',
                                            ie: '9',
                                            safari: '10',
                                            edge: '17'
                                        }
                                    }
                            ]
                            ]
                        }
                    },
                    {test:/\.(png|jpg|gif)/,
                        loader:'url-loader',
                        enModule:true,
                        options:{
                            limit:8*1024,
                            name: '[hash:10].[ext]',
                            outputpath:''
                        }
                    },
                    {
                        test:/\.html$/,
                        loader:'html-loader'
                    },
                    {exclude:/\.(js|less|css|png|jpg|gif)/,
                        loader:'file-loader',
                        options:{name:'[hash:10].[ext]'
                        }
                    }
                ]
            }
        ]
    },
}

缓存

1.babel 缓存 –> 第二次打包更快

{
    test:/\.js$/,
    exclude:/node_modules/,
    loader:'babel-loader',
    options:{
        // 预设:批示 babel 做怎么的兼容性解决
        presets:[
        [
            '@babel/preset-env',
            {
                // 按需加载
                useBuiltIns:'usage',
                // 指定 core-js 版本
                corejs:{version:3},
                // 指定兼容性做到哪个版本的浏览器
                targerts:{
                    chrome: '40',
                    fixfox: '50',
                    ie: '9',
                    safari: '10',
                    edge: '17'
                }
            }
        ]
        ],
        // 第二次构建时,会读取之前的缓存
        cacheDirectory: true
        }
    },

2. 文件资源缓存 –> 上线缓存优化

    hash: 每次 webpack 构建会生成一个惟一 hash 值
        问题:因为 js 和 css 同时应用一个 hash 值,如果从新打包,会导致所有缓存生效,可能我却只改了一个文件,chunkhash:依据 chunk 生成 hash 值,如果打包来源于同一个 chunk,那么 hash 值也一样
        问题:js 和 css 的 hash 值还是一样的。起因:css 是由 js 引入的,所以属于同一个 chunk
    contenthash: 依据文件内容生成 hash 值,
webpack.config.js

tree shaking

去除应用程序中没有应用的代码


前提:1. 必须应用 es6 模块化
2. 开启 production 模式

在 package.json 中配置
"sideEffects":false 所有代码都没有副作用,都能够镜像 tree sharking 
    问题 可能会把 css/@babel/polyfille 干掉
"sideEffects": ["*.css","*.less"] 哪些文件不 tree sharking

code split

1. 入口配置

    单入口 // 单页面利用
    entry:'./src/js/index.js' 
    多入口 // 多页面利用
    entry:{
        index:'./src/js/index.js',
        test:'./src/js/test.js'
    }

2.optimization

module.exports={
    //...
    // 能够将 nodemudules 中的代码独自打包成一个 chunk 最终输入
    // 还能够主动剖析多入口 chunk 中,有没有公共的文件,如果有会打包成一个独自的 chunk
    optimization:{
        splitChunks:{chunks:'all'}
    }
}
    

3.import 动静导入语法,能将某个文件独自打包

通过 js 代码,让某个文件被独自打包成一个 chunk, 通过正文能够固定此文件的名称

import(/*webpackChunkName: 'xxxName' */'./xx/xxx.js')
    .then(res =>{// 加载胜利})
    .catch(()=>{// 加载失败})

懒加载和预加载

1. 懒加载 当文件须要用时才加载

import 动静导入语法

document.getElementById('btn').onclick = function(){import(/*webpackChunkName: 'xxxName' */'./xx/ss.js')
    .then(res=>{// 干啥干啥})
}

2. 预加载 webpackPrefetch:true

./xx/ss.js 曾经被加载了,点击的时候再从缓存中加载,

document.getElementById('btn').onclick = function(){import(/*webpackChunkName: 'xxxName',webpackPrefetch:true */'./xx/ss.js')
    .then(res=>{// 干啥干啥})
}
  • 失常加载能够认为是并行加载(同一时间加载多个文件)
  • 预加载 prefectch 等其余资源加载结束,浏览器闲暇了,再偷偷加载资源 兼容性比拟差 慎用

PWA 渐进式网络开发应用程序

网络离线可拜访

webbox–>webbox-webpack-plugin

const WebboxWebpackPlugin = require('webbox-webpack-plugin')
module.exports={
    plugins:[
        new WebboxWebpackPlugin.GenerateSW({
            /*
                1. 帮忙 serviceWorker 疾速启动
                2. 删除旧的 serviceWorker 

                生成一个 serviceWorker 配置文件
             */
            clientsClaim:true,
            skipWaiting:true
        })
    ]
}

index.js 中注册 serviceworker
// 解决兼容性
if('serviceWorker' in navigator){window.addEventListener('load',()=>{
        navigator.serviceWorker
            .register('./service-work.js')
            .then(()=>{// 胜利})
            .catch(()=>{// 失败})
    })
}

1. 可能会呈现问题 eslint 不意识 window 和 navigator
解决 package.json 中 eslintConfig 中配置
"env":{"browser":true // 反对浏览器端的变量}

2. sw 代码必须运行在服务器上
    -->node.js 
        --> npm i serve -g 
            serve -s build 启动一个服务器将 build 下的资源作为动态资源裸露进来

多过程打包

thread-loader 个别给 babel-loader 用

但须要留神
过程启动大概需 500ms,过程间通信也有开销。只有工作耗费工夫比拟长,才须要多过程打包

{
    test:/\.js$/,
    exclude:/node_modules/,
    use:[
        //'thread-loader',
        {
            loader:'thread-loader',
            options:{workers: 2 // 过程 2 个}
        }
        {
            loader:'babel-loader',
            options:{
                // 预设:批示 babel 做怎么的兼容性解决
                presets:[
                [
                    '@babel/preset-env',
                    {
                        // 按需加载
                        useBuiltIns:'usage',
                        // 指定 core-js 版本
                        corejs:{version:3},
                        // 指定兼容性做到哪个版本的浏览器
                        targerts:{
                            chrome: '40',
                            fixfox: '50',
                            ie: '9',
                            safari: '10',
                            edge: '17'
                        }
                    }
                ]
                ],
                // 第二次构建时,会读取之前的缓存
                cacheDirectory: true
                }
        }
    ]
    },

externals

module.exports={
    externals:{
        // 疏忽 / 回绝  库名 -- npm 包名 
        // 能够在 index.html 中引入 cdn
    }
}

dll 动静连贯

应用 dll 技术 对某些库(第三方库)进行独自打包

    指令 webpack --config webpack.dll.js
webpack.dll.js
const {resolve} = require('path')
const webpack = require('webpack')
module.exports = {
    entry:{// 最终打包生成的[name]-->jquery
        //['jquery']--> 要打包的库是 jquery
        jquery:['jquery']
    },
    ouput:{filename:'[name].js',
        path:resolve(__dirname,'dll'),
        library:'[name]_[hash]' // 打包的库里面向外裸露进来的内容叫什么名字
    },
    plugin:[
        new webpacl.DllPlugin({
            // 打包生成一个 manifest.json --> 提供和 jquery 映射
            name: '[name]_[hash]',// 映射库的裸露内容名称
            path:resolve(__dirname,'dll/manifest.json')

        })
    ],
    mode:'production'
}

webpack.config.js
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
module.exports={
    plugins:[
        // 通知 webpack 哪些库不参加打包,同时名称也得变
        new webpack.DllReferencePlugin({manifest: resolve(__dirname,'dll/manifest.json')
        }),
        // 将某个文件打包输入进来,并在 html 中引入该资源
        new AddAssetHtmlWebpackPlugin({filepath:resolve(__dirname,'dll/jquery.js')
        })
    ]
}

正文完
 0