webpack提升构建速度

目录

    • 配置优化
      • 减少 `resolve` 的解析
      • 把 loader 应用的文件范围缩小
      • 减少 plugin 的消耗
      • 选择合适的 devtool
    • 使用工具
      • thread-loader
      • DLLPlugin
    • 流程优化
      • 拆分构建步骤
      • 拆分项目代码
    • 版本更新
    • 总结

在这里插入图片描述

前端项目随着时间推移和业务发展,页面可能会越来越多,或者功能和业务代码会越来越多,又或者依赖的外部类库会越来越多,这个时候原本不足为道的 webpack 构建时间消耗就会慢慢地进入我们的视野。

构建消耗的时间变长了,如果是使用 CI 服务来做构建,大部分情况下我们无需等待,其实影响不大。但是本地的 webpack 开发环境服务启动时的速度和我们日常开发工作息息相关,在一些性能不是特别突出的设备上(例如便携式笔记本等等),启动时的长时间等待可能会让你越来越受不了。

博主亲身经历的一个项目,使用 webpack 构建的时长可以达到 6 分钟左右,这种场景下,就算用 CI 服务,在遇见需要紧急发布修复问题时,也会让人很抓狂。

也许某一天你负责的项目也会到了需要优化 webpack 构建性能的时候,所以这一章节我们来聊聊如何提升 webpack 的构建速度。

提升 webpack 构建速度本质上就是想办法让 webpack 少干点活,活少了速度自然快了,尽量避免 webpack 去做一些不必要的事情,记得这个主要方向,后续的针对构建速度的优化都是围绕着这一方向展开。

配置优化

减少 resolve 的解析

在前边第三小节我们详细介绍了 webpack 的 resolve 配置,如果我们可以精简 resolve 配置,让 webpack 在查询模块路径时尽可能快速地定位到需要的模块,不做额外的查询工作,那么 webpack 的构建速度也会快一些,下面举个例子,介绍如何在 resolve 这一块做优化:

resolve: {
  modules: [
    path.resolve(__dirname, 'node_modules'), // 使用绝对路径指定 node_modules,不做过多查询
  ],

  // 删除不必要的后缀自动补全,少了文件后缀的自动匹配,即减少了文件路径查询的工作
  // 其他文件可以在编码时指定后缀,如 import('./index.scss')
  extensions: [".js"], 

  // 避免新增默认文件,编码时使用详细的文件路径,代码会更容易解读,也有益于提高构建速度
  mainFiles: ['index'],
},

上述是可以从配置 resolve 下手提升 webpack 构建速度的配置例子。

我们在编码时,如果是使用我们自己本地的代码模块,尽可能编写完整的路径,避免使用目录名,如:import './lib/slider/index.js',这样的代码既清晰易懂,webpack 也不用去多次查询来确定使用哪个文件,一步到位。

把 loader 应用的文件范围缩小

我们在使用 loader 的时候,尽可能把 loader 应用的文件范围缩小,只在最少数必须的代码模块中去使用必要的 loader,例如 node_modules 目录下的其他依赖类库文件,基本就是直接编译好可用的代码,无须再经过 loader 处理了:

rules: [ 
  {
    test: /\.jsx?/,
    include: [ 
      path.resolve(__dirname, 'src'), 
      // 限定只在 src 目录下的 js/jsx 文件需要经 babel-loader 处理
      // 通常我们需要 loader 处理的文件都是存放在 src 目录
    ],
    use: 'babel-loader',
  },
  // ...
],

如上边这个例子,如果没有配置 include,所有的外部依赖模块都经过 Babel 处理的话,构建速度也是会收很大影响的。

减少 plugin 的消耗

webpack 的 plugin 会在构建的过程中加入其它的工作步骤,如果可以的话,适当地移除掉一些没有必要的 plugin。

区分 mode 会让 webpack 的构建更加有针对性,更加高效。例如当 mode 为 development 时,webpack 会避免使用一些提高应用代码加载性能的配置项,如 UglifyJsPlugin,ExtractTextPlugin 等,这样可以更快地启动开发环境的服务,而当 mode 为 production 时,webpack 会避免使用一些便于 debug 的配置,来提升构建时的速度,例如极其消耗性能的 Source Maps 支持。

