美文网首页
webpack 性能优化

webpack 性能优化

作者: zhudying | 来源:发表于2023-11-27 11:10 被阅读0次
    1. oneOf

    对于某种类型的文件,webpack 会从上至下匹配所有的 loader,也就是,所有的 loader 都会去处理这种文件。但是,webpack 这种匹配方式在有些场景反而影响了效率。比如说,一个 webpack 只有 babel-loader 处理了 js 文件,那么当它匹配完了以后,完全没有必要再匹配一些针对 css 文件的 loader。所以,这就是为什么,我们使用 oneOf,匹配到了,立刻跳出循环。因此 oneOf 可以优化构建速度

        module: {
                rules: [
                    {
                        oneOf: [
                            {
                                test: /\.(png|jpg|jpeg)$/,
                                use: ['file-loader'],
                                exclude: /(node_modules|bower_components|dist)/
                            }
                        ]
                    }
               ]
          }
    
    2. babel 缓存

    babel 缓存的意思是,浏览器第一次拿资源文件的时候,会从服务器上走 http 拉取,但是当刷新页面再次请求的时候,浏览器会直接从缓存(可以是内存,也可以是硬盘,自己配置)当中拿同名文件,因此省去了发送 http 请求拿资源的时间。

    3. 多进程打包

    业内有两种解决方案比较常用,一个是 thread-loader,一个是 happy-pack,但是 happy-pack 的维护者现在对这个库不再维护了,因此,推荐使用 thread-loader(多进程打包,不是线程)。

     {
                    rules:
                        [
                            {
                                test: /\.(js|jsx)$/,
                                exclude: /(node_modules|bower_components|dist)/,
                                use: [
                                    /**
                                     * 开启多进程打包,打开进程一般 600 ms,
                                     * 通信也有开销。
                                     */
                                    {
                                         loader: "thread-loader",
                                         options: {
                                             workers: 3
                                         }
                                    },
                                    {
                                        loader: "babel-loader",
                                        options: {
                                            cacheDirectory: true
                                        }
                                    }
    
                                ]
                            }
                       ]
                  }
    

    需要在 options 字段下配置 workers 也就是进程的个数。注意 thread-loader 并不是开的进程数越多就越好,假如你的 js 代码量很少,开多核反而会降低性能,这是因为打开进程有比较大的开销(600 ms 左右),进程间通信也有开销。

    4. tree shaking

    tree shaking 的意思是你的项目里面有些代码可能是从来没被引入的,比方说你定义了一个函数但是你从来没有引用到它。这个时候 tree shaking 可以在打包的时候帮你干掉这些代码。

    前提
    使用 ES6 module
    production 默认开启

    需要配合 package.json 里面 sideEffects: ["*.css"] 一同使用,否则可能会干掉打包好的 css 文件。

    5. code split

    code split 直接从字面上理解即可,就是代码分割技术,因为 html 里面的静态资源文件是并行加载的,即发送 http 请求并且把文件放到内存里这个过程是并行的。所以适当的代码分割技术可以让我们的项目运行性能更好。另外,代码分割也可以帮助我们在多路由的场景进行性能优化。
    多入口

    entry: {
      main: './src/js/index.js', // 入口1
      test: './src/js/test.js'  // 入口2
    },
    output: {
        // [name]是webpack命名规则,使用chunk的name作为输出的文件名。
        // 什么是chunk?打包的资源就是chunk,输出出去叫bundle。
        // chunk的name是啥呢? 比如: entry中xxx: "./src/xxx.js", name就是xxx。注意是前面的xxx,和文件名无关。
        // 为什么需要这样命名呢?如果还是之前写法main.js,那么打包生成两个js文件都会叫做main.js会发生覆盖。(实际上会直接报错的)
      filename: 'js/[name].[contenthash:10].js'
      path: resolve(__dirname, 'build')
    }
    // optimization 代码分割配置
    optimization: {
      splitChunks:{
        chunks: 'all' // 对所有模块都进行分割
    // 以下是默认值
          // minSize: 20000, // 分割代码最小的大小
          // minRemainingSize: 0, // 类似于minSize,最后确保提取的文件大小不能为0
          // minChunks: 1, // 至少被引用的次数,满足条件才会代码分割
          // maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
          // maxInitialRequests: 30, // 入口js文件最大并行请求数量
          // enforceSizeThreshold: 50000, // 超过50kb一定会单独打包(此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)
          // cacheGroups: { // 组,哪些模块要打包到一个组
          //   defaultVendors: { // 组名
          //     test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
          //     priority: -10, // 权重(越大越高)
          //     reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
          //   },
          //   default: { // 其他没有写的配置会使用上面的默认值
          //     minChunks: 2, // 这里的minChunks权重更大
          //     priority: -20,
          //     reuseExistingChunk: true,
          //   },
          // },
          // 修改配置
          // cacheGroups: {
            // 组,哪些模块要打包到一个组
            // defaultVendors: { // 组名
            //   test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
            //   priority: -10, // 权重(越大越高)
            //   reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
            // },
    
      }
    }
    

    上面这块配置可以把你做两件事:

    node_modules 中代码单独打包成一个 chunk
    自动分析多入口 chunk 中,有没有公共文件,如果有会打包成一个单独 chunk

    6. 懒加载和预加载

    懒加载
    使用 import 函数,同上。回调函数中使用 import 函数。

    document.getElementById('btn').onclick = () => {
      import('./test').then(({mul})=> {
        console.log(mul(4,5))
      })
    )
    

    预加载

     // eslint会对动态导入语法报错,需要修改eslint配置文件
      // webpackChunkName: "math":这是webpack动态导入模块命名的方式
      // "math"将来就会作为[name]的值显示。
    // webpackPrefetch 开启预加载
    document.getElementById('btn').onclick = () => {
      import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({mul})=> {
        console.log(mul(4,5))
      })
    )
    
    7. pwa

    适用情景,我们希望在用户离线时也可以访问我们的页面。对于 webpack 而言,我需要使用的是 workbox-webpack-plugin。配置成功以后,浏览器在离线后可以从 service-worker 里拉取静态资源。

    // webpack
    plugins: [
      new WorkboxWebpackPlugin.GenerateSW({ 
        // 删除旧的 serviceWorker 且快速启动
        clientsClaim: true,
        skipWaiting: true
      })
    ]
    
    // js
    if('serviceWorker' in navigator){
      window.addEventListenr('load', ()=>{
        navigator.serviceWorker.register.register('./service-worker.js')
        .then(()=>{
          console.log('sw 注册成功了')
        })
        .catch(()=>{
          console.log('sw 注册失败')
        })
      })
    }
    
    8. CDN

    CDN称之为内容分发网络(Content Delivery Network或Content Distribution Network,缩写:CDN), 它是指通过相互连接的网络系统,利用最靠近每个用户的服务器; 更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户; 来提供高性能、可扩展性及低成本的网络内容传递给用户;

    在开发中,我们使用CDN主要是两种方式:
    方式一:打包的所有静态资源,放到CDN服务器, 用户所有资源都是通过CDN服务器加载的;
    方式二:一些第三方资源放到CDN服务器上

    9. JS代码压缩

    Terser

     optimization: {
         minimize: true, // 是否要启用压缩,默认情况下,生产环境会自动开启
         minimizer: [
                    // 压缩时使用的插件,可以有多个
             new TerserPlugin(), // js压缩插件
             new OptimizeCSSAssetsPlugin() // css压缩插件
       ],
    }
    
    10. gizp

    浏览器发送请求时,会在请求头中设置Accept-Encoding:gzip,deflate,br。表明浏览器支持gzip。服务器收到浏览器发送的请求之后,判断浏览器是否支持gizp,如果支持gzip,则向浏览器传送压缩过的内容,不支持则向浏览器发送未经压缩的内容。一般情况下,浏览器和服务器都支持gzip,响应头返回包含content-encoding:gzip。浏览器接收到服务器的响应之后判断内容是否被压缩,如果被压缩则解压缩显示页面内容
    使用compression-webpack-plugin插件对打包结果进行预压缩,可以移除服务器的压缩时间。

        const CmpressionWebpackPlugin = require("compression-webpack-plugin")
        module.exports = {
          plugins: [
            new CmpressionWebpackPlugin({
              // filename: "[file].gzip"
              test: /\.js/, //针对需要预压缩的文件
              minRatio: 0.5 //压缩比率
            })
          ]
        };
    
    

    相关文章

      网友评论

          本文标题:webpack 性能优化

          本文链接:https://www.haomeiwen.com/subject/cmjdvdtx.html