
Rolldown viteManifestPlugin 插件指南在 Vite 构建中生成 manifest.json 资产映射【免费下载链接】rolldownFast Rust bundler for JavaScript/TypeScript with Rollup-compatible API.项目地址: https://gitcode.com/GitHub_Trending/ro/rolldown导读viteManifestPlugin是 Rolldown 内置builtin插件之一专门用于在构建结束后生成一份manifest.json将源码中的原始文件名映射到最终产出的 chunk 与 asset 文件。它由 Vite 的manifestPlugin移植而来核心价值在于服务端渲染SSR时的资源注入与构建产物的清单管理。读完本文你将掌握该插件的引入方式、两个核心配置项root/outPath的用法、manifest 输出的字段结构以及它在 Rolldown 内部的实现原理与测试验证方式。插件定位为 Vite 而生为 SSR 服务该插件位于仓库的 crates/rolldown_plugin_vite_manifest/ 目录其官方说明README.md开宗明义这是一个为vite生成manifest.json将原始文件名映射到产出的 assets/chunks的插件移植自 Vite 的manifestPlugin。其核心工作内容是收集构建产生的所有 chunk 与 asset将它们与源码中的原始名称关联起来最终输出一份 manifest JSON。这份清单文件在以下场景中尤为实用服务端渲染SSR服务端需要根据入口模块名定位对应的打包产物如入口 chunk、其依赖的动态导入 chunk 与样式文件从而在 HTML 中注入正确的script/link标签资源注入前端框架或构建编排系统可以通过 manifest 反向查找某个原始资源文件被编译成了哪个最终文件。值得注意的是README 中有一则明确提示 [!NOTE]该插件仅面向vite使用不推荐外部单独使用其 API 可能在 Rolldown 的 minor 版本之间发生变化但在同一个 minor 版本内保持兼容。这意味着如果你想在自己的非 Vite 构建脚本中稳定使用它需要自行承担 API 变动的风险同时由于插件深度依赖 Vite 生态约定如isLegacy、cssEntries等回调语义脱离 Vite 环境使用价值有限。快速上手Debug 用法示例README 中给出了一份可直接运行的调试用法示例完整继承了原文的配置骨架。在项目的入口配置如rolldown.config.js中引入import { defineConfig } from rolldown; import { viteManifestPlugin } from rolldown/experimental; export default defineConfig({ input: { entry: ./main.ts, }, plugins: [ viteManifestPlugin({ root: path.resolve(import.meta.dirname), outPath: path.resolve(import.meta.dirname, dist/manifest.json), }), ], });这段配置的关键信息有三点插件入口路径viteManifestPlugin从rolldown/experimental导出对应源码 packages/rolldown/src/experimental-index.ts表明其当前处于 experimental 阶段API 可能随 minor 版本演进root必须显式提供插件需要以项目根目录为基准把模块的绝对路径换算成相对路径作为 manifest 的 key详见下文实现解析outPath决定输出位置manifest 最终会作为一份 emit 资源写入该路径。配置项一览README 中的 Options 表格完整如下OptionTypeDescriptionrootstringProject root directoryoutPathstringWhere to write the manifest output fileroot项目根目录作为 manifest key 的计算基准。实现中root被用于把 chunk 的facade_module_id入口模块绝对路径裁剪为相对路径从而得到稳定、可读的清单键名见 src/utils.rs 中get_chunk_name对module_id.relative_path(self.root)的调用。因此传入不一致的root会直接导致 manifest 中的 key 与源码路径对不上号务必使用与构建入口一致的绝对路径。outPathmanifest 输出文件路径manifest 的写入位置。它在插件内部并非直接落盘而是通过emit_file_async以EmittedAsset的形式交还给打包器统一输出见 src/lib.rs这样能够复用 Rolldown 的产物发射机制与其他 emit 文件保持一致的命名与写入流程。绑定层的额外选项JS 侧可见在 Rust 绑定层配置结构还包含两个回调字段见 crates/rolldown_binding/src/options/plugin/config/binding_vite_manifest_plugin_config.rsis_legacyJS 侧isLegacy(options) boolean形式的回调用于判断当前输出是否针对 legacy 构建。为true时chunk 名会被追加-legacy后缀实现见 utils.rs这是 Vite legacy 插件生态的常见约定css_entriesJS 侧cssEntries() Recordstring, string形式的回调返回「css 产物文件名 → 入口模块名」的映射用于在 manifest 中为 asset 标注其所属的 CSS 入口见 lib.rs。这两个回调是 Vite 侧集成时由 Vite 包装层注入的普通调试场景可像测试用例那样传入空实现见下文测试章节。manifest 输出格式详解插件输出的 JSON 主体由ManifestChunk结构序列化而来字段采用 camelCase 命名并且大量使用skip_serializing_if省略空字段让最终清单保持精简定义见 src/utils.rs字段类型含义何时出现filestring最终产出的文件名始终namestringchunk 名如入口main有值时namesstring[]asset 的完整名称列表有值时srcstring原始源文件路径相对rootchunk 有facade_module_id时isEntryboolean是否为入口 chunk仅true时输出isDynamicEntryboolean是否为动态入口 chunk仅true时输出importsstring[]静态依赖的 chunk 名列表非空时输出dynamicImportsstring[]动态 import 的 chunk 名列表非空时输出cssstring[]关联的 CSS 文件预留字段当前固定为Noneassetsstring[]关联的 asset 文件预留字段当前固定为None一个真实的输出样例来自仓库测试快照 packages/rolldown/tests/fixtures/builtin-plugin/manifest/manifest.json.snap{ asset.txt: { file: asset.txt, src: asset.txt }, chunk.js: { file: chunk.js, isDynamicEntry: true, name: chunk, src: chunk.js }, main.js: { dynamicImports: [chunk.js], file: main.js, isEntry: true, name: main, src: main.js } }可以直观看到manifest 的 key 是源码路径如main.js而值中file指向最终产物main.js并且通过imports/dynamicImports完整描述了 chunk 之间的依赖拓扑。底层实现原理挂钩点generate_bundle插件注册了唯一一个 hookgenerateBundle见 src/lib.rs 的register_hook_usage插件内部名称为builtin:vite-manifestlib.rs该名称也注册在绑定层的 binding_builtin_plugin_name.rs 中JS 侧通过 vite-manifest-plugin.ts 的new BuiltinPlugin(builtin:vite-manifest, config)与之对应。这意味着整个插件以 Rust 原生实现运行没有额外的 JS 插件调度开销。输出排序BTreeMap在 generate_bundle 中插件用BTreeMap收集 manifest 条目从而保证最终 JSON 的 key 按字典序排列、输出稳定可复现// Use BTreeMap to make the result sorted let mut manifest BTreeMap::default();随后遍历bundle中的每个Output按 chunk 与 asset 分派处理。Chunk 的命名规则对每个Output::Chunk通过get_chunk_name计算 manifest keyutils.rs若 chunk 存在facade_module_id即它是某个模块的包装入口则取该模块相对root的路径作为名称并做normalize_path归一化、剔除\0字符若没有facade_module_id内部拆分出来的 chunk则以_ 产物文件名的形式兜底命名。同时create_chunk会通过get_internal_imports把 chunk 的静态imports与dynamic_imports映射为「内部 chunk 名列表」——只有当依赖文件能在当前 bundle 中命中同名 chunk 时才保留天然过滤掉 external 的外部模块。Asset 的处理与「JS 优先」去重策略对Output::Asset插件会把每个唯一的 asset 按原始文件名写入 manifest若 asset 没有original_file_names则退化为_ 文件名。这里有一个值得注意的细节lib.rs如果 JS chunk 与 asset chunk 由同一个源文件生成优先保留 JS chunk因为它包含更丰富的信息isEntry、imports、dynamicImports等。这一点由工具函数is_non_js_fileutils.rs保证只有当当前已存在的 manifest 条目对应的产物不是.js/.cjs/.mjs时asset 才会覆盖写入否则跳过。这避免了「同一源文件既产出 JS 又产出 asset 时 key 冲突被错误覆盖」的问题。输出与未来规划最后manifest 以serde_json::to_string_pretty的美化 JSON 格式通过emit_file_async发射为EmittedAsset文件名为outPathlib.rs。源码中还保留了一段注释掉的逻辑TODO: uncomment these when multiple outputs are supported对应 Vite 侧对rollupOptions.output数组长度的判断说明当前实现假定单输出场景多输出multiple outputs支持仍在规划中。测试验证一个可复现的闭环仓库在 packages/rolldown/tests/fixtures/builtin-plugin/manifest/_config.ts 提供了一个完整的集成测试夹具可作为自定义验证的最小模板import path from node:path; import { defineTest } from rolldown-tests; import { viteManifestPlugin } from rolldown/experimental; import { expect } from vitest; export default defineTest({ sequential: true, config: { output: { chunkFileNames: [name].js, assetFileNames: [name][extname], }, plugins: [ viteManifestPlugin({ root: path.resolve(import.meta.dirname), outPath: manifest.json, cssEntries: () Object.fromEntries(new Map().entries()), }), { name: test, buildStart() { this.emitFile({ type: asset, name: asset.txt, source: hello world, originalFileName: asset.txt, }); }, }, ], }, async afterTest() { const manifest await import(./dist/manifest.json); await expect(manifest.default).toMatchFileSnapshot( path.resolve(import.meta.dirname, manifest.json.snap), ); }, });该测试同时覆盖了三条核心行为值得在接入该插件时重点回归入口 chunk 记录main.js以isEntry: true与dynamicImports: [chunk.js]呈现动态入口 chunk 记录动态导入产生的chunk.js被标记为isDynamicEntry: trueemit 的 asset 记录通过emitFile发射的asset.txt以原始文件名出现在 manifest 中且没有多余的空字段names等被省略。使用注意事项小结仅在 Vite 生态内使用README 明确不推荐外部使用且 API 在 minor 版本间可能变动升级 Rolldown 时需关注 changelogroot与outPath建议传绝对路径前者决定 manifest key 的相对路径基准后者决定产物写入位置两者语义不同但都影响最终清单的正确性manifest key 可能包含非 JS 产物asset 条目与 chunk 条目共存且同一源文件的 JS 产物优先级更高解析清单时应以file字段为准而非假设 key 即源码路径当前为单输出假设多输出配置output数组尚未支持源码中相关逻辑仍处于 TODO 状态。通过这份指南你可以快速在自己的 Rolldown Vite 项目中接入viteManifestPlugin并结合上文给出的源码路径与测试夹具深入理解乃至扩展这份 manifest 生成能力。【免费下载链接】rolldownFast Rust bundler for JavaScript/TypeScript with Rollup-compatible API.项目地址: https://gitcode.com/GitHub_Trending/ro/rolldown创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考