选择合适的 devtool

前边的内容我们提过,devtool 可以用于配置 webpack 构建出来的 sourcemap 相关的内容,输出详细的 sourcemap 是相当影响 webpack 的构建速度的,所以这里需要做一个取舍,在构建生产环境代码时不输出 sourcemap,而开发环境时一般选用 eval-cheap-source-map 来确保 sourcemap 基本可用的情况下还有着不错的构建速度。

使用工具

thread-loader

thread-loader 是官方提供的一个可以利用多进程加速 loader 执行的 loader,如果项目中 loader 的运行处理占用比较多的时间,例如 babel 或者 typescript 解析和编译的代码量很大,或者 image—webpack-loader 处理图片耗时比较久,那么可以尝试使用 thread-loader 来提速。下边是基础使用的例子:

const threadLoader = require('thread-loader');

const threadLoaderOptions = {
  // 这里填写对应 thread-loader 的配置
  // 预热时的配置和使用 thread-loader 时的配置要一致,所以这里统一使用一个变量来管理
  // 配置参考官方文档:https://github.com/webpack-contrib/thread-loader
}

// thread-loader 的预热,可以加速启动
threadLoader.warmup(threadLoader, [
  'babel-loader',
  // 更多其他需要使用 thread-loader 的 loader
]);

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.jsx?/, // 匹配文件路径的正则表达式,通常我们都是匹配文件类型后缀
        use: [
          // 在你需要的 loader 前加上 thread-loader
          {
            loader: 'thread-loader',
            options: threadLoaderOptions
          },
          {
            loader: 'babel-loader', // 指定使用的 loader
            options: {
              presets: ['@babel/preset-env'],
            },
          },
        ]
      },
      // ...
    ],
}

值得注意的是,由于 thread-loader 新启动进程也需要耗时,所以如果不是运算特别多的 loader 使用 thread-loader 的话可能速度会更慢。

DLLPlugin

DLLPlugin 是 webpack 官方提供的一个插件,也是用来分离代码的,和 optimization.splitChunks有异曲同工之妙,之所以把 DLLPlugin 放到 webpack 构建性能优化这一部分,是因为它的配置相对繁琐,如果项目不涉及性能优化这一块,基本上使用 optimization.splitChunks 即可。

我们来看一下 DLLPlugin 如何使用,使用这个插件时需要额外的一个构建配置,用来打包公共的那一部分代码,举个例子,假设这个额外配置是 webpack.dll.config.js

module.exports = {
  name: 'vendor',
  entry: ['react', 'react-dom'], // 这个例子我们打包 react & react-dom 作为公共类库

  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "vendor.js",
    library: "vendor_[hash]" // 打包后对外暴露的类库名称
  },

  plugins: [
    new webpack.DllPlugin({
      name: 'vendor_[hash]',
      path: path.resolve(__dirname, "dist/manifest.json"), // 使用 DLLPlugin 在打包的时候生成一个 manifest 文件
    })
  ],
}

然后就是我们正常的应用构建配置,在那个的基础上添加两个一个新的 webpack.DllReferencePlugin 配置:

module.exports = {
  plugins: [
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, 'dist/manifest.json'), 
      // 指定需要用到的 manifest 文件,
      // webpack 会根据这个 manifest 文件的信息,分析出哪些模块无需打包,直接从另外的文件暴露出来的内容中获取
    }),
  ],
}

在构建的时候,我们需要优先使用 webpack.dll.config.js 来打包,如 webpack --config webpack.dll.config.js --mode production,构建后生成公共代码模块的文件 vendor.jsmanifest.json,然后再进行应用代码的构建。

你会发现构建结果的应用代码中不包含 react 和 react-dom 的代码内容,这一部分代码内容会放在 vendor.js 这个文件中,而你的应用要正常使用的话,需要在 HTML 文件中按顺序引用这两个代码文件,如:

<script src="vendor.js"></script>
<script src="main.js"></script>

作用是不是和 optimization.splitChunks 很相似,但是有个区别,DLLPlugin 构建出来的内容无需每次都重新构建,后续应用代码部分变更时,你不用再执行配置为 webpack.dll.config.js 这一部分的构建,沿用原本的构建结果即可,所以相比 optimization.splitChunks,使用 DLLPlugin 时,构建速度是会有显著提高的。

