webpack 性能优化

打包优化

HMR: hot module replacement 热模块替换 / 模块热替换
作用: 一个模块发生变化,只会重新打包这一个模块(而不是打包所有)
极大提升构建速度
样式文件:可以使用HMR功能,因为style-loader 内部实现了
js文件:默认不使用HMR功能 --> 需要修改 js 代码,添加支持HMR功能的代码
注意:HMR功能对js的处理,只能处理非入口js文件的其他文件
html文件:默认不使用HMR功能,同时会导致html文件不会热更新了 (不用做HMR功能呢)
解决: 修改entry入口,将html文件引入 例: entry: ['./src/js/index.js', './src/index.html']

代码调试

代码调试 devtool: 'source-map'
source-map: 一种提供源代码到构建代码映射技术(如果构建后代码出错,通过映射关系可以追踪源代码的错误)
[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

source-map: 外部
    错误代码的准确信息 和 源代码的错误位置
inline-source-map: 内联
    1. 只生成一个内联 source-map
    错误代码的准确信息 和 源代码的错误位置
hidden-source-map: 外部
    错误代码错误原因,但是没有错误位置
    不能追踪到源代码的错误,只能提示到构建后代码的错误位置
eval-source-map: 内联
    1.每一个文件都生成对应的source-map, 都在eval
    错误代码的准确信息 和 源代码的错误位置
nosources-source-map: 外部
    错误代码的准确信息,但是没有任何源代码信息(隐藏源代码)
cheap-source-map: 外部
    错误代码的准确信息 和 源代码的错误位置
    只能精确到行
cheap-module-source-map: 外部
    错误代码的准确信息 和 源代码的错误位置
    module 会将loader和source map加入

内联 和 外部的区别:1. 外部生成了文件,内联没有 2.内联构建速度更快

开发环境:速度快,调试友好
    速度快(eval>inline>cheap>...)
        eval-cheap-source-map
        eval-source-map
    调试友好
        source-map
        cheap-module-source-map
        cheap-source-map
    --> eval-source-map 更友好(脚手架默认的) ,其次 eval-cheap-module-source-map
生产环境:源代码要不要隐藏? 调试要不要更友好
    内联会让体积变大,所以生产环境用外部

    nosources-source-map  全部隐藏
    hidden-source-map     只隐藏源代码,会提示构建后代码错误信息

    --> source-map  调试友好 /  cheap-module-source-map

oneOf 以下loader只会匹配一个
注意: 不能有两个配置处理同一种类型文件
提升构建速度

缓存

babel缓存
cacheDirectory: true
--> 让第二次打包更快
文件资源缓存
hash:每次webpack构建打包会生成一个唯一的hash值
问题: 因为js和css同时使用一个hash值
如果重新打包,会导致所有缓存失效(可能只改动一个文件)
chunkhash: 根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样
问题:js和css的hash值还是一样的,因为css是在js中被引入的,所以同属于一个chunk
contenthash: 根据文件的内容生成hash值。不同的文件hash值一定不一样,并且是单独管理的
--> 让代码上线运行缓存更好使用

tree shaking: 去除无用的代码

前提:1.必须使用es6模块化 2. 开启production环境
作用: 减少代码体积
在package.json中配置
"sideEffects": false; 所有代码都没有副作用(都可以进行 tree shaking)
webpack版本原因造成的问题: 可能把css/@babel/polyfill (副作用)文件干掉
"sideEffects": [".css", ".less"]

code split

        demo1:
            多入口
            entry: {
                // 多入口:有一个入口,最终输出就有一个bundle
                index: './src/js/index.js',
                test: './src/js/test.js'
            },
        demo2:
            optimization: {
                splitChunks: {
                    chunks: 'all'
                }
            },
        demo3:
            通过js代码,让某个文件被单独打包成一个chunk
            import 动态导入语法:能将某个文件单独打包.
            import(/*webpackChunkName:'test' */'./test')
              .then(() => {
                  // eslint-disable-next-line
                  console.log('加载成功')
              })
              .catch(() => {
                  // eslint-disable-next-line
                  console.log('加载失败')
              })

懒加载 lazy loading

懒加载~: 当文件需要使用的时候在加载
预加载 prefetch: 会在使用之前,提前加载js文件

// 例如 点击事件之后加载test.js
document.getElementById('btn').onclick = function(){
    import(/*webpackChunkName:'test',webpackPrefetch: true */'./test')
              .then(() => {
                  // eslint-disable-next-line
                  console.log('加载成功')
              })
              .catch(() => {
                  // eslint-disable-next-line
                  console.log('加载失败')
              })
}

PWA 渐进式网络开发应用程序(在入口文件里配置)

/*
    1.eslint 不认识window  navigator全局变量
      解决:需要修改package.json 中的 eslintConfig 配置
        "env": {
            "browser": true // 支持浏览器变量
        }
    2. sw代码必须运行在服务器上
        --> nodejs
        --> npm i serve -g
            serve -s -build 启动服务器,将 build 目录下所有资源作为静态资源暴露出去
 */
// 注册 serviceworker
// 处理兼容性问题
if ('serviceworker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js')
      .then(() => {
        // eslint-disable-next-line
        console.log('sw注册成功~')
      })
      .catch(() => {
        // eslint-disable-next-line
        console.log('sw注册失败~')
      });
  });
}


