文章详细介绍了 CKEditor 5 团队如何通过一系列深入的包体积优化措施,成功将编辑器捆绑包大小减少了 40%。作者首先阐述了 CKEditor 5 在高度模块化和多样化分发场景下遇到的包体积挑战,特别是新引入的元包(meta-package)在简化安装的同时,最初反而增加了体积。随后,文章深入剖析了精细化 tree-shaking 的关键策略,包括识别并重构带有副作用的代码、利用 `/* #__PURE__ */` 注释、将编译目标升级到 ES2022 以优化静态字段的打包方式,以及在 `package.json` 中合理使用 `sideEffects` 字段处理外部依赖。文中还介绍了团队自研的 Sonda 工具在分析和定位体积问题中的应用。最后,文章强调了建立持续的包体积回归监控机制的重要性,并通过自动化报告确保优化成果的长期稳定性,并为其他 JavaScript 库的开发者提供了一份实用的优化清单。
前言
CKEditor 团队通过 tree-shaking 优化和新的安装方法,成功将 CKEditor 5 的捆绑包大小减少了 40%。今日前端早读课文章由 @Filip Sobol 分享,@飘飘编译。
译文从这开始~~
本文将展示我们是如何通过 tree-shaking 和包体积优化技巧,让 CKEditor 5 的体积缩小了 40%。并分享一些您可以用来精简自己的 JavaScript 库的技巧。同时,我们还会介绍过程中使用的工具和流程、如何评估优化效果、以及如何避免回退(回归)问题。
【第3525期】架起桥梁:在 Dart 中运行 JavaScript 模块
任何开发过软件库的人都知道,构建和维护是件很难的事。你不仅要编写代码、撰写文档和测试(这是所有项目的基本要求),还得确保这个库易用、可访问、运行快速,并且能兼容各种前端和后端环境。在影响 JavaScript 性能的诸多因素中,包体积优化是至关重要的一项。
对于像 CKEditor 5 这样高度模块化的框架来说尤其如此。它包含了 80 多个开源和商业包,包越多,组件越复杂,额外的字节就越容易悄悄混进你的打包文件中。不过,减少打包体积的过程并不简单。
包体积优化的起点
为了营造氛围,让我们把时间倒回 2023 年末 —— 我保证这很有意义。就在那时,我们启动了 “马达加斯加” 计划(这是对电影《马达加斯加 2》中 “快点,趁我们还没清醒过来!” 这句台词的致敬)。
此次行动的主题是让 CKEditor 5 更适合开发者使用。从一开始我们就知道这个项目范围非常大,涵盖了多个方面:从发布流程、分发、安装和配置,再到提升文档体验,以帮助集成者更轻松地使用 CKEditor。
在这个重构分发和安装流程的过程中,我们重点攻克的一个方向就是优化 CKEditor 的打包体积。JavaScript 的体积优化包括代码压缩、压缩传输、tree-shaking、代码拆分和智能依赖管理 —— 这些都是现代 JavaScript 应用的关键技术。本文就将深入探讨这个优化过程,这也是我们面对的最复杂挑战之一。
分发与安装方式:打包优化的基础
“分发和安装方式” 到底指什么呢?
先来点背景信息,帮助不熟悉 CKEditor 5 的人了解:
-
CKEditor 5 是一个前端组件:它可以安装到任何网页应用中,从原生 JavaScript 到 React、Angular、Vue、Svelte、Next.js、Nuxt,甚至可以运行在你 fridge 操作系统的浏览器里。
-
它由多种资源组成:JavaScript 源码、TypeScript 类型定义、翻译(JS 文件)、图标(SVG)以及样式表(CSS)。
-
它是高度模块化的:目前由 85 个官方 npm 包组成。每个包可能会包含多个编辑器功能,并携带各自的翻译、图标和样式文件。
规模相当可观,而且对我们来说情况更为复杂的是,与框架不同,我们不能交付一个完整的构建系统或项目模板,并期望集成商基于此来开展项目。CKEditor 需要以最小的集成成本无缝融入各种现有项目中。
因此,“分发” 指的是开发者如何获取源码,“安装” 则是如何在自己的项目中使用它。
我们是怎么失控的:打包体积问题的挑战
大多数 JavaScript 库通常有两种安装方式:一种是通过 npm,另一种是适配 CDN 的构建版本。而到了 2023 年,CKEditor 5 发布已有 8 年,我们竟然积累了超过六种不同的安装方法。
问题出在哪儿?
第一大问题是复杂度。我们的生态非常模块化(有 80 多个包,提供超过 100 个功能,不只是代码,还有翻译、样式和图标)。复杂性带来了以下几个挑战:
-
使用 npm 的开发者可以自由拉取需要的依赖,但在 CDN 上,选择就有限了 —— 下载过多资源会造成网络瓶颈。我们也不能一次打包所有包,因为体积会太大。
-
所有包要正常协同工作,必须使用完全相同的版本。然而,因为包太多,开发者经常会装上不同版本。有时候,包管理器会更新其中一部分包,其余的则没动。
-
翻译和样式必须和代码一起导入。在使用少量包的小项目中没问题,但在复杂系统中,配置变得非常困难,后期维护和更新也很棘手。想象一下编辑器需要导入上百个路径(包括代码、样式和翻译)。
第二个挑战是生态系统的演变。2015 年我们写下第一行 CKEditor 5 代码时,JavaScript 世界完全不同 ——ES Modules 和 webpack 才刚刚火起来,前端框架还不成熟,大多数人还在和 jQuery 奋战。那时候我们根本想不到今天生态会发展成什么样子。
【第3465期】转向纯 ESM(ECMAScript Modules)
于是,后来我们不断引入新的安装方式,来弥补之前方法的不足。每一种方法都有不同的限制和需求。不断增加新方式显然不是长久之计,我们最终意识到 —— 是时候按下重启键了。
老的安装方式:体积优化前的阶段
要理解我们对安装方式做出的改变,先要看看旧方法的弊端。
举一个之前最灵活、最强大的安装方法为例:我们用 TypeScript 将源码 .ts 文件转译为 .js 文件。最终生成的 JavaScript 文件保留了原始结构和所有 import,只是移除了 TypeScript 专用语法。但问题在于,发布的代码依然包含对 .svg 文件和 PostCSS 风格 .css 文件的引入,而大多数构建工具默认无法识别这些格式。
因此,用户不得不为 CKEditor 单独配置打包工具来处理这些资源,甚至需要用到专门插件。我们最开始只支持 webpack,后来才支持 Vite。如果有人使用的是其他打包工具,那就只能更换,或维护一个独立的 CKEditor 构建流程。

