• Webpack构建速度优化


    前言

    当我们的项目越来越大,webpack的配置项越来越多时,构建速度会越来越慢,所以我们需要通过一些配置来提高webpack的构建速度。

    目录
    • 缩小范围
    • noParse
    • IgnorePlugin
    • 优化 resolve 配置
    • externals
    • 缓存

    缩小范围

    在配置 loader 的时候,我们需要更精确的去指定 loader 的作用目录或者需要排除的目录,通过使用 includeexclude 两个配置项,可以实现这个功能,常见的例如:

    • include:符合条件的模块进行解析
    • exclude:排除符合条件的模块,不解析,优先级更高

    这样一来,一开始构建,我们就能去除一些选项,比如,在使用babel-loader的时候

    {
      test: /\.jsx?$/,
      use: [
        {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/react'],
            plugins: [[require('@babel/plugin-proposal-decorators'), { legacy: true }]],
            cacheDirectory: true, // 启用缓存
          },
        },
      ],
      include: path.resolve(__dirname, 'src'),
      exclude: /node_modules/,
     },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    noParse

    对于我们引入的一些第三方包,比如jQuery,在这些包内部是肯定不会依赖别的包,所以根本不需要webpack去解析它内部的依赖关系,使用 noParse 进行忽略的模块文件中不会解析 importrequire 等语法

    参考webpack视频讲解:进入学习
    module:{
        noParse:/jquery|lodash/
    }
    
    • 1
    • 2
    • 3

    IgnorePlugin

    有很多的第三方包内部会做国际化处理,包含很多的语言包,而这些语言包对我们来说时没有多大用处的,只会增大包的体积,我们完全可以忽略掉这些语言包,从而提高构建效率,减小包的体积。

    用法

    • requestRegExp 表示要忽略的路径。
    • contextRegExp 表示要忽略的文件夹目录。
    new webpack.IgnorePlugin({ resourceRegExp, contextRegExp });
    
    • 1

    moment为例,首先找到moment中语言包所在的文件夹,然后在webpack配置文件中添加插件

    new webpack.IgnorePlugin(/./locale/, /moment/)
    
    • 1

    也可以写成

    new webpack.IgnorePlugin({
    resourceRegExp: /^\.\/locale$/,
    contextRegExp: /moment$/,
    }),
    
    • 1
    • 2
    • 3
    • 4

    这时候moment使用默认语言英语,如果要使用别的语言,可以手动引入需要使用的语言包。

    import moment from 'moment'
    import 'moment/locale/zh-cn'
    moment.locale('zh-CN')
    
    • 1
    • 2
    • 3

    优化 resolve 配置

    alias

    alias 用的创建 import 或 require 的别名,用来简化模块引用,项目中基本都需要进行配置。

    const path = require('path')
    {
      ...
      resolve:{
        // 配置别名
        alias: {
          '~': resolve('src'),
          '@': resolve('src'),
          'components': resolve('src/components'),
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    配置完成之后,我们在项目中就可以

    // 使用 src 别名 ~ 
    import '~/fonts/iconfont.css'
    
    // 使用 src 别名 @ 
    import '@/fonts/iconfont.css'
    
    • 1
    • 2
    • 3
    • 4
    • 5

    除此之外,因为一些第三方库,如react,我们在安装的时候,实际上已经安装好了它编译好的包,所以我们在这里可以直接指定别名路径

    alias: {
    react: path.resolve(
              dirname,
              '../node_modules/react/umd/react.production.min.js'
           ),
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    配合上noParse,在使用的时候,就无须在构建一遍react

    noParse: /react\.production\.min\.js$/,
    
    • 1
    extensions

    在webpack中,我们可以预先设定一些文件的扩展名

    webpack 默认配置

    const config = {
      //...
      resolve: {
        extensions: ['.js', '.json', '.wasm'],
      },
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果在编写的时候不带文件后缀,如

    import file from '../path/to/file';
    
    • 1

    webpack在解析的时候,就可以从我们设置的扩展名中从左往右进行判断

    需要注意的是:

    • 高频文件后缀名放前面;
    • 手动配置后,默认配置会被覆盖

    如果想保留默认配置,可以用 ... 扩展运算符代表默认配置,例如

    const config = {
      //...
      resolve: {
        extensions: ['.ts', '...'], 
      },
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    modules

    告诉 webpack 解析模块时应该搜索的目录,常见配置如下

    const path = require('path');
    
    // 路径处理方法
    function resolve(dir){
      return path.join(__dirname, dir);
    }
    
    const config = {
      //...
      resolve: {
         modules: [resolve('src'), 'node_modules'],
      },
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    告诉 webpack 优先 src 目录下查找需要解析的文件,会大大节省查找时间

    externals

    externals 配置选项提供了「从输出的 bundle 中排除依赖」的方法,因为我们在每次打包的时候,有些依赖的变动很小,所以我们可以不选择不把依赖打包进去,而使用script标签的形式来加载他。

    比如react和react-dom,我们在页面中引入它

    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin="anonymous">script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin="anonymous">script>
    
    • 1
    • 2

    然后配置externals

    externals: {
         react: 'React',
         'react-dom': 'ReactDOM',
    },
    
    • 1
    • 2
    • 3
    • 4

    注意 这里配置项的键值是package.json文件中依赖库的名称,而value值代表的是第三方依赖编译打包后生成的js文件,然后js文件执行后赋值给window的全局变量名称

    我们可以通过下面的方法,来找这个全局变量

    上面所说的js文件就是要用CDN引入的js文件。那么可以通过浏览器打开CDN链接,选择没有压缩过的那种(不带min),比如

    https://cdn.bootcdn.net/ajax/libs/react/18.2.0/cjs/react-jsx-dev-runtime.development.js
    
    • 1

    然后在它的源代码里面找,类似与导出赋值这种代码

    缓存

    webpack5提供了非常强大的持久化缓存的能力,开箱即用

    catch缓存

    webpack5新加了缓存项配置,具体如下

    默认缓存路径在node_modules/.cache/webpack

    // 缓存配置 
        cache: {
          type: 'filesystem',  // 开启持久化缓存
          version: createEnvironmentHash(env.raw),  // 参考react脚手架的配置 可以记录打包缓存的版本
          cacheDirectory: path.appWebpackCache, // 缓存路径
          store: 'pack',
          // 构建依赖,如果有文件修改,则重新执行打包流程
          buildDependencies: {
            defaultWebpack: ['webpack/lib/'],
            config: [__filename],
          },
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    babel-loader 开启缓存

    abel 在转译 js 过程中时间开销比价大,将 babel-loader 的执行结果缓存起来,重新打包的时候,直接读取缓存

    缓存位置: node_modules/.cache/babel-loader

    配置

    //支持转义ES6/ES7/JSX
    {
      test: /\.jsx?$/,
      use: [
        {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/react'],
            plugins: [
              [
                require('@babel/plugin-proposal-decorators'),
                { legacy: true },
              ],
            ],
            cacheDirectory: true, // 启用缓存
          },
        },
      ],
      include: path.resolve(__dirname, 'src'),
      exclude: /node_modules/,
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    cache-loader

    缓存一些性能开销比较大的 loader 的处理结果, 缓存位置:node_modules/.cache/cache-loader

    配置 cache-loader

    const config = {
     module: { 
        // ...
        rules: [
          {
            test: /.(s[ac]|c)ss$/i, //匹配所有的 sass/scss/css 文件
            use: [
              // 'style-loader',
              MiniCssExtractPlugin.loader,
              'cache-loader', // 获取前面 loader 转换的结果
              'css-loader',
              'postcss-loader',
              'sass-loader', 
            ]
          }, 
          // ...
        ]
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    dll动态链接(已弃用)

    在 webpack5.x 中已经不建议使用这种方式进行模块缓存,因为其已经内置了更好体验的 cache 方法

    hard-source-webpack-plugin

    hard-source-webpack-plugin 为模块提供了中间缓存,重复构建时间大约可以减少 80%,但是在 webpack5 中已经内置了模块缓存,不需要再使用此插件

  • 相关阅读:
    ffmpeg基础五:单独解码裸流aac或MP3或H264
    排序算法模板
    软件测试和调试有什么区别?
    ESP8266 如何使用 GPIO13 & GPIO15 进行 UART0 通信?
    济南槐荫吴家堡 国稻种芯·中国水稻节:山东稻出黄河大米
    SQL常见题型总结
    7、迁移学习
    图扑软件用数据可视化形式告诉你,楼宇建设如何数字化转型
    Jmeter常用函数用法详解
    vue-element-admin总结(全程复制不会剁手吧你!)
  • 原文地址:https://blog.csdn.net/gogo2027/article/details/127783574