JavaScript import attributes 怎样加载 JSON 模块
如果你是在原生浏览器模块或 Node ESM 中加载 JSON,最稳妥的写法是把类型写在导入属性里:import data from "./data.json" with { type: "json" };。浏览器还要求脚本本身是模块,并且 JSON 响应的 MIME 类型应为 application/json。Vite 这类构建工具则会在构建阶段接管 JSON 文件,所以它的写法和原生运行时不能直接互换。
记住一句话:原生环境用with { type: "json" }明确告诉运行时“这是 JSON”;Vite 项目里不写with也可能正常,是因为 JSON 已经被构建器转换进模块图。
一、先看触发信号:你到底在哪个环境加载 JSON
我排查这类问题时,第一步不是修改语法,而是确认代码最终由谁加载。直接挂在 HTML 的 中,属于浏览器原生模块;带 "type": "module" 的 Node 项目或 .mjs 文件,属于 Node ESM;经过 Vite 开发服务器和生产构建的源码,则由构建器先处理。
这三个环境都写着 import,但 JSON 的“类型检查发生在哪里”并不相同。原生浏览器按照响应的 MIME 类型识别模块,文件名后缀不能代替服务端返回头;Node ESM 也把 JSON 的 type 属性视为必需条件。Vite 的 JSON 章节则明确提供了直接导入和根字段命名导入,这属于它的构建能力。
因此,看到下面这些信号时先停一下:浏览器报“期望 JavaScript 模块却收到 application/json”,Node 报缺少 JSON 类型属性,或者 Vite 中同一份 JSON 可以直接写命名导入。它们不是同一个故障。
二、原生环境的最小写法:给 JSON 标明类型
在浏览器原生模块里,准备一个与脚本同源的 data.json:
{
"name": "Shilpa",
"theme": "light"
}
然后在模块脚本中使用默认导入。JSON 模块只有一个默认导出,不能把对象字段直接当成 ES 命名导出:
服务端还要把这个文件作为 application/json 返回。with 属性会让运行时按 JSON 资源发起请求并检查媒体类型;如果服务器误返回 text/javascript,导入应失败,而不是把 JSON 文件当成代码执行。

三、需要按需读取时,用动态 import 的第二个参数
配置只在某个页面分支真正打开时才需要,可以用动态导入。属性不写在路径字符串里,而是放到第二个参数的 with 对象中:
async function loadThemeConfig() {
// 动态导入仍然要明确 JSON 类型
const module = await import("./theme.json", {
with: { type: "json" },
});
// JSON 模块的值位于 default,而不是任意命名导出
return module.default;
}
loadThemeConfig().then((config) => {
// 只在配置加载成功后使用主题字段
document.documentElement.dataset.theme = config.name;
});
静态导入和动态导入都会被当前环境缓存。如果你要读取“每次请求都可能变化”的积分、新闻或后台配置,不要把动态 import() 当成实时接口;应使用 fetch(),再根据响应处理 JSON。动态导入的优势是延后加载模块,不是绕过缓存。
四、Vite 为什么可以省略 with:它接管了构建阶段
在 Vite 源码中,下面这种写法是官方文档展示的能力:
// Vite 在构建阶段把 JSON 转成模块
import config from "./config.json";
// Vite 还支持根字段命名导入,适合只使用少量字段
import { apiBase } from "./config.json";
console.log(config.mode, apiBase);
这并不表示浏览器原生 import 忽然允许省略属性。开发阶段由 Vite 解析文件、生成可供模块图使用的代码;生产构建后,浏览器看到的是构建产物和普通 JavaScript 模块。Vite 的命名导入也是构建器提供的便利,不能据此推断原生 JSON 模块拥有同样的命名导出。
我通常按下面的边界做选择:如果代码直接交给浏览器或 Node 加载,保留 with { type: "json" };如果代码只在 Vite 管理的源码图中,按项目现有约定使用直接导入;如果同一段源码既要被原生运行又要被 Vite 打包,则优先统一成默认导入,并把环境差异写进构建约定,而不是让调用方猜。