此外,这种方法需要安装大量 npm 包,经常会导致版本不一致。为了解决这个问题,我们引入了运行时检测机制,一旦发现包版本不一致就直接报错 —— 根据我们的统计,这也是用户最常遇到的报错。
显然,我们可以做得更好。
新的安装方式
到了 2023 年,CKEditor、JavaScript 生态和工具链都更加成熟,我们也有了更多选择和行业共识。我们决定不再 “发明新轮子”,尽可能移除 “魔法” 配置。
我们首先重新思考了 CKEditor 5 的打包方式。第一步很直接 —— 为每个 CKEditor 5 包预先打包好一个普通的 .js 文件和一个 .css 文件。这样一来,开发者就可以在任何项目中直接使用这些文件,无需额外配置或 CKEditor 专属插件。
这种方式在 npm 上很好用,但在 CDN 场景下就不太适合了,因为它需要下载几十个 .js 文件和更多的 .css 文件 —— 即便是 HTTP/2,也不能完全解决这个问题。而且,这也无法解决包版本不一致造成的重复模块问题,很多用户在安装或升级 CKEditor 时都曾遇到过。
为了解决这个问题,我们引入了两个元包(meta-package):
-
ckeditor5:包含编辑器核心和所有开源包;
-
ckeditor5-premium-features:包含所有商业功能包。

