Rolldown Vite JSON 插件深度指南:viteJsonPlugin 的 JSON 转 ESM 处理机制与配置实战 Rolldown Vite JSON 插件深度指南viteJsonPlugin 的 JSON 转 ESM 处理机制与配置实战【免费下载链接】rolldownFast Rust bundler for JavaScript/TypeScript with Rollup-compatible API.项目地址: https://gitcode.com/GitHub_Trending/ro/rolldown导读viteJsonPlugin内置插件名builtin:vite-json是 Rolldown 为兼容 Vite 生态而移植的 JSON 模块处理插件它把.json文件在构建期转换成可直接被 ESM 导入的 JavaScript 模块并支持按文件大小自动切换「字面量导出」与「JSON.parse()包装」两种策略。本文以该插件的官方维护文档为主体结合其 Rust 实现、NAPI 绑定层与 JS 构造器源码完整讲解它的工作原理、全部配置项、边界行为与调试用法帮助你准确理解并安全地使用这一 Vite 专属插件。一、插件是什么为 Vite 生态定制的 JSON 转换器viteJsonPlugin移植自 Vite 官方仓库中的jsonPlugin见 crates/rolldown_plugin_vite_json/README.md其职责非常聚焦在 transform 阶段把 JSON 文件内容改写为 JavaScript 模块代码。改写后的模块有两种形态直接以字面量形式导出解析后的 JSONexport default { ... }或者包装为JSON.parse()调用export default /*#__PURE__*/ JSON.parse(...)具体走哪条路取决于配置。在 Rolldown 源码中插件本体是一个实现了Plugintrait 的 Rust 结构体位于 crates/rolldown_plugin_vite_json/src/lib.rs#[derive(Debug, Default)] pub struct ViteJsonPlugin { pub minify: bool, pub named_exports: bool, pub stringify: ViteJsonPluginStringify, } #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] pub enum ViteJsonPluginStringify { #[default] Auto, True, False, }插件通过name()方法对外暴露名为builtin:vite-json的内置插件标识并仅注册transform这一个 hookregister_hook_usage()返回HookUsage::Transform。[!NOTE] 该插件是 Vite 专属的文档明确提示不建议在 Vite 之外单独使用且它的 API 可能在 Rolldown 的 minor 版本之间发生变化但同一 minor 版本内保持兼容。二、安装与调试用法从rolldown/experimental引入该插件目前通过实验性入口rolldown/experimental导出对应的 JS 构造器实现在 packages/rolldown/src/builtin-plugin/constructors.tsviteJsonPlugin(config)内部创建BuiltinPlugin(builtin:vite-json, config)并将其包装为可调用形式并在 packages/rolldown/src/experimental-index.ts 中统一导出。官方文档给出的最小可用配置如下import { defineConfig } from rolldown; import { viteJsonPlugin } from rolldown/experimental; export default defineConfig({ input: { entry: ./main.ts, }, plugins: [ viteJsonPlugin({ minify: false, namedExports: false, stringify: auto, }), ], });要点说明示例中三个选项全部采用默认值实际使用时可以省略显式写出便于在调试时确认配置生效。插件的 Rust 侧字段通过 NAPI 绑定层接收配置见 crates/rolldown_binding/src/options/plugin/config/binding_vite_json_plugin_config.rs。其中minify、namedExports缺省时unwrap_or_default()得到falsestringify缺省时得到ViteJsonPluginStringify::Auto。stringify在 JS 侧的类型定义见 packages/rolldown/src/binding.d.cts为BindingViteJsonPluginStringify绑定层用napi::Eitherbool, String承载即可以传布尔值也可以传字符串auto传其它字符串会抛出Invalid stringify option错误。三、配置项详解官方文档提供了三个选项的完整说明下表为原文表格并补充了默认值与类型约束选项类型说明默认值minifyboolean是否在走stringify路径时压缩 JSON 内容去除空白与格式falsenamedExportsboolean是否为 JSON 属性生成具名导出对 ESM 兼容性有用falsestringifyJsonPluginStringify决定 JSON 内容何时被字符串化并包装进JSON.parse()调用auto3.1minifystringify 路径下的内容压缩该选项只对「字符串化」分支生效。在 crates/rolldown_plugin_vite_json/src/lib.rs 的 transform 实现中当minify: true时代码先用serde_json::from_str::Value(code)解析 JSON再通过serde_json::to_string(value)重新序列化从而剥掉缩进、换行等格式化空白当minify: false时则直接复用原始源码字符串不做任何压缩。let json if self.minify { let value serde_json::from_str::Value(code)?; Cow::Owned(serde_json::to_string(value)?) } else { Cow::Borrowed(code) };源码注释中标注了TODO(perf)即当前实现先解析再序列化并不是性能最优方案后续可能替换为更轻量的压缩手段——这一点也可视为 Vite 上游实现思路的延续。3.2namedExports具名导出与默认导出并存namedExports决定生成代码的形态其判定逻辑与数据结构密切相关let is_name_exports self.named_exports code.trim_start().starts_with({);也就是说只有当namedExports: true并且JSON 源码去除前导空白后以{开头即顶层是对象时才走具名导出分支顶层为数组、字符串、数字等字面量时即使开启namedExports也只会生成默认导出。具名导出的代码生成逻辑位于 crates/rolldown_plugin_utils/src/data_to_esm.rs 的data_to_esm顶层对象为空对象时输出export default {};\n对每个字段若键名是合法标识符通过is_validate_assignee_identifier_name校验生成export const key value;并在默认导出对象中用简写属性引用否则如true、eval、含引号或换行的键该键不生成具名导出仅以字符串键的形式出现在默认导出对象中输出末尾会拼接一个同时包含所有字段的默认导出对象保证import data from ./x.json依然可用。该文件自带单元测试to_esm_named_exports_object、to_esm_named_exports_literal、to_esm_named_exports_forbidden_ident、to_esm_named_exports_multiple_fields分别验证了对象、字面量、非法标识符键和多个字段四种场景可直接作为行为契约阅读。3.3stringify何时把 JSON 变成JSON.parse()调用ViteJsonPluginStringify三种取值的语义与官方文档完全一致auto默认按文件大小自动决策。核心依据是rolldown_plugin_utils中的常量THRESHOLD_SIZE 10 * 1000即 10KB见 crates/rolldown_plugin_utils/src/constants.rs注释引用了 V8 官方博客《The cost of JavaScript in 2019》中关于 JSON 解析的说明。当源码字节数超过 10KB 时自动走 stringify 分支。true无条件 stringify即使文件很小。false永不 stringify始终按字面量导出。对应的 Rust 判定逻辑let is_stringify self.stringify ! ViteJsonPluginStringify::False (self.stringify ViteJsonPluginStringify::True || code.len() constants::THRESHOLD_SIZE);有意思的是data_to_esm内部的serialize_value也会对大对象字段做类似处理字段序列化后超过 10KB 时包一层/*#__PURE__*/ JSON.parse(...)说明「大字面量用JSON.parse包装」是这套工具链的通用策略。四、底层工作原理从源码看完整处理链4.1 transform 入口与前置过滤transform的第一步是一组快速过滤条件见 crates/rolldown_plugin_vite_json/src/lib.rsif *args.module_type ! ModuleType::Json || !utils::is_json_ext(args.id) || is_special_query(args.id) { return Ok(None); }三者任一命中就直接返回Ok(None)表示本插件不处理该模块模块类型不是 JSONmodule_type ! ModuleType::Json文件扩展名不是 JSON 形态is_json_ext(args.id)判定逻辑见 crates/rolldown_plugin_vite_json/src/utils.rs它匹配test.json、test.json?...这类路径但刻意排除test.json?commonjs-proxy与test.json?commonjs-external两种带查询参数的 CJS 代理/外部模块正则语义为/\.json(?:$|\?)(?!commonjs-(?:proxy|external))/并配有单元测试json_ext逐一验证这些边界带特殊查询标记is_special_query(args.id)实现见 crates/rolldown_plugin_utils/src/is_special_query.rs会拦截?raw、?url、?worker、?sharedworker等 Vite 特殊导入后缀——这些导入由 Vite 的其它内置机制处理JSON 插件不应干预例如import data from ./data.json?raw期望拿到的是原始字符串而非模块代码。4.2 BOM 剥离通过过滤后代码先经过strip_bom见 crates/rolldown_plugin_utils/src/strip_bom.rs移除可能存在的 UTF-8 BOM 前缀\u{FEFF}避免 JSON 解析器因 BOM 报错也为后续code.trim_start().starts_with({)的对象判定扫清障碍。4.3 两条输出路径stringify 路径is_name_exports false is_stringify trueconcat_string!( export default /*#__PURE__*/ JSON.parse(, serde_json::to_string(json)?, ) )生成的模块形如export default /*#__PURE__*/ JSON.parse({\name\:\rolldown\})。注意外层用serde_json::to_string对 JSON 字符串再做一次字符串转义确保内层内容在 JS 源码里是合法的字符串字面量。/*#__PURE__*/注释用于辅助压缩器做副作用分析便于后续 tree-shaking。字面量导出路径调用data_to_esm(value, self.named_exports)把解析后的 JSON 值渲染为export default ...;或具名导出形式见 3.2 节。两条路径最终都会通过map: SourceMap::default().into()输出空 sourcemap该插件不生成源映射把module_type从ModuleType::Json切换为ModuleType::Js让转换产物按 JS 模块继续参与后续的链接与打包流程。4.4 模块依赖与可测试性插件 crate 的依赖关系见 crates/rolldown_plugin_vite_json/Cargo.toml非常精简memchr用于高效字节搜索serde_json负责 JSON 解析与序列化rolldown_common/rolldown_plugin提供模块类型与 Plugin traitrolldown_plugin_utils提供data_to_esm、is_special_query、strip_bom与 10KB 阈值常量。其中is_json_ext和data_to_esm均带单元测试说明插件的核心边界逻辑在 Rust 层已被直接验证。五、总结与实践建议场景推荐配置理由常规 Vite 项目构建全部使用默认值minify: false、namedExports: false、stringify: auto行为与 Vite 内置 JSON 处理一致需要import { key } from ./x.jsonnamedExports: true顶层对象字段会被提升为具名导出同时保留默认导出追求产物体积minify: true配合stringify: auto大 JSON 走JSON.parse包装小 JSON 走字面量强制规避大字面量解析开销stringify: true无论文件多小都生成JSON.parse调用大 JSON 以纯字面量内联stringify: false产物可直接查看但超大对象可能影响解析与内存需要再次强调的是该插件面向 Vite 生态设计官方不推荐在 Vite 之外单独使用同时它属于实验性 API从rolldown/experimental导出API 形态可能随 minor 版本演进升级 Rolldown 时请留意该插件的变更。若你的场景不在 Vite 体系内更稳妥的做法是让 Rolldown 走内置的通用 JSON 模块处理流程而非手动挂载本插件。【免费下载链接】rolldownFast Rust bundler for JavaScript/TypeScript with Rollup-compatible API.项目地址: https://gitcode.com/GitHub_Trending/ro/rolldown创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考