Rolldown 代码分割(Code Splitting)esbuild 兼容性快照测试全景:23 个 splitting 用例深度解析

发布时间:2026/11/13 17:18:11

Rolldown 代码分割(Code Splitting)esbuild 兼容性快照测试全景:23 个 splitting 用例深度解析 Rolldown 代码分割Code Splittingesbuild 兼容性快照测试全景23 个 splitting 用例深度解析【免费下载链接】rolldownFast Rust bundler for JavaScript/TypeScript with Rollup-compatible API.项目地址: https://gitcode.com/GitHub_Trending/ro/rolldown导读本文以 Rolldown 仓库中 esbuild 快照差异测试的splitting类别汇总文档为核心完整梳理该类别下 23 个通过用例的测试结构与技术内涵。通过逐一映射测试夹具_config.json、源码与artifacts.snap并结合 汇总生成器 runner.ts 与codeSplitting配置项的实现源码你将掌握Rolldown 如何以 esbuild 输出为基准验证自身代码分割行为共享模块抽取、动态导入拆包、CJS/ESM 互操作、跨 chunk 循环引用等场景的期望输出长什么样以及这份汇总文档是如何被自动化生成的。一、这份汇总文档是什么esbuild 快照差异测试中的 splitting 类别Rolldown 维护了一套以 esbuild 测试用例为蓝本的快照差异snap-diff测试体系用于衡量自身打包结果与 esbuild 输出的一致性。每个 esbuild 测试类别对应一份生成式的 Markdown 汇总文档splitting.md 就是其中面向**代码分割code splitting**类别的汇总。文档结构分为四个区块# Failed Cases失败用例当前为空# Passed Cases通过用例23 个全部链接到 crates/rolldown/tests/esbuild/splitting/ 下的真实测试夹具目录# Ignored Cases忽略用例当前为空# Ignored Cases (not supported)暂不支持而忽略当前为空。也就是说在这份文档所代表的快照比较范围内splitting 类别当前是 23/23 全部通过、零失败、零忽略的状态。1.1 汇总文档的生成机制这份文档并非手写而是由 runner.ts 自动生成的。关键逻辑如下runner.ts对每个 esbuild 快照类别执行快照对比得到diffList并按用例名排序调用getSummaryMarkdownAndStats(diffList, snapCategory)生成 Markdown 与统计信息写入snap-diff/summary/类别.md即本文对应的 splitting.md汇总所有类别的 pass / failed / ignored / total 统计。在 runner.ts 中可以看到分类与排版逻辑diffList按isNotSupported→isIgnored→isFailed→ 其余为passList的顺序归类Failed区块链接到每个夹具目录下的diff.md失败差异详情Passed区块则直接链接到夹具目录本身。此外生成器对“未记录原因的跳过用例”有硬性约束凡是以.前缀跳过skipped的用例都必须在 reasons.ts 中登记进ignoreReasons、notSupportedReasons或failedReasons否则直接抛出错误提示补全文档。这意味着 splitting.md 中“无忽略、无失败”的干净状态本身就是被工具链强制审计过的结论。二、23 个通过用例全景完整列表以下完整继承汇总文档中的全部链接并统一转换为仓库根目录相对路径。每一个链接都对应 crates/rolldown/tests/esbuild/splitting/ 下一个可独立运行的测试夹具目录edge_case_issue2793_with_splittingedge_case_issue2793_without_splittingsplitting_assign_to_localsplitting_chunk_path_dir_placeholder_implicit_outbasesplitting_circular_reference_issue251splitting_cross_chunk_assignment_dependenciessplitting_cross_chunk_assignment_dependencies_recursivesplitting_duplicate_chunk_collisionsplitting_dynamic_and_not_dynamic_common_js_into_es6splitting_dynamic_and_not_dynamic_es6_into_es6splitting_dynamic_common_js_into_es6splitting_dynamic_es6_into_es6splitting_dynamic_import_issue272splitting_dynamic_import_outside_source_tree_issue264splitting_hybrid_esm_and_cjs_issue617splitting_minify_identifiers_crash_issue437splitting_missing_lazy_exportsplitting_nested_directoriessplitting_public_path_entry_namesplitting_re_export_issue273splitting_shared_common_js_into_es6splitting_shared_es6_into_es6splitting_side_effects_without_dependencies从命名与测试语义看这批用例大致覆盖以下几个主题共享模块抽取splitting_shared_es6_into_es6、splitting_shared_common_js_into_es6动态导入拆包splitting_dynamic_es6_into_es6、splitting_dynamic_common_js_into_es6以及动态/静态混用的splitting_dynamic_and_not_dynamic_es6_into_es6、splitting_dynamic_and_not_dynamic_common_js_into_es6跨 chunk 依赖splitting_cross_chunk_assignment_dependencies及其递归变体、splitting_assign_to_local、splitting_side_effects_without_dependencieschunk 命名与路径splitting_nested_directories、splitting_public_path_entry_name、splitting_chunk_path_dir_placeholder_implicit_outbase历史 issue 回归issue251循环引用、issue272动态导入、issue264源树外动态导入、issue273重导出、issue437压缩标识符崩溃、issue617ESM/CJS 混合、issue2793含/不含分割两种开关。三、测试夹具的构成与运行方式以 splitting_shared_es6_into_es6 为例一个夹具目录通常包含四类文件_config.json打包配置入口定义a.js、b.js、shared.js等输入源码artifacts.snap期望输出快照insta 快照其头部注明source: crates/rolldown_testing/src/integration_test.rs说明由集成测试框架产出部分用例还带有compile-log.txt如 splitting_missing_lazy_export等附加产物。3.1 入口配置_config.json_config.json中的config.input采用“命名入口”数组形式name决定产物 chunk 名import指向相对源码{ config: { input: [ { name: a, import: a.js }, { name: b, import: b.js } ] } }这正是 splitting_shared_es6_into_es6 的配置两个入口共享同一模块。类似地splitting_nested_directories 用pageA/page.js、pageB/page.js两个嵌套目录下的入口入口名分别命名为pageA_page、pageB_page用于验证嵌套目录场景下的 chunk 命名规则。3.2 期望输出artifacts.snap快照直接呈现打包后的可执行代码本文所有产物代码均引自对应artifacts.snap文件。例如 splitting_shared_es6_into_es6/artifacts.snap 中的输出为// a.js console.log(123); // b.js console.log(123);输入中两个入口都import { foo } from ./shared.js并console.log(foo)而shared.js中export let foo 123。快照输出显示常量foo在分割场景下被求值内联为字面量123shared.js作为共享模块被消除无需单独成 chunk这与 esbuild 在该场景下的输出基准一致。四、代表性用例源码级拆解4.1 共享模块抽取splitting_shared_es6_into_es6输入a.js、shared.js// a.js import { foo } from ./shared.js console.log(foo) // shared.js export let foo 123a.js与b.js的输入完全一致。期望快照见上文显示两个入口各自输出console.log(123)。这说明在该场景下Rolldown 既完成了共享模块的识别又通过常量传播把导出值内联进了每个入口使共享 chunk 无需单独产出——是“分割 摇树/常量折叠”协同工作的典型结果。4.2 动态导入拆包splitting_dynamic_es6_into_es6splitting_dynamic_es6_into_es6 是单个入口、动态import()的场景。其 artifacts.snap 输出两个 chunk// entry.js import(./foo.js).then(({ bar }) console.log(bar)); // foo.js let bar 123; export { bar };入口保持import()的异步形态foo.js被拆为独立异步 chunk 并补上export { bar }动态导入的bar命名导出被保留在拆出的 chunk 中。这正是codeSplitting开启时动态导入默认被拆为独立 chunk 的行为验证。4.3 CJS 与 ESM 互操作splitting_dynamic_common_js_into_es6当动态导入的目标是 CommonJS 模块、输出格式为 ESM 时需要运行时 helper 做转换。splitting_dynamic_common_js_into_es6/artifacts.snap 展示了完整形态// entry.js import(./foo.js).then((m) /* __PURE__ */ __toESM(m.default)).then(({ default: { bar } }) console.log(bar)); export { __commonJSMin as t }; // foo.js import { t as __commonJSMin } from ./entry.js; var require_foo /* __PURE__ */ __commonJSMin(((exports) { exports.bar 123; })); export default require_foo();可以看到两条关键机制其一__commonJSMin这个 CJS 包装 helper 被提升到入口 chunk并通过export { __commonJSMin as t }与import { t as __commonJSMin }在 chunk 之间共享避免重复注入同时保证模块实例唯一其二动态导入处使用__toESM(m.default)将 CJS 的default归一化为 ESM 语义。快照头部还保留// HIDDEN [\0rolldown/runtime.js]标记说明运行时模块作为隐藏依赖参与打包。4.4 跨 chunk 循环引用splitting_circular_reference_issue251splitting_circular_reference_issue251 验证循环依赖模块被分割到不同 chunk 时的正确性// a.js var q 6; // 来自 b.js var p 5; // 来自 a.js export { p, q }; // b.js import { p, q } from ./a.js; export { p, q };b.js的内容var q 6被折叠进a.jschunk而a.js再统一export { p, q }b.js只保留对a.js的转发导入。即循环引用不破坏模块初始化顺序chunk 间的 import/export 边被正确重建。4.5 跨 chunk 赋值依赖splitting_cross_chunk_assignment_dependenciessplitting_cross_chunk_assignment_dependencies/artifacts.snap 覆盖“chunk A 修改、chunk B 读取共享状态”的场景// a.js import { t as setValue } from ./shared.js; setValue(123); // b.js import ./shared.js; // shared.js var value; function getValue() { return value; } function setValue(next) { value next; } sideEffects(getValue); export { setValue as t };共享模块shared.js被抽为独立 chunka.js通过import { t as setValue }使用内部重命名的导出b.js以副作用导入方式引入同一共享 chunk。其递归变体 splitting_cross_chunk_assignment_dependencies_recursive 则进一步覆盖多层依赖链下的情形。4.6 重复 chunk 冲突消除splitting_duplicate_chunk_collisionsplitting_duplicate_chunk_collision 有 4 个入口a、b、c、da/b都导入ab.jsc/d都导入cd.js。其 artifacts.snap 表明共享模块被去重合并ab.js与cd.js各自只产出一个共享 chunk4 个入口分别引用它们。用例名中的 “collision” 指向 esbuild 测试中关于重复/冲突 chunk 的语义这里验证的是去重后不产生命名冲突。4.7 嵌套目录入口命名splitting_nested_directoriessplitting_nested_directories/artifacts.snap 输出pageA_page.js、pageB_page.js两个入口 chunk// pageA_page.js console.log(123); // pageB_page.js console.log(-123);输入中pageA/page.js与pageB/page.js各自独立无共享模块因此直接按入口名pageA_page/pageB_page产出两个独立 chunk验证了命名入口在嵌套目录下的 chunk 命名拼接规则。4.8 输出路径占位符splitting_chunk_path_dir_placeholder_implicit_outbasesplitting_chunk_path_dir_placeholder_implicit_outbase/artifacts.snap 覆盖[dir]占位符与隐式 outbase 语义// entry.js console.log(import(./file.js)); // file.js位于 output-path/should-contain/this-text/ 下 console.log(file.js);入口通过动态import(./file.js)触发拆包动态 chunk 被放置到output-path/should-contain/this-text/路径下chunk 路径的//#region注释直接记录了该虚拟输出路径验证了目录占位符按模块相对隐式 outbase 的规则展开。4.9 空模块命名空间与缺失导出splitting_missing_lazy_exportsplitting_missing_lazy_export 的 common.js 是import * as ns from ./empty.js export function foo() { return [ns, ns.missing] } export function bar() { return [ns.missing] }该用例验证对空模块做命名空间导入并访问不存在的导出ns.missing时打包输出与 esbuild 基准一致——此类“惰性导出缺失”场景不会导致崩溃或错误产物目录中的compile-log.txt记录对应编译期输出。4.10 历史 issue 回归组splitting_dynamic_import_issue272动态导入相关的历史回归splitting_dynamic_import_outside_source_tree_issue264源树之外的动态导入路径处理splitting_re_export_issue273chunk 间重导出splitting_minify_identifiers_crash_issue437开启压缩标识符minify identifiers时的崩溃回归splitting_hybrid_esm_and_cjs_issue617同一打包中 ESM 与 CJS 模块混合edge_case_issue2793_with_splitting / edge_case_issue2793_without_splitting同一边界用例在“开启/关闭分割”两种开关下的对照验证其配置均为单入口index.js。这些以issueNNN命名的用例说明该类别不仅是功能测试更是一组针对真实缺陷的回归防线——任何一次快照变化都会被 runner.ts 捕获并反映到汇总文档中。五、与公开codeSplitting选项的源码映射这批测试所验证的“代码分割开关”对应的是 Rolldown 公开 API 中的codeSplitting选项。从源码看其内部模型是 code_splitting_mode.rs 中定义的CodeSplittingMode枚举Bool(true)默认行为自动代码分割惰性加载的动态导入被拆为独立 chunk对应splitting_dynamic_es6_into_es6等场景Bool(false)关闭分割所有动态导入内联进单一 bundleAdvanced(ManualCodeSplittingOptions)开启自动分割同时携带用户定义的手动分组manual chunk grouping配置。该枚举还提供is_automatic()/is_disabled()判定方法Default实现为Bool(true)。而选项字段本身定义在 inner_bundler_options/mod.rs/// Mirrors the public codeSplitting: boolean | CodeSplittingOptions. pub code_splitting: OptionCodeSplittingMode,其注释明确说明对象形式Advanced携带的分组配置在归一化normalization阶段被拆分为“开关门gate”NormalizedBundlerOptions::manual_code_splitting。这也解释了为什么 esbuild 测试用例中无需显式配置分组仅靠默认开关即可验证自动分割行为——高级分组属于另一层归一化逻辑。六、结论与边界说明把 splitting.md 与 crates/rolldown/tests/esbuild/splitting/ 下的夹具对照可以得到如下事实该快照类别当前全部通过23 个用例全部命中Passed CasesFailed Cases、Ignored Cases、Ignored Cases (not supported)均为空覆盖维度完整共享模块抽取、动态导入拆包、CJS/ESM 互操作与运行时 helper 注入、跨 chunk 循环引用与赋值依赖、chunk 命名与路径占位符、空模块缺失导出以及多个历史 issue 回归均有对应夹具结论边界这里的“通过”指 Rolldown 的输出与 esbuild 在该类别快照基准下的期望输出一致是快照比较层面的兼容性证据该汇总文档由 runner.ts 自动生成并强制审计跳过原因是持续集成中观察代码分割行为漂移的可靠入口。对于想深入代码分割实现的读者可以从 crates/rolldown/tests/esbuild/splitting/ 的任一夹具入手配合 code_splitting_mode.rs 的选项模型以及测试框架入口 integration_test.rs快照头部标注的 source逐步展开阅读。【免费下载链接】rolldownFast Rust bundler for JavaScript/TypeScript with Rollup-compatible API.项目地址: https://gitcode.com/GitHub_Trending/ro/rolldown创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/11/11 9:25:32