这两个包只是简单地把其余 80 多个包重新导出:
export * from '@ckeditor/ckeditor5-alignment';
export * from '@ckeditor/ckeditor5-autoformat';
export * from '@ckeditor/ckeditor5-autosave';
// ...
它们还包含打包好的 CSS 和翻译文件,因此你只需要最多 6 个导入语句就能配置完整功能的编辑器:
import {/* ... */} from 'ckeditor5';
import {/* ... */} from 'ckeditor5-premium-features';
import 'ckeditor5/ckeditor5.css';
import 'ckeditor5-premium-features/ckeditor5-premium-features.css';
// 可选
import coreTranslations from 'ckeditor5/translations/pl.js';
import premiumTranslations from 'ckeditor5-premium-features/translations/pl.js';
最棒的是,这种安装方式在使用 importmaps 的情况下,npm 和浏览器的工作方式几乎一致 —— 不需要任何构建步骤,唯一的区别是样式的加载方式。
不过,这种做法违背了目前不推荐使用的 “barrel 文件”(或者简单地说 “只是重新导出其他文件的文件”)策略,因为这会影响打包工具的性能。打包器需要解析每个依赖项及其嵌套依赖,即便你只引入其中一个功能模块。
幸运的是,因为我们为每个包都做了打包,打包工具只需解析大约 80 个文件及其依赖,这种开销是可以接受的。此外,这一改动不仅极大地改善了开发者体验,还把 “模块重复错误” 的发生率降低了一半。等我们彻底淘汰旧安装方式后,这一数字还会进一步下降。
自找的麻烦:当 tree-shaking 遇上 barrel 文件
细心的读者可能已经猜到我们接下来要说什么了。一个基本原则是:导入路径越精确,就越不容易引入多余代码,也更容易让打包工具识别并剔除未使用的内容。这个剔除未使用代码的过程通常叫做 “dead code elimination”,但在 JavaScript 世界中,我们都称它为 “tree-shaking”。
在旧的安装方式中,我们从各个独立包中引入代码。如果我们需要 Editor 类,可以直接从 @ckeditor/ckeditor5-core 的入口文件引入。如果你非常关注打包效率和运行时性能,还可以直接从 @ckeditor/ckeditor5-core/src/editor/editor.js 引入。这样,打包工具就不需要解析入口文件中重导出的 20 多个文件。
但在新的安装方式中,我们却反其道而行之。我们设定了两个总入口,分别重导出 60 多个和 20 多个包的代码。这意味着只要从中引入一点内容,打包工具就必须扫描和处理多达 80 多个包的内容。
如果某些代码本身无法被 tree-shake 呢?虽然 tree-shaking 基于 ES2015 模块语法,且现代打包器(得益于 Rollup 的推广)已经普遍支持 tree-shaking,但并不是所有代码都适合这项优化。即使使用了 ES 模块语法,只要代码带有副作用(side effects),就不能被安全地移除。不管你的打包器多强大,副作用代码依然会保留下来。我们要分析的包有 80 多个,遇到无法 tree-shake 的代码的概率自然也大大增加。
时间快进到 2024 年 5 月,我们完成了新安装方式的开发,开始在各种条件下进行测试。其中一个测试就是创建两个简化的项目,导入相同的编辑器代码,但使用不同的安装方式。新方式的功能完全正常,但打包体积…… 很糟糕。如果我没记错,新的安装方式打包后的体积比原来的大了 30%。我们必须在正式发布前解决这个问题。
精通 tree-shaking:从 “死代码” 到极致优化
理想情况下,打包工具可以自动移除所有未使用的代码。但现实是,它们无法总是判断某段代码是否 “安全可删”。为避免破坏功能,它们会保留这类代码。因此,tree-shaking 需要开发者的帮助,告诉打包工具哪些可以安全删除。
举个简单例子:
function add(a, b){
return a + b;
}
add(1,2);
这段代码只是简单地返回两个数相加的结果,没有修改任何全局变量、DOM 或打印信息,也没有副作用,因此打包工具会删除它。
但如果我们加入了 console.log:
function add(a, b){
return a + b;
}
console.log(add(1,2));
执行这段代码会在控制台打印结果。这个 console.log() 是调试用的,还是功能所需?打包工具无法判断。它只知道如果删除这段代码,程序行为就会变了,因此这部分代码就会保留下来。
更糟的是,如果 add() 内部调用了其它函数,那么这些函数也会被一并保留,哪怕它们在其他地方根本没用到。一个小小的副作用,可能导致整个依赖链都被打进最终包中。
要检测包中这类 “副作用代码” 的存在,我们可以使用所谓的 “副作用引入”:
import 'ckeditor5';
import 'ckeditor5-premium-features';
如果你想用这种方式测试自己的库,要确保引入的是构建后将要发布到 npm 的版本,而不是源码。为什么这样很重要?我们稍后会解释。
使用 Vite 构建项目,只保留上述两个 import,我们打包出的 JS 文件(gzip 压缩 + 代码压缩后)大小为 297 KiB。考虑到这段代码什么也没做,这个体积显然偏大。用 esbuild 和 webpack 构建出来的结果更大,分别为 336 KiB 和 325 KiB。
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
接下来我们来看看这些体积到底来自哪里。现在工具更先进了,我们用自己开发的 Sonda 分析所有构建结果。它比我们之前用的六七种工具都方便得多。
添加 Sonda 到 Vite 配置中如下:
import { defineConfig } from'vite';
import Sonda from'sonda/vite';
export default defineConfig({
build:{
sourcemap:true
},
plugins:[
Sonda({
deep:true,
gzip:true,
sources:true
})
]
});
重新构建项目后,我们得到了如下报告:

CKEditor 5 打包文件 treemap(总计 297 KiB;其中 231 KiB 来自 CKEditor 5,自有代码,其他为依赖)。
界面中方块很多,但我们可以一眼看出 “罪魁祸首”。大约 231 KiB 来自我们自己的代码,其余来自第三方依赖。点击每个模块,可以看到它是怎么被引入的、哪些代码最终被打进包中。

让代码 “纯净”:写出无副作用的 JavaScript
看着被高亮的代码(意味着被打包进最终文件),我们最先注意到的就是在全局作用域注册的变量:
【第3529期】从自动补全到得力助手:训练 AI 适应代码库
const toPx = toUnit('px');
这类变量我们要么移进具体函数中,要么直接内联函数调用。但不是所有问题都能这么简单处理。
比如,我们发现很多类因为用了 mixins 而无法被正确 tree-shake,而我们又不能随意更改这些代码以免破坏兼容性:
exportde faultclass InlineEditor extends ElementApiMixin(Editor){
// ...
}
打包工具无法判断 ElementApiMixin(Editor) 是否有副作用,因此不会移除这段代码。但我们作为开发者知道它是安全的。
这时候,我们可以添加一个特殊注释,所有主流打包工具都支持:
export default class InlineEditor extends /* #__PURE__ */ElementApiMixin(Editor){
// ...
}
这个注释会告诉打包器:这个函数没有副作用,因此如果这个类没被用到,可以安全移除。
如果是嵌套 mixins,我们需要对每一层都加上:
export default class Document extends/* #__PURE__ */BubblingEmitterMixin(/* #__PURE__ */ObservableMixin()){
// ...
}
有时候,一个 /* #__PURE__ */ 注释还不够。比如,我们的实时协作功能使用了由 Protobuf 生成的绑定代码,内部创建对象并附加多个属性:
import $protobuf from "protobufjs/minimal.js";
var $root = $protobuf.roots["default"]||($protobuf.roots["default"]={});
$root.AttributeOperation =/* ... */
$root.InsertOperation =/* ... */
export $root;
我们知道 $root 对象仅作为一个整体使用且没有副作用,所以如果它不是直接导入的,就可以移除。我们无法告知打包工具忽略对象创建后发生的属性赋值。不过,我们可以将整个代码块包裹在一个立即调用函数表达式(IIFE)中,并使用与之前相同的 /* #__PURE__ */ 注释:
import $protobuf from "protobufjs/minimal.js";
exportconst messages = /* #__PURE__ */(()=>{
var $root = $protobuf.roots["default"]||($protobuf.roots["default"]={});
$root.AttributeOperation =/* ... */
$root.InsertOperation =/* ... */
return $root;
})();
如果你使用的是 Rollup 或 Vite,我们推荐你开启一个设置项:experimentalLogSideEffects。它可以在构建时报告代码中的副作用点,虽然只能检测有限场景,但作为起点已经很不错。
编译目标:ES2022 如何拯救我们的打包体积
即使我们已经做了很多优化,仍然发现一些类无法如预期那样被 tree-shake。源代码看不出原因,但观察生成后的打包代码就一目了然了。
来看这个例子:
export class Test{
publics tatic field =123;
publics taticmethod(){
return123;
}
}
为什么这么简单的类也 tree-shake 不掉?原因在于打包后的输出格式。
当打包目标设为 es2019 时,工具必须将 static field 转换为兼容旧环境的写法:
var __defProp = Object.defineProperty;
// ...
classTest{
staticmethod(){
return123;
}
}
__publicField(Test,"field",123);
export{ Test };
静态方法没变化,但静态字段被转换成了带副作用的赋值逻辑,而这种代码结构几乎无法被 tree-shake。
下面是将目标设为 es2022 后的输出:
export class Test{
static field =123;
static method(){
return123;
}
}
现代打包工具可以轻松处理并优化这样的代码。
幸运的是,我们本来就计划将目标升级,于是直接跳过了 es2021,选择了 es2022。优化后的打包结果如下:
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
这也验证了我们前面强调的:测试构建后的代码,而非源码本身,非常重要。否则我们根本不会意识到这个问题的存在。
外部依赖:巧用 sideEffects 标志
我们的优化已经非常显著,是不是可以收工了?让我们看看更新后的 Sonda 分析报告:

最新 treemap(总计 76 KiB;其中 CKEditor 5 占 32 KiB)
在总共 80 KiB 中,不到 33 KiB 来自我们自己的包,大多都是核心编辑器代码,几乎在所有项目中都会使用。剩下的 47 KiB 来自外部依赖,而且这些依赖中也包含不能被 tree-shake 的代码。
这是我们无法控制的吗?其实不是。
我们可以在 package.json 中使用一个叫做 sideEffects 的字段,它可以是布尔值或路径数组,用于控制打包工具是否保留带副作用的文件。
我们之前避免使用它,是因为它经常被滥用,反而掩盖了实际的 tree-shaking 问题。但如果我们告诉打包工具某些构建产物没有副作用,那么只要这些代码没被显式导入,就可以被移除。
于是我们在一些含有不可 tree-shake 依赖的包中加入了如下配置:
{
"sideEffects": [
"*.css",
"build/**/*.js",
"dist/translations/*.umd.js"
]
}
再次构建后的最终结果:
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
最终的 Sonda 报告中,方块少了非常多。

最终 treemap(33 KiB,总共;其中 CKEditor 5 占 28.4 KiB)
我们可以看到,唯一保留下来的外部依赖是 es-toolkit—— 这是我们替换 lodash-es 后选用的更小、更快、API 基本兼容的库。它的存在是因为我们项目中真正使用了它的功能,不是因为无法被 tree-shake。考虑到这部分代码对所有 CKEditor 5 用户都必不可少,这一点也可以接受。
实战成果:打包体积减少 40%
时间来到 2025 年 6 月。经过上文提到的一系列优化,以及中途一些针对特定打包工具的小改进,我们成功将无法被 tree-shake 的代码减少了 90%。
这个数字足够让本文标题更吸睛,但更重要的是,这些改动对真实的编辑器项目产生了怎样的影响。来看下面这个真实的编辑器配置:
import {
ClassicEditor,
Essentials,
CKFinderUploadAdapter,
Autoformat,
Bold,
Italic,
BlockQuote,
CKBox,
CKFinder,
EasyImage,
Heading,
Image,
ImageCaption,
ImageStyle,
ImageToolbar,
ImageUpload,
PictureEditing,
Indent,
Link,
List,
MediaEmbed,
Paragraph,
PasteFromOffice,
Table,
TableToolbar,
TextTransformation,
CloudServices,
Mention
} from 'ckeditor5';
import { CaseChange, SlashCommand } from 'ckeditor5-premium-features';
import 'ckeditor5/ckeditor5.css';
import 'ckeditor5-premium-features/ckeditor5-premium-features.css';
ClassicEditor.create( document.querySelector('#editor'),{
plugins:[
Essentials,
CKFinderUploadAdapter,
Autoformat,
Bold,
Italic,
BlockQuote,
CKBox,
CKFinder,
CloudServices,
EasyImage,
Heading,
Image,
ImageCaption,
ImageStyle,
ImageToolbar,
ImageUpload,
Indent,
Link,
List,
MediaEmbed,
Paragraph,
PasteFromOffice,
PictureEditing,
Table,
TableToolbar,
TextTransformation,
Mention,
CaseChange,
SlashCommand
],
licenseKey:'<LICENSE_KEY>',
toolbar:{
items:[
'undo','redo',
'|','heading',
'|','bold','italic',
'|','link','uploadImage','insertTable','blockQuote','mediaEmbed',
'|','bulletedList','numberedList','outdent','indent','caseChange'
]
},
image:{
toolbar:[
'imageStyle:inline',
'imageStyle:block',
'imageStyle:side',
'|',
'toggleImageCaption',
'imageTextAlternative'
]
},
table:{
contentToolbar:[
'tableColumn',
'tableRow',
'mergeTableCells'
]
},
language:'en'
});
下面是压缩并 gzip 后的打包体积对比:
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
这个成果非常可观,尤其是在最终用户看来,编辑器的功能没有任何变化。更值得一提的是,在过去一年里我们还引入了不少新功能和新包(这些都会影响 “优化后” 的体积),也就是说现在打包的功能更多了,但总体体积却更小了。
回归监控:如何尽早发现体积回退问题
tree-shaking 优化做好后,我们还必须确保未来不会引入 “反向优化”—— 即体积回退(regression)。包体积优化不是一次性的事情,它需要持续监控。很巧的是,在我们第一次完成优化后不到一周,就发生了体积回退的问题。幸好我们在发布前发现并修复了,也由此意识到,回归监控在大型项目中是必不可少的。
负责实现体积监控的是我们非常棒的 QA 团队,他们本就维护着一套每晚运行的端到端测试。初版的体积监控脚本很简单:它会拿最新的两个 nightly 构建,分别用 Vite、esbuild 和 webpack 构建以下内容:
import 'ckeditor5';
import 'ckeditor5-premium-features';
然后对比打包体积是否变化,并把结果发到我们的 Slack 频道上,提醒是否出现回归。
但很快我们意识到这还不够。这种对比只是告诉我们体积变了,却无法告诉我们 “为什么变了”,我们还得手动排查,效率不高。
这时候,Sonda 再次派上了用场。Sonda 默认生成 HTML 格式的报告,但它也可以生成 JSON 格式的详细数据 —— 这正是我们用来分析差异的关键。
配置如下:
Sonda({
format:'json',
deep:true
})
其中 deep: true 会启用 source map 分析,这样我们不仅能看到哪个包导致了体积变化,还能具体定位到哪个源文件。
加入 Sonda 后,脚本会读取 JSON 报告,做差异分析,并将结果发到 Slack 上:

Slack 上显示了 CKEditor 5 构建前后对比报告,并能追踪到具体差异来源。
这样一来,每当代码变动导致体积变化,我们都能第一时间知道发生了什么、是哪个 PR 引起的,修复效率也大大提升。
如何优化你的 JavaScript 库:打包优化清单(TL;DR)
如果你也希望优化自己的库,下面是本篇文章总结出的优化思路和一些额外建议:
检查 tree-shaking 效果
使用文中介绍的方式测试你的库是否支持 tree-shaking。记得用不同的打包器测试,因为它们对 tree-shaking 的支持程度不尽相同。
让代码 “纯净”
优先通过重构,让你的代码变得易于被 tree-shake,尽量在不影响外部 API 的情况下实现优化(除非你接受引入 breaking change)。
用注释帮助打包器
如果不能修改代码逻辑,可以使用 /* #__PURE__ */ 注释,让打包工具知道这段代码没有副作用。但切记只能用于真正无副作用的代码,滥用反而会导致 bug。
升级目标环境,避免引入 polyfill
根据你支持的运行时环境(Node 或浏览器)设定合理的构建目标(target)。目标越新,生成代码越简洁。polyfill 应由最终项目负责引入,而不是你在库中包含。
使用最新依赖
如果多个包引用了同一个依赖但版本不一致,就可能导致重复打包。保持依赖版本统一有助于减少体积。
替换老旧依赖
我们将 lodash-es 替换为更轻巧的 es-toolkit,你也可以参考 e18e(Ecosystem Performance) 社区推荐的替代库列表,选择现代、轻量的库。
合理拆分模块
如果适合你的项目结构,可以将库拆分成多个小模块。这和我们在 CKEditor 5 中采取的 “大聚合” 策略相反,但对于某些场景更合适。
标注副作用文件
最后手段是使用 sideEffects 字段标记哪些文件有副作用。但正如前文提到的,这只是权宜之计,过度使用反而会掩盖问题。
总结
没有什么代码,比 “没有代码” 更快。
在 JavaScript 生态中,tree-shaking 常常被忽视。它不仅仅是为了让体积看起来更小,而是直接影响到最终用户的加载速度和使用体。
优化 tree-shaking 并不容易,尤其是在大型或成熟的库中,但这是值得投入精力去做的事。打包优化包括:压缩、tree-shaking、代码拆分、智能依赖管理 —— 这些都是现代 JavaScript 应用的核心能力。
从测量开始,持续优化,做好回归监控。你每节省的一个字节,用户都会感受到实实在在的提升。
关于本文
译者:@飘飘
作者:@Filip Sobol
原文:https://ckeditor.com/blog/how-we-reduced-ckeditor-bundle-size/

对你有帮助,帮” 赞 “一下,
期待下一期,帮” 在看” 一下
