尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Rolldown 的 output.preserveModulesRoot 选项详解:精确控制 preserveModules 模式下的输出目录结构

Rolldown 的 output.preserveModulesRoot 选项详解:精确控制 preserveModules 模式下的输出目录结构 Rolldown 的 output.preserveModulesRoot 选项详解精确控制 preserveModules 模式下的输出目录结构【免费下载链接】rolldownFast Rust bundler for JavaScript/TypeScript with Rollup-compatible API.项目地址: https://gitcode.com/GitHub_Trending/ro/rolldown导读output.preserveModulesRoot是 Rolldown一个使用 Rust 编写、兼容 Rollup API 的 JavaScript/TypeScript 打包器在preserve modules 模式即output.preserveModules: true下用于控制输出目录结构的关键选项。它通过剥离输入模块路径中共享的目录前缀让产物的目录结构不再受源代码目录深度影响从而在输出目录迁移、monorepo 多包开发、第三方模块未标记external等场景下保持稳定的产物路径。读完本文你将掌握该选项的完整配置方法、适用场景、底层实现原理及其与preserveModules、virtualDirname、input、external等选项的协同关系。一、选项定位它是preserveModules的目录修剪器Rolldown 的preserveModules模式与 Rollup 保持行为一致不再像默认模式那样“尽量少产出 chunk”而是为每个模块生成独立的 chunk并使用原始模块名作为文件名。与此同时tree-shaking 依然生效——未被入口引用、且执行无副作用side effects的模块文件会被抑制不产出非入口模块中未使用的导出也会被移除。但仅仅保留模块名是不够的如果两个入口模块分处不同的目录层级例如src/module.js与src/another/module.js它们产出的文件会带着各自的目录结构写入output.dir。此时preserveModulesRoot的价值就体现出来了——它指定一个“输入模块的根目录路径”在输出时把该前缀从产物路径中剥离从而裁剪掉你不想保留的目录层级。官方对该选项的使用场景说明非常明确当输出目录结构可能发生变化时这个选项尤其有用。典型情况包括第三方模块未被标记为external这些模块被打包进来后其文件路径会被保留到产物中导致output.dir下出现不受控的深层目录monorepo 多包相互依赖且未标记external多个 package 之间互相引用时产物路径中可能包含各自包的目录前缀剥离公共根目录可以让输出结构更干净、更可预期。二、完整配置示例与输出效果以下示例继承自官方文档并补充了必要的上下文注释import { defineConfig } from rolldown; export default defineConfig({ input: [src/module.js, src/another/module.js], output: { dir: dist, preserveModules: true, preserveModulesRoot: src, }, });设置preserveModulesRoot: src后输入模块会被输出到如下路径dist/module.js // 来自 src/module.js dist/another/module.js // 来自 src/another/module.js对比不设置该选项的行为src/module.js与src/another/module.js的目录结构原本会被原样带入产物得到dist/src/module.js与dist/src/another/module.js。preserveModulesRoot剥离了公共前缀src/这正是它名字中 “Root” 的含义——它定义的是“从哪个根目录开始保留结构”。在 TypeScript 类型定义中该选项声明为preserveModulesRoot?: string;位于 output-options.ts其语义描述为“在使用 preserve modules 模式时需要从output.dir中剥离的输入模块目录路径”文档说明正是通过{include ./docs/output-preserve-modules-root.md}机制内嵌到该选项的 API 注释中参见 output-options.ts。配套选项速查选项类型默认值作用preserveModulesbooleanfalse开启 preserve modules 模式为所有模块按原始模块名产出独立 chunk见 output-preserve-modules.mdpreserveModulesRootstring未设置指定从输出路径中剥离的输入模块根目录virtualDirnamestring_virtual插件产出的“虚拟”模块文件的目录名见 output-options.ts三、底层实现Rolldown 如何在 Rust 中剥离路径前缀preserveModulesRoot从 JavaScript 侧经 binding 层传递到 Rust 核心。参数绑定路径为packages/rolldown/src/utils/bindingify-output-options.ts序列化选项 →crates/rolldown_binding/src/utils/normalize_binding_options.rs中的preserve_modules_root: output_options.preserve_modules_root最终进入NormalizedBundlerOptions定义于 normalized_bundler_options.rs。真正的路径计算发生在生成阶段的generate_chunk_name_and_preliminary_filenames函数中crates/rolldown/src/stages/generate_stage/mod.rs核心逻辑可归纳为三步判断模式仅当self.options.preserve_modules为true时才对入口模块走 preserve modules 的命名分支见 mod.rs。剥离根前缀读取preserve_modules_root后通过strip_path_prefix_to_slash函数把该前缀从模块的绝对路径中裁剪掉得到相对路径见 mod.rs。失败回退如果前缀剥离失败例如模块路径并不以preserveModulesRoot开头实现会回退为relative_path_to_slash(abs, input_base.as_str())——即退而求其次基于入口路径的公共基目录input_base来计算相对路径保证产物文件名仍然稳定可用见 mod.rs。此外源码还处理了路径风格归一化当模块 id 是“类绝对路径”形式如/favicon时实现会将这种无卷标的根路径锚定到 cwd 所在卷根Windows 的盘符或 UNC 共享避免剥离前缀时误吞开头的斜杠从而把盘符/前导斜杠泄漏进[name]见 mod.rs。虚拟文件目录的补充说明在 preserve modules 模式下如果插件为了达成某些效果而产出额外的“虚拟”文件这些文件会被以实际文件形式输出命名模式为${output.virtualDirname}/fileName.js默认_virtual/。preserveModulesRoot只负责裁剪真实模块路径的公共前缀虚拟文件则由virtualDirname单独管理两者互不干扰详见 output-preserve-modules.md。四、跨平台与路径规范化来自测试用例的验证路径处理最容易在 Windows 与类 Unix 系统之间出现行为差异。仓库中有一个专门的集成测试验证了这一场景preserve_modules_root_with_slash_normalized_ids见 crates/rolldown/tests/rolldown/issues/9593/mod.rs。该测试构造了一个返回slash 规范化 id把\统一替换为/见测试中的resolve_id实现mod.rs的 resolve 插件并以preserve_modules: Some(true)、preserve_modules_root: Some(src.into())构建打包配置。它验证了即使插件提供的模块 id 经过了反斜杠到正斜杠的归一化preserveModulesRoot的剥离逻辑依然能够正确工作。从源码结构看这正是通过node_style_absolute与strip_path_prefix_to_slash的组合来兼容“模块 id 保持原生分隔符、而输出路径统一使用/”这两种情形参见 mod.rs 及注释指向的 internal-docs 说明。这一测试同时印证了官方文档开篇的定位该选项的设计目标就是让产物目录结构“稳定且可预测”即使源代码目录树或模块解析方式发生变化。五、使用建议与注意事项结合官方文档与源码行为给出以下实操建议与preserveModules: true成对使用preserveModulesRoot仅在 preserve modules 模式下生效源码在 mod.rs 处先判断preserve_modules单独设置不会产生任何效果。不要盲目用它做全量格式转换官方文档明确指出如果目的是把整个文件结构转换成另一种格式并直接导入不建议盲目开启 preserve modules——因为 tree-shaking 可能让某些预期中的导出缺失。此时更合适的做法是把所有文件显式加入input选项对象并可通过 glob 模式动态指定见 output-preserve-modules.md。优先把相互依赖的包标记为external文档强调该选项主要面向“未标记 external”的场景。在 monorepo 中正确标记external见 input-options.ts 的ExternalOption类型可以从根源上避免依赖包路径被写入产物而preserveModulesRoot则是在无法标记时的兜底手段。善用input的对象形式与命名当需要精确控制每个产物的输出名时应优先使用对象形式input: { name: path }配合entryFileNames等命名模板而不是依赖路径推导。六、小结output.preserveModulesRoot是 Rolldown preserve modules 模式下控制产物目录结构的精准“修剪器”它以一行配置剥离输入模块的公共目录前缀让输出目录结构在输入目录变化时保持稳定尤其适合第三方模块未标记external与 monorepo 多包开发的场景。其实现位于 Rust 生成阶段的 chunk 命名流程中包含“优先剥离前缀、失败回退到入口基目录”的健壮逻辑并有针对 slash 规范化模块 id 的跨平台测试用例作为保障。理解这一选项有助于你在使用 Rolldown 时产出目录结构干净、可预期且与 Rollup 行为一致的打包产物。【免费下载链接】rolldownFast Rust bundler for JavaScript/TypeScript with Rollup-compatible API.项目地址: https://gitcode.com/GitHub_Trending/ro/rolldown创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表