导入断言
基线 2025 *
新推出
注意: 此提案的先前版本使用了 assert 关键字而不是 with。断言功能现在是非标准的。请查看浏览器兼容性表了解详细信息。
导入属性功能指示运行时如何加载模块,包括模块解析、获取、解析和评估的行为。它在import声明、export...from声明和动态import()中都受支持。
属性可以附加到任何类型的 import/export from 语句,包括默认导入、命名空间导入等。它们跟在模块说明符字符串后面,并以 with 关键字开头。当与 import() 一起使用时,属性在 options 参数中作为 with 属性指定。
语法
import { names } from "module-name" with {};
import { names } from "module-name" with { key: "data" };
import { names } from "module-name" with { key: "data", key2: "data2" };
import { names } from "module-name" with { key: "data", key2: "data2", /* …, */ keyN: "dataN" };
export { names } from "module-name" with {};
export { names } from "module-name" with { key: "data" };
export { names } from "module-name" with { key: "data", key2: "data2" };
export { names } from "module-name" with { key: "data", key2: "data2", /* …, */ keyN: "dataN" };
参数
描述
导入属性告诉运行时如何加载特定模块。
主要用例是加载非 JS 模块,例如 JSON 模块和 CSS 模块。考虑以下语句:
import data from "https://example.com/data.json";
在 Web 上,每个 import 语句都会导致一个 HTTP 请求。然后,响应被准备成一个 JavaScript 值,并通过运行时提供给程序。例如,响应可能看起来像这样:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
...
{"name":"Maria"}
模块仅根据其提供的 MIME 类型进行识别和解析——URL 中的文件扩展名不能用于识别文件类型。在这种情况下,MIME 类型是 application/json,它告诉浏览器文件是 JSON 并且必须解析为 JSON。如果由于某种原因(例如,服务器被劫持或虚假),服务器响应中的 MIME 类型设置为 text/javascript(用于 JavaScript 源代码),那么该文件将被解析并作为代码执行。如果“JSON”文件实际上包含恶意代码,import 声明将无意中执行外部代码,构成严重的安全威胁。
导入属性通过允许作者明确指定应如何验证模块来解决此问题。例如,上述缺少属性的导入语句实际上会失败:
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "application/json". Strict MIME type checking is enforced for module scripts per HTML spec.
相反,你必须提供一个属性来告诉运行时此文件必须包含 JSON。要验证模块的类型(通过 MIME 类型),请使用名为 type 的属性键。要验证模块是 JSON 模块,值为 "json"。
注意: 实际的 type 属性值不直接对应于 MIME 类型。它由 HTML 规范单独指定。
因此,上面的代码应改写为:
import data from "https://example.com/data.json" with { type: "json" };
type 属性改变了模块的获取方式(浏览器发送带有 头的请求),但并不改变模块的解析或评估方式。运行时已经知道根据响应 MIME 类型将模块解析为 JSON。它只使用该属性来对 Accept: application/jsondata.json 模块进行事后检查,以确保它确实是一个 JSON 模块。例如,如果响应头改为 Content-Type: text/javascript,程序将以与上述类似的错误失败。
规范明确要求支持 type: "json" — 如果模块被断言为 type: "json" 且运行时不使此导入失败,则它必须被解析为 JSON。但是,否则没有行为要求:对于没有 type: "json" 属性的导入,如果在此环境中安全不是问题,运行时仍可能将其解析为 JSON。另一方面,浏览器隐式假定模块是 JavaScript,如果模块不是 JavaScript(例如 JSON),则会失败。这确保了模块类型始终严格验证并防止任何安全风险。实际上,Node 和 Deno 等非浏览器运行时与浏览器语义保持一致,并对 JSON 模块强制执行 type。
type 属性还支持其他模块类型。例如,HTML 规范还定义了 css 类型,它导入一个 CSSStyleSheet 对象:
import styles from "https://example.com/styles.css" with { type: "css" };
属性语法被设计为可扩展的——尽管语言只指定了 type,但运行时可以读取和处理其他属性。属性可以改变运行时在模块加载过程的每个阶段的行为:
-
解析:该属性是模块说明符(
from子句中的字符串)的一部分。因此,给定相同的字符串路径,不同的属性可能导致加载完全不同的模块。例如,TypeScript 支持resolution-mode属性。tsimport type { TypeFromRequire } from "pkg" with { "resolution-mode": "require" }; -
获取:例如,CSS 模块以
设置为destination"style"获取,JSON 模块以destination: "json"获取。这意味着给定相同的目标 URL,服务器仍可能返回不同的内容。 -
解析和评估:运行时可以使用该属性来确定如何解析和评估模块。
但是,您不能使用未知属性——如果运行时遇到未知属性,它会抛出错误。
示例
使用类型属性导入 JSON 模块
在 data.json 中
{
"name": "Shilpa"
}
在 index.html 中
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8" />
<script type="module">
import data from "./data.json" with { type: "json" };
const p = document.createElement("p");
p.textContent = `name: ${data.name}`;
document.body.appendChild(p);
</script>
</head>
<body></body>
</html>
启动本地 HTTP 服务器(参见故障排除)并访问 index.html 页面。您应该在页面上看到 Shilpa。
注意: JSON 模块只有一个默认导出。您不能从它们进行命名导入(例如 import { name } from "data.json")。
规范
| 规范 |
|---|
| ECMAScript® 2026 语言规范 # prod-WithClause |
浏览器兼容性
加载中…