数据流式编程核心:执行单元设计原理与背压实践

我是一个平时喜欢折腾数据管线的工程师,今天想好好聊聊数据流式编程里最基础也最关键的一个概念——执行单元。这个词听起来有点学院派,但说白了,它就是数据流里那个真正干活的节点:收一条数据进来,处理一下&#xff0…

2026/11/5 10:59:40

Android架构组件实战:从MVC到MVVM的演进与核心知识点解析

做了这么多年Android开发,我越来越深刻地体会到一件事:架构组件(Android Architecture Components)真正解决的不是"代码能不能跑"的问题,而是"代码能不能长期维护"的问题。很多项目一开始写得很爽…

2026/11/13 10:29:25

Kimi砍娱乐业务押注Scaling Law:大模型能力为王

1. 一句话看明白:杨植麟到底做了个什么决定最近打开各大平台,Kimi的热度一直没下来过。从"和kimi聊天的人太多了"到"订阅会员可进入优先队列",再到开发者圈子里讨论的"kimi code怎么用""ccswitch配置kimi…

2026/11/13 17:16:28

汝城电工证培训机构多少钱 证书过期了不知道怎么复审延期

汝城电工证培训机构多少钱 证书过期了不知道怎么复审延期 证书过期了不知道怎么复审延期,这事儿你不是一个人。很多人拿到电工证后,因为工作变动、项目周期或者疏忽,一不留神证书就“过期”了,但又不清楚该找谁、怎么操作。特别是如果你在汝城地区,想通…