五、按错误信号处理:修语法、修 MIME,还是改用 fetch
浏览器提示模块类型不匹配:先检查 HTML 是否使用了 type="module",再检查 JSON 响应的 Content-Type 是否为 application/json,最后确认静态导入带有 with { type: "json" }。文件名写成 .json 不能替代这三项。
旧代码还在写 assert { type: "json" }:导入属性的前一版语法使用过 assert,当前文档以 with 为标准写法。不要把两种语法拼在一起;按目标运行时和构建链的当前文档统一替换。
Node 报 JSON 类型缺失:确认项目处于 ESM 模式,并把静态或动态导入都改成带 type: "json" 的形式。Node 的原生规则与 Vite 的源码转换规则不能互相证明。
数据会变化却读到旧值:模块导入有生命周期内的缓存语义。把实时数据改成 fetch(),在请求后调用 response.json();不要通过给 URL 随意追加查询参数来掩盖数据来源和缓存策略。
六、最后用一张表做值班式复盘
| 场景 | 推荐写法 | 优先检查 |
|---|---|---|
| 浏览器原生模块 | import data from "./data.json" with { type: "json" } | module 脚本、MIME、同源/CORS |
| Node ESM | 静态或动态导入都带 type: "json" | ESM 模式、属性语法、文件路径 |
| Vite 源码 | 按 Vite 规则直接导入 JSON | 构建器版本、命名导入是否只是构建能力 |
| 实时数据 | fetch() 后解析 JSON | 缓存、请求失败、响应类型 |
把“原生加载”和“构建时转换”分清后,with { type: "json" } 就不再是需要死记的特殊符号:它是原生模块的类型边界;而 Vite 的省略,是构建器替你完成了文件转换。
相关问题
JSON 模块能否直接写 import { name } from "./data.json"?在原生 JSON 模块语义里不要这样写,使用默认导出后再读取字段;Vite 的命名导入是构建器能力。
什么时候应该放弃 import,改用 fetch?当数据需要按请求刷新、需要处理 HTTP 状态码,或不应被模块缓存生命周期绑定时,使用 fetch() 更清楚。
IntersectionObserver 怎样按可见性加载内容
- 上一篇
- IntersectionObserver 怎样按可见性加载内容
- 下一篇
- CSS color-mix 怎么按主题色生成悬停和禁用颜色
-
- 文章 · 前端 | 1小时前 | 前端 · 性能优化 · javascript · 浏览器API · IntersectionObserver rootMargin threshold Intersection Observer API unobserve 前端懒加载
- IntersectionObserver 怎样按可见性加载内容
- 182浏览 收藏
-
- 文章 · 前端 | 1小时前 | 前端 · css · 浏览器兼容 · anchor-name position-area CSS anchor positioning position-anchor position-try 下拉菜单定位
- CSS anchor positioning 怎样让下拉菜单跟随触发按钮并自动避让边缘
- 161浏览 收藏
-
- 文章 · 前端 | 1小时前 | 前端 · css · 可访问性 · CSS 滚动容器 overflow: clip overflow: hidden 键盘聚焦
- CSS overflow: clip 怎样在裁剪内容时不产生滚动条
- 252浏览 收藏
-
- 文章 · 前端 | 2小时前 | 前端 · css · CSS 组件样式 @scope scope root scope limit :scope
- CSS @scope 怎样限制组件样式不越过容器边界
- 208浏览 收藏
-
- 文章 · 前端 | 1天前 | 并发控制 · 前端 Query Web Locks API LockManager 多标签页同步
- 前端 Web Locks 怎样查询当前持有者
- 284浏览 收藏
-
- 文章 · 前端 | 1天前 | 前端 · javascript · JavaScript 国际化 语言边界 Intl.Segmenter 文本分词
- 前端 Intl.Segmenter 怎样按语言边界切分文本
- 432浏览 收藏
-
- 文章 · 前端 | 1天前 | 前端 · 泛型 · typescript · TypeScript 泛型 keyof 对象键 属性读取
- TypeScript keyof 怎样约束对象键并安全读取属性
- 432浏览 收藏
-
- 文章 · 前端 | 1天前 | ArrayBuffer structuredClone transfer
- 前端 structuredClone 怎样处理嵌套可转移对象
- 464浏览 收藏
-
- 文章 · 前端 | 1天前 | 前端 · css · 深色模式 color-scheme light-dark CSS主题
- CSS light-dark 怎样为浅色深色主题切换颜色
- 379浏览 收藏
-
- 文章 · 前端 | 1天前 | 前端 · css · CSS 组件布局 容器查询 container-type @container container-name
- CSS container-type 怎样隔离组件查询范围
- 295浏览 收藏
-
- 文章 · 前端 | 1天前 |
- 前端 PerformanceObserver 怎样接收长任务条目
- 182浏览 收藏
-
- 文章 · 前端 | 1天前 | 前端性能 PerformanceResourceTiming 资源响应时间
- 前端 PerformanceResourceTiming 怎样定位资源响应时间
- 150浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 581次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 620次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 651次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 616次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 432次使用
-
- 接口返回 200 但前端仍报错怎么办:从响应格式到跨域一步步排查
- 2026-06-14 332浏览
-
- golang生成JSON以及解析JSON
- 2023-01-17 329浏览
-
- Go如何实现json字符串与各类struct相互转换
- 2023-01-07 377浏览
-
- Go中使用gjson来操作JSON数据的实现
- 2023-01-07 141浏览
-
- Go 语言 json解析框架与 gjson 详解
- 2023-01-08 203浏览