但是很显然,DLLPlugin 的配置要麻烦得多,并且需要关心你公共部分代码的变化,当你升级 lodash(即你的公共部分代码的内容变更)时,要重新去执行 webpack.dll.config.js 这一部分的构建,不然沿用的依旧是旧的构建结果,使用上并不如 optimization.splitChunks 来得方便。这是一种取舍,根据项目的实际情况采用合适的做法。

还有一点需要注意的是,html-webpack-plugin 并不会自动处理 DLLPlugin 分离出来的那个公共代码文件,我们需要自己处理这一部分的内容,可以考虑使用 add-asset-html-webpack-plugin,关于这一个的使用就不讲解了,详细参考官方的说明文档:使用 add-asset-html-webpack-plugin。

流程优化

拆分构建步骤

这里拿图片的压缩作为一个例子讲解,我们在前边的小节提到图片可以使用 webpack 的 image-webpack-loader 来压缩图片,在对 webpack 构建性能要求不高的时候,这样是一种很简便的处理方式,但是要考虑提高 webpack 构建速度时,这一块的处理就得重新考虑一下了,思考一下是否有必要在 webpack 每次构建时都处理一次图片压缩。

我们可以直接使用 imagemin 来做图片压缩,编写简单的命令即可。然后使用 pre-commit 这个类库来配置对应的命令,使其在 git commit 的时候触发,并且将要提交的文件替换为压缩后的文件。

这样提交到代码仓库的图片就已经是压缩好的了,以后在项目中再次使用到的这些图片就无需再进行压缩处理了,image-webpack-loader 也就没有必要了。

使用同样的思路去考虑其他构建步骤,是否有必要在每次构建时处理,可以考虑用 git hooks 或者工作流的一些机制来触发一些构建工作,来减少 webpack 的构建压力。

拆分项目代码

webpack 的构建性能优化是比较琐碎的工作,当我们需要去考虑 webpack 的构建性能问题时,往往面对的是项目过大,涉及的代码模块过多的情况。在这种场景下你单独做某一个点的优化其实很难看出效果,你可能需要从我们上述提到的多个方面入手,逐一处理,验证,有些时候你甚至会觉得吃力不讨好,投入产出比太低了,这个时候我们可以考虑换一个角度来思考我们遇到的问题。

例如,拆分项目的代码,根据一定的粒度,把不同的业务代码拆分到不同的代码库去维护和管理,这样子单一业务下的代码变更就无须整个项目跟着去做构建,这样也是解决因项目过大导致的构建速度慢的一种思路,并且如果处理妥当,从工程角度上可能会给你带来其他的一些好处,例如发布异常时的局部代码回滚相对方便等等。

版本更新

官方发布的 webpack 4.0 更新日志来看,webpack 4.0 版本做了很多关于提升构建性能的工作,我觉得比较重要的改进有这么几个:

  • AST 可以直接从 loader 直接传递给 webpack,避免额外的解析,对这一个优化细节有兴趣的可以查看这个 PR。
  • 使用速度更快的 md4 作为默认的 hash 方法,对于大型项目来说,文件一多,需要 hash 处理的内容就多,webpack 的 hash 处理优化对整体的构建速度提升应该还是有一定的效果的。
  • Node 语言层面的优化,如用 for of 替换 forEach,用 MapSet 替换普通的对象字面量等等,这一部分就不展开讲了,有兴趣的同学可以去 webpack 的 PRs 寻找更多的内容。
  • 后续更新的版本把 uglifyjs-webpack-plugin 换成了 terser-webpack-plugin,可以更好地针对 ES6 的代码进行处理。

更多关于性能优化的 webpack 迭代可以查看官方的 release 文档:webpack release,搜索 performance 关键字就好。

webpack 5 的大版本,针对性能优化还有更棒的持久化缓存方案推出,让每一次的构建打包可以向我们的 webpack-dev-server 一样,只针对变化部分做增量构建,可以极大地提高构建性能,这个值得期待一下,有兴趣的同学可以使用 webpack 5 beta 版本来测试一下。

总结