2026/11/13 17:16:28

花都小电工证在哪考多少钱能搞定?外省证怎么转?

花都小电工证在哪考多少钱能搞定?外省证怎么转? 之前考的证在外省能不能转过来?这几乎是每个想考【花都小电工证】的人最关心的问题。尤其是在现在,很多小伙伴都是在外地打工,手上有个证,想换个城市干,或者想换份工作,但发现外地证在当地用不了,那可…

2026/11/13 17:16:28

贵州考电工证难不难保姆级教程

贵州考电工证难不难保姆级教程 证书过期了不知道怎么复审延期?别慌!今天就给你一条清晰的【贵州考电工证难不难保姆级教程】,从报考到复审,一步步讲透,看完就能上手操作,再也不怕被行业门槛卡住。 一、贵州考电工证难不难?真实情况大揭秘 1.…

2026/11/13 17:16:28

电工证需要上墙吗?工地太忙根本没时间复习考试,多久拿证能上岗

电工证需要上墙吗?工地太忙根本没时间复习考试,多久拿证能上岗 工地太忙根本没时间复习考试,手里拿着电工证却不知道怎么用,更别提还得上墙展示。你是不是也遇到过这样的情况?现在不少工地要求电工证必须上墙展示,但这真的有必要吗?更重要的是,…

