在 ES 模块中导入 JSON(无需 Fetch,无需打包工具)
如果你曾经在纯 ES 模块项目中尝试过 import config from './config.json' 并碰壁,你并不孤单。多年来,在没有打包工具的情况下导入 JSON 意味着只能退而求其次使用 fetch() 或将数据转换为 JavaScript 文件。这种变通方法的时代已经结束了。
截至 2025 年,**导入属性(import attributes)**已在现代浏览器中全面支持。你现在可以进行原生 JavaScript JSON 模块导入,无需任何构建工具。
核心要点
- 使用
with { type: 'json' }在 ES 模块中原生导入 JSON——无需打包工具或fetch()。 type属性是强制性的,出于安全考虑:它确保运行时在处理文件之前验证 MIME 类型。- JSON 模块仅公开默认导出。导入后需要从中解构。
- 你的 JSON 文件必须通过 HTTP 提供,并带有正确的
Content-Type: application/json头。
现代语法:导入属性
当前语法使用 with 关键字来声明模块类型:
// Static import
import config from './config.json' with { type: 'json' }
console.log(config.apiUrl)
对于动态加载:
// Dynamic import
const { default: config } = await import('./config.json', {
with: { type: 'json' }
})
注意: 旧的
assert { type: 'json' }语法(在 Chrome 91–122 中支持)现已弃用。请始终使用with。
为什么 type: 'json' 属性是必需的
with { type: 'json' } 属性不是可选的装饰。它具有特定的安全目的:它强制浏览器或运行时在处理任何内容之前将响应的 MIME 类型验证为 application/json。
如果没有它,服务器可能会返回伪装成 JSON 文件的 JavaScript,而引擎将无法强制执行这种区分。type 属性可以防止这种情况。
JSON 模块仅具有默认导出
有一点会让开发者困惑:JSON 模块不支持命名导出。整个 JSON 对象作为默认导出传入。
import data from './data.json' with { type: 'json' }
// ✅ 正确
const { users, settings } = data
// ❌ 这样不行
import { users } from './data.json' with { type: 'json' }
导入后从默认导出中解构。
Discover how at OpenReplay.com.
浏览器和 Node.js 支持
| 环境 | 最低版本 |
|---|---|
| Chrome | 123+ |
| Firefox | 138+ |
| Safari | 17.2+ |
| Node.js | 当前 LTS 及更新版本 |
所有这些现在都已广泛部署。如果你的目标是现代浏览器和当前的 Node.js 版本,则无需打包工具或 fetch() 调用来加载 JSON。
注意: 早期的 Node.js 版本在实验性标志后提供 JSON 模块。带有导入属性的 JSON 模块支持现在在当前的 Node.js 版本中已经稳定。有关确切的版本详细信息,请参阅 Node.js ESM 文档。
发布前需要了解的实际限制
你需要一个 HTTP 服务器。 模块导入——包括 JSON 模块——通常在通过 file:// 直接加载页面时不起作用。浏览器对模块加载应用严格的安全规则。请使用本地开发服务器,如 Vite、serve 或任何静态文件服务器。
你的 JSON 文件必须使用正确的 MIME 类型提供。 服务器需要返回 Content-Type: application/json。大多数静态服务器会自动为 .json 文件处理此问题,但如果你使用自定义服务器或 CDN 配置,请仔细检查。
JSON 必须有效。 在导入级别没有错误恢复。JSON 文件中的语法错误将导致模块完全无法加载。在部署之前验证你的 JSON。
实际示例
// config.json
{
"apiUrl": "https://api.example.com",
"timeout": 5000,
"features": {
"darkMode": true
}
}
// app.js
import config from './config.json' with { type: 'json' }
const { apiUrl, timeout, features } = config
if (!apiUrl || typeof timeout !== 'number') {
throw new Error('Invalid configuration')
}
这种模式适用于配置文件、功能标志、国际化字符串或应用程序启动时需要的任何静态结构化数据。
结论
导入属性为你提供了一种简洁、原生的方式在 ES 模块中导入 JSON,无需 fetch(),无需打包工具,也无需变通方法。with { type: 'json' } 语法现在在现代浏览器和当前的 Node.js 版本中得到广泛支持。只需确保你的文件通过 HTTP 提供并使用正确的 MIME 类型,就可以了。
常见问题
可以。导入属性提案被设计为可扩展的。例如,CSS 模块脚本在支持的浏览器中使用 with { type: 'css' }。但是,JSON 是目前支持最广泛的类型。其他类型取决于运行时,可能尚未在所有地方可用。
导入将完全失败并抛出 SyntaxError。与 fetch 不同(你可以捕获并检查原始响应),JSON 模块导入不提供部分恢复。在部署之前使用 linter 或 CI 检查验证你的 JSON 文件,以避免加载时的静默故障。
对于 JSON 导入本身不需要。现代浏览器和 Node.js 原生支持它。但是,出于其他原因,如代码分割、tree shaking 或为旧目标转译语法,你可能仍然需要打包工具。关键是仅 JSON 加载本身不再需要打包工具。
浏览器对模块加载执行严格的安全规则。file 协议不支持模块请求所需的机制,因此浏览器会阻止导入。你需要通过 HTTP 服务器提供文件,即使是在本地。像 Vite 或 serve npm 包这样的工具可以用最少的设置来处理这个问题。
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.