《Webpack5 核心原理与应用实践》学习笔记-> webpack性能优化技巧

简介: 《Webpack5 核心原理与应用实践》学习笔记-> webpack性能优化技巧


之前讲的是构建性能,这里是细粒度更高的性能优化,主要是还是体现在构建速度提升上,之前主要是对标生产环境,这里主要是对标开发环境。


使用最新版


使用最新版的webpacknode,新版本对比旧版本一定是更优的,没有谁说越更新越菜鸡的吧,新版本的更新不一定体现在性能优化上,还有会有新特性的增加。


但是需要注意的是不要盲目升级,例如新版本做了破坏性的变更,使用的插件或依赖不支持新版本的特性,等等一些问题都是需要考虑的。


新版本的更新一定是要了解新版本增加了什么特性,这些特性对于项目是否有影响,影响的强度是否能承受等,考虑好升级带来的利弊,再确定是否需要升级。


下面就是新版本的一些特性讲解了。


lazyCompilation


Webpack 5.17.0 之后引入实验特性 lazyCompilation,用于实现 entry 或异步引用模块的按需编译。


在以前如果webpack配置entry是多入口的情况,那么编译时是会将所有的都进行编辑,实际上这些入口你可能只会用到一到两个,其他的你根本就用不上,这种情况不仅浪费构建时间,同时也耗费内存,lazyCompilation的出现就是解决这个问题的,用法草鸡简单:


module.exports = {
    // 忽略其他配置
    experiments: {
        lazyCompilation: true
    }
}

它的作用是如果你定义的entry没有被访问,或者使用异步加载模块(const xxx = import('./xxx.js'))的方式,那么这些模块不会立即被构建,而是在你实际请求到这个模块的时候才会进行构建。


注意:这个不是懒加载,可以理解为懒构建,很明显这个功能不是提供给生产环境使用的,同时这个功能也是实验性功能,后面可能会发生较大的改动,建议使用该功能的锁定版本。


此外,lazyCompilation 支持如下参数:


  • backend: 设置后端服务信息,一般保持默认值即可;
  • entries:设置是否对 entry 启动按需编译特性;
  • imports:设置是否对异步模块启动按需编译特性;
  • test:支持正则表达式,用于声明对那些异步模块启动按需编译特性。


约束 Loader 执行范围


loader都打交道很长时间了,作用就是解析各种不同类型的文件,但是往往我们在使用一些第三方库的时候,库的作者都替我们把资源编译好了,我们如果再去解析就是在浪费性能了。


例如在node_modules下面,我们可以看到所以我们使用到的第三方依赖库,node_modules也是动辄上百兆。


但是通常情况下我们是不需要对node_modules下的文件进行编译的,所以我们可以使用module.rules.exclude排除掉node_modules下的编译:


module.exports = {
    module: {
        rules: [
            {
                test: /.js$/,
                exclude: /node_modules/,
                use: ["babel-loader"],
            },
        ],
    },
}

使用这个属性webpack看到是这个文件是这个目录下面的就会直接跳过,也就不会触发对应的loader的处理。


这里的属性值可以是字符串正则表达式数组函数condition


一般看到exclude都会想到配套的includeinclude的使用方法和exclude相同,作用相反,同时exclude优先级高于include:


module.exports = {
    module: {
        rules: [
            {
                test: /.js$/,
                exclude: /node_modules/,
                include: /node_modules/, // 无效
                use: ["babel-loader"],
            },
        ],
    },
}

使用 noParse 跳过文件编译


很多npm的库作者已经帮你提前编译好库的内容了,一般都在 node_modules/lib/dist下面,这个时候我们就不需要再二次编译了:


module.exports = {
    module: {
        noParse: /lodash|vue/,
    },
};

这里需要注意的是并不是所有库的作者都给你提供了编译后的资源,需要自行确认,其次由于跳过了编译,无法发现包中的错误,也无法标记导出值。


开发模式禁用产物优化


webpack默认提供了很多产物优化方案,但是这些都是需要算力支持的,在开发环境中我们其实并不需要关系这些优化的东西,只有在生产环境中为了减少包的体积我们才需要,因此,开发模式下建议关闭这一类优化功能,如下:


  • 确保 mode='development'mode = 'none',关闭默认优化策略;
  • optimization.minimize 保持默认值或 false,关闭代码压缩;
  • optimization.concatenateModules 保持默认值或 false,关闭模块合并;
  • optimization.splitChunks 保持默认值或 false,关闭代码分包;
  • optimization.usedExports 保持默认值或 false,关闭 Tree-shaking 功能;


最终,建议开发环境配置如:


module.exports = {
  mode: "development",
  optimization: {
    removeAvailableModules: false,
    removeEmptyChunks: false,
    splitChunks: false,
    minimize: false,
    concatenateModules: false,
    usedExports: false,
  },
};

最小化 watch 监控范围


watchnpx webpack --watch命令)会持续监听文件是否发生改变,如果发生改变会就执行rebuild,但是往往很多文件我们项目持续到结束都不会发生修改,例如node_modules下的文件(万恶之首,又不能干掉,哈哈哈),所以我们需要对他取消监控:


module.exports = {
    watchOptions: {
        ignored: /node_modules/
    },
};

跳过 tseslint 检查


上面讲的都是怎么减少构建的内容来提升性能,但是还有性能点可能不在编译时,还有运行时(应该是开发时),tseslint在开发时都会进行检查,ts做类型推导,eslint做代码检查,这些都是需要吃算力的。


对于ts可以使用fork-ts-checker-webpack-plugin插件来将类型推导放到子进程中执行:


const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
module.exports = {
    module: {
        rules: [{
            test: /.ts$/,
            use: [
                {
                    loader: 'ts-loader',
                    options: {
                        // 设置为“仅编译”,关闭类型检查
                        transpileOnly: true
                    }
                }
            ],
        }, ],
    },
    plugins:[
        // fork 出子进程,专门用于执行类型检查
        new ForkTsCheckerWebpackPlugin()
    ]
};

对于eslint可以使用eslint-webpack-plugin代替eslint-loader


const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
    plugins: [
        new ESLintPlugin(options)
    ],
};

个人更推荐使用ide的插件或其他附件功能实现他们的特性,例如WebStorm对于上面两者的检测是自带的,当然vscode也是有对应的插件。


慎用 source-map


source-map是很消耗性能的一个东东,但是呢在开发环境中还是需要的,生产环境中是不需要有的,所以建议:


  • 开发环境使用 eval ,确保最佳编译速度;
  • 生产环境使用 source-map,获取最高质量。


source-map的属性值在之前的文章有讲过,所以这里就没有详细的。


设置 resolve 缩小搜索范围


resolve.extensions


这个属性让我们在使用importrequire可以忽略后缀,例如:import('./a'),找到的可能是./a.js./a.json./a.wasm./a/index.js./a/index.json./a/index.wasm、 但是需要做到这些程序还是需要做很多推导工作的。


上面列举的这些都是webpack默认支持的,我们可以使用这个属性扩展我们自己的想要的,例如ts,但是不宜过多,同时可以指定文件后缀名来跳过解析。


resolve.modules


这个属性用来告诉 webpack 解析模块时应该搜索的目录,默认的情况下是从根目录下寻找node_modules目录,如果没找到就往上层找,直到全局。


一般情况下,一个项目都是控制node_modules的范围的,所以这个功能实用性不高,建议关闭:


const path = require('path');
module.exports = {
    resolve: {
        modules: [path.resolve(__dirname, 'node_modules')],
    },
};

resolve.mainFiles


这个属性其实和resolve.extensions有点对应,import('./a')如果不带后缀其实就是一个目录,但是这种情况下webpack是要找到对应的文件的,所以这里对应的文件名就是通过这个属性来配置:


module.exports = {
    resolve: {
        mainFiles: ['index'],
    },
};

默认情况下是index,所以上面resolve.extensions属性中就会出现index.xxx了,这里告诉这个属性当然是希望能尽量减少对这个属性的配置。


总结


webpack构建性能这一块一直都被诟病,所以这一块也是一个挑战,对于性能优化建议先使用性能分析工具,来分析性能瓶颈,再通过对应的手段来进行性能优化。


目录
相关文章
|
2月前
|
缓存 前端开发 算法
Webpack 进阶:深入理解其工作原理与优化策略
Webpack 进阶:深入理解其工作原理与优化策略
37 2
|
4月前
|
自然语言处理 JavaScript 前端开发
webpack 的热更新是如何做到的?原理是什么?
webpack 的热更新是如何做到的?原理是什么?
37 0
|
4月前
|
JSON 监控 测试技术
《Webpack5 核心原理与应用实践》学习笔记-> 提升插件健壮性
《Webpack5 核心原理与应用实践》学习笔记-> 提升插件健壮性
49 0
|
4月前
|
缓存 前端开发 API
《Webpack5 核心原理与应用实践》学习笔记-> webpack插件开发基础
《Webpack5 核心原理与应用实践》学习笔记-> webpack插件开发基础
55 0
|
4月前
|
前端开发 JavaScript 测试技术
《Webpack5 核心原理与应用实践》学习笔记-> webpack的loader运行与调试
《Webpack5 核心原理与应用实践》学习笔记-> webpack的loader运行与调试
33 0
|
4月前
|
存储 缓存 JavaScript
《Webpack5 核心原理与应用实践》学习笔记-> webpack的loader开发技巧
《Webpack5 核心原理与应用实践》学习笔记-> webpack的loader开发技巧
43 1
|
4月前
|
缓存 监控 JavaScript
《Webpack5 核心原理与应用实践》学习笔记-> webpack极致性能优化
《Webpack5 核心原理与应用实践》学习笔记-> webpack极致性能优化
31 1
|
JavaScript 前端开发
WEBPACK简单学习笔记
WEBPACK简单学习笔记
128 0
WEBPACK简单学习笔记
|
1月前
|
JavaScript 前端开发
webpack成长指北第9章---webpack如何对icon字体进行打包
webpack成长指北第9章---webpack如何对icon字体进行打包
27 1
|
1月前
|
前端开发 JavaScript
webpack成长指北第7章---webpack的css\less\scss样式打包
webpack成长指北第7章---webpack的css\less\scss样式打包
41 0