webpack 开发环境配置文件

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 提取css成单独文件的插件
// mini-css-extract-plugin
const miniCssExtractPlugin = require('mini-css-extract-plugin')
// 压缩css插件:optimize-css-assets-webpack-plugin
const optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')

// 设置 nodeJs 环境变量,方便开发者调试
process.env_NODE_ENV = 'development'



module.exports = {
    entry: ['./src/js/index.js', './src/index.html'],
    output: {
        filename: 'js/built.[contenthash:10].js',
        path: resolve(__dirname, 'build')
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_moudles/, // 排除,防止eslint检测
                loader: 'eslint-loader',
                // 优先执行
                enforce: 'pre',
                options: {
                    // 自动修复
                    fix: true
                }
            },

            {
                // 以下loader只会匹配一个
                // 注意: 不能有两个配置处理同一种类型文件
                // 提升构建速度
                oneOf: [
                    {
                        // 处理css资源
                        test: /\.css$/,
                        use: [
                            miniCssExtractPlugin.loader,
                            // 将css整合到js中
                            'css-loader',
                            {
                                loader: 'postcss-loader'
                            }
                        ]
                    },
                    {
                        test: /\.js$/,
                        exclude: /node_modules/,
                        loader: 'babel-loader',
                        options: {
                            // 预设: 指示 babel 做怎样的兼容处理
                            // presets: ['@babel/preset-env']
                            presets: [
                                [
                                    '@babel/preset-env',
                                    {
                                        // 按需加载
                                        useBuiltIns: 'usage',
                                        // 指定 core-js 版本
                                        corejs: {
                                            version: 3
                                        },
                                        // 指定兼容性做到哪个版本的浏览器
                                        targets: {
                                            chrome: '60',
                                            firefox: '60',
                                            ie: '9',
                                            safari: '10',
                                            edge: '17'
                                        }
                                    }
                                ]
                            ]
                        }
                    },

                    {
                        // 处理图片资源
                        test: /\.(jpg|png|gif)$/,
                        loader: 'url-loader',
                        options: {
                            limit: 5 * 1024,
                            name: '[hash:10].[ext]',
                            // 关闭es6模块
                            esMoudle: false,
                            outputPath: 'imgs'
                        }
                    },
                    {
                        // 处理html的img资源
                        test: /\.html$/,
                        loader: 'html-loader',

                    },
                    {
                        // 处理其他资源
                        exclude: /\.(css|less|js|html|jpg|png|gif)/,
                        loader: 'file-loader',
                        options: {
                            name: '[contenthash:10].[ext]',
                            outputPath: 'media'
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            // 压缩html
            minify: {
                // 移除空格
                collapseWhitespace: true,
                // 移除注释
                removeComments: true
            }
        }),
        new miniCssExtractPlugin({
            //对输出的css文件进行重命名
            filename: 'css/built.[contenthash:10].css'
        }),
        // 压缩css
        new optimizeCssAssetsWebpackPlugin()
    ],
    mode: 'development', // 开发模式
    devServer: {
        contentBase: resolve(__dirname, 'build'),
        compress: true,
        port: 3000,
        open: true,
        // 开启 HMR 功能
        // 当修改了webpack配置,新配置想生效,重启webpack服务
        hot: true,
    },
    devtool: 'eval-source-map'
}

你可能感兴趣的:(webpack 性能优化)