2026/11/12 20:35:13

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/13 0:01:06

办上海高压电工证良心建议:别被中介坑了,自己看这篇就够了

办上海高压电工证良心建议:别被中介坑了,自己看这篇就够了 你是不是也像我一样,第一次听说“高压电工证”这个名词,就感觉一头雾水?其实很多人都跟我一样,不知道去哪报名、怕被中介坑,结果花了冤枉钱还考不上。今天我就从一个在商丘培训过的学员角度,…

2026/11/13 0:01:06

黎里考电工证在哪里值不值得考

黎里考电工证在哪里值不值得考 之前考的证在外省能不能转过来?这是很多在外地工作、准备回老家发展的朋友最关心的问题。特别是在黎里地区,很多从事电力相关工作的朋友,都面临这样一个难题: 外省的电工证能否在本地使用?值不值得考?…

2026/11/13 0:01:06

毕节哪里考电工证 怎么报名学历不高也能上手

毕节哪里考电工证 怎么报名学历不高也能上手 你是不是也和我一样,学历不高,想着考个电工证,但又担心自己条件不够,怕报不上名?其实不然,只要符合条件,学历不高也能考电工证。今天就来聊聊【毕节哪里考电工证】这个问题,还有怎么报名,让你一步到位不…

2026/11/12 22:10:13

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/13 12:14:39

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