本文我们首先介绍了如何从多个配置优化的方式来提高 webpack 的构建速度:

  • 减少 resolve 的解析
  • 把 loader 应用的文件范围缩小
  • 减少 plugin 的消耗
  • 选择合适的 devtool

在必要的时候,我们可以使用 thread-loader 和 DLLPlugin 来帮助我们进一步优化 webpack 的构建性能,但是从另外的角度考虑,在不过分依赖 webpack 构建的情况下,我们可以从流程优化上着手,如提交代码前就压缩图片,拆分构建的代码库等,以此来减少 webpack 构建的工作量。

同时,更新 Node 版本和 webpack 版本都有助于让我们的构建变得更快,勤劳的程序员们一直在优化代码库的性能,别辜负了他们的努力,尽可能让构建跑在最新的运行环境上吧。

你工作中遇到的项目是否有哪些部分是可以考虑使用上述的优化方法来提升构建速度的?你是否有其他的一些构建优化的方法呢?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/134804.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

简单描述下微信小程序的相关文件类型以及微信小程序和uniapp的区别?

前言 微信小程序是一种基于微信平台的轻量级应用&#xff0c;其文件类型涵盖了不同用途的文件。了解这些文件类型能帮助开发者更好地构建小程序。 微信小程序是微信平台上的一种轻量级应用程序&#xff0c;为用户提供了一种便捷的方式来在微信生态系统内进行各种操作和获取服务…

MYSQL索引+常见的锁

一)联合索引: 1)定义:是给一张表上面的多个列增加索引&#xff0c;也就是说给表上面的多个列增加索引&#xff0c;供快速查询使用&#xff0c;当两个列的组合是唯一值时&#xff0c;联合索引是个不错的选择 联合索引和单个索引对比来讲&#xff0c;联合索引的所有索引项都会出现…

【左程云算法全讲7】二叉树基础

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于左程云算法课程进行的&#xff0c;每个知识点的修正和深入主要参考…

LeetCode(7)买卖股票的最佳时机【数组/字符串】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 121. 买卖股票的最佳时机 1.题目 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票…

Shell编程入门--概念、特性、bash配置文件

目录 一、Shell概念1.定义2.分类和使用场景2.1.分类和切换2.2.使用场景 3.特性3.1.文件描述符与输出重定向3.2.历史命令---history3.3.别名 --alias3.4.命令排序执行3.5.部分快捷键3.6.通配符置换 4.脚本规范5.脚本运行方式5.1.bash脚本执行5.2.bash脚本测试 二、bash配置文件1…

抢占全球30%碳化硅市场份额!英飞凌押注低碳化和数字化“新时代”

“未来十年将是低碳化和数字化‘双轮驱动’发展的时代。” 英飞凌科技全球高级副总裁及大中华区总裁、英飞凌科技大中华区电源与传感系统事业部负责人潘大伟在英飞凌2023年大中华区生态创新峰会上表示。 当前&#xff0c;“数字化低碳化”新趋势正在席卷和重塑着未来世界的千行…

【MySQL】初识数据库

目录 1.概念2.基本使用显示当前的数据库列表创建数据库使用数据库创建表向表中插入数据查看创建的表中的数据 3.SQL的分类4.存储引擎 1.概念 MySQL本质是基于C(mysql)S(mysqld)模式的一种网络服务。 mysqld&#xff1a;它是数据库的服务器端&#xff08;这是一个守护进程&…

SpringBoot代码生成器mapper model

Spring Boot 是一个由 Pivotal 团队提供的全新框架&#xff0c;设计目的是简化新 Spring 应用的初始搭建和开发过程。它采用特定的配置方式&#xff0c;使开发人员能够快速上手并构建基于 Spring 的应用程序。Spring Boot 提供了一套默认配置&#xff0c;包括 Spring、Spring M…

Mathtype公式自动转Word自带公式

Mathtype公式自动转Word自带公式 前言/word技巧探索过程参考资料&#xff08;有效与无效&#xff09;全自动方案/代码/教程 前言/word技巧 word公式 用ALT号可以输入简单latex显示公式&#xff1b;复杂度&#xff0c;需要引入latex包的不行&#xff1b;显示不出来的话按一下en…

C++ PCL点云配准源码实例

程序示例精选 C PCL点云配准源码实例 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《C PCL点云配准源码实例》编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易读。 学习与应用…

MATLAB中plot函数用法

目录 语法 说明 向量和矩阵数据 表数据 其他选项 示例 创建线图 绘制多个线条 根据矩阵创建线图 指定线型 指定线型、颜色和标记 在特定的数据点显示标记 指定线宽、标记大小和标记颜色 添加标题和轴标签 绘制持续时间并指定刻度格式 基于表绘制坐标 在一个轴…

vue,react虚拟dom

Virtual DOM 前言 在传统的Web开发中&#xff0c;直接操作真实的DOM通常是一个昂贵且低效的操作。为了解决这个问题&#xff0c;Virtual DOM&#xff08;虚拟DOM&#xff09;被引入为一个中间层&#xff0c;允许开发者在内存中进行操作&#xff0c;从而避免频繁且不必要的真实D…

MATLAB中Arrow 属性说明

目录 颜色和样式 位置 Arrow 属性是箭头的外观和行为。 Arrow 属性控制 Arrow 对象的外观和行为。通过更改属性值&#xff0c;可以修改箭头的特定方面。使用圆点表示法查询和设置属性。 ar annotation("arrow"); c ar.Color; ar.Color "red"; 颜色和…

下一批就是外包机器视觉公司兄弟们,机器视觉兄弟们可能还不知道,日结,灵活就业的兄弟们正在连夜找工作!

下一批就是外包机器视觉公司兄弟们&#xff0c;机器视觉兄弟们可能还不知道&#xff0c;日结&#xff0c;灵活就业的兄弟们正在连夜找工作&#xff01; 怀念十多年前打工的时候&#xff0c;那个人人脸上都有笑容&#xff0c;充满活力&#xff0c;充满希望的年代。 日结的机器视…

【教3妹学编程-算法题】Range 模块

3妹&#xff1a;哈哈哈哈哈哈哈哈 2哥 : 3妹看什么呢&#xff0c;笑的这么开森 3妹&#xff1a;2哥你快来看啊&#xff0c;成都欢乐谷的NPC模仿“唐僧”&#xff0c; 太搞笑了。 2哥 : 哦这个我也看到了&#xff0c;真的是唯妙唯肖&#xff0c;不能说像&#xff0c;只能说一模一…

Python之函数进阶-闭包原理

Python之函数进阶-闭包原理 闭包 自由变量&#xff1a;未在本地作用域中定义的变量&#xff0c;例如定义在内层函数外的外层函数的作用域中的变量闭包&#xff1a;就是一个概念&#xff0c;出现在嵌套函数中&#xff0c;指的是内层函数引用到了外层函数的自由变量&#xff0c…

【算法】牛的旅行(图的直径,floyd算法求最短路)

题目 农民John的农场里有很多牧区&#xff0c;有的路径连接一些特定的牧区。 一片所有连通的牧区称为一个牧场。 但是就目前而言&#xff0c;你能看到至少有两个牧区不连通。 现在&#xff0c;John想在农场里添加一条路径&#xff08;注意&#xff0c;恰好一条&#xff09;。 一…

基于JavaWeb+SSM+Vue校内校园二手交易微信小程序系统的设计和实现

基于JavaWebSSMVue校内校园二手交易微信小程序系统的设计和实现 源码传送入口前言主要技术系统设计功能截图Lun文目录订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码传送入口 前言 在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应…

vmware配置固定ip

1.在vmware中选择编辑-->虚拟网络编辑器。 1.1按下面1&#xff0c;2&#xff0c;3顺序操作&#xff0c;分别修改子网IP:192.168.5.0&#xff0c;子网掩码:255.255.255.0,这里的子网ip为什么是192.168.5.0呢&#xff0c;因为物理机器的关网是192.168.5.1&#xff0c;见物理机…

creo6.0教程之拉伸

目录 一、实体拉伸&#xff1a;1.拉伸基本操作&#xff1a;2.其他常用的拉伸选项&#xff1a;3.移除材料的拉伸&#xff1a; 一、实体拉伸&#xff1a; 1.拉伸基本操作&#xff1a; 1、点击-拉伸&#xff0c;进入拉伸操作界面 2、选择绘制草图放置的平面&#xff0c;选择放置…