此页面由社区从英文翻译而来。了解更多并加入 MDN Web Docs 社区。

View in English Always switch to English

导入属性

基线 2025 *
最近可用

自 April 2025 起,此特性已在最新浏览器中得到支持。但在较旧的设备或浏览器中可能无法运行。

* 此特性的某些部分的支持程度可能有所不同。

备注:该提案的早期版本使用 assert 关键字而非 with。断言特性现在并不属于标准。详情请查看浏览器兼容性表格

导入属性(import attribute)特性指示运行时如何加载模块,包括模块路径解析、获取、语法解析和执行的行为。它支持 import 声明、export...from 声明和动态 import()

属性可以附加到任何类型的 import/export from 语句,包括默认导入、命名空间导入等。它们跟在模块标识符字符串之后,以 with 关键字开头。与 import() 一起使用时,属性在 options 参数中作为 with 属性指定。

语法

js
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" };

参数

keyN

属性键。可以是标识符或字符串字面量。所有键必须唯一,且必须被运行时识别。

"dataN"

属性值。必须是字符串字面量。

异常

SyntaxError

静态导入中指定了不支持的 key

TypeError

动态导入中指定了不支持的 key

请注意,在某些情况下,为支持的键指定不支持的值也可能导致异常,具体取决于该键。

描述

导入属性告诉运行时如何加载特定模块。

主要用例是加载非 JS 模块,例如 JSON 模块和 CSS 模块。考虑以下语句:

js
import data from "https://example.com/data.json";

在 Web 上,每个导入语句都会触发一个 HTTP 请求。运行时随后将响应处理为 JavaScript 值,并提供给程序。例如,响应可能如下所示:

http
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
...
{"name":"Maria"}

模块仅根据其提供的媒体类型(MIME 类型)进行识别和解析——URL 中的文件扩展名不能用于识别文件类型。在这种情况下,MIME 类型是 application/json,它告诉浏览器该文件是 JSON,必须作为 JSON 解析。如果由于某种原因(例如,服务器被劫持或伪造),服务器响应中的媒体类型被设置为 text/javascript(对于 JavaScript 源代码),那么该文件将被解析并作为代码执行。如果“JSON”文件实际上包含恶意代码,import 声明将无意中执行外部代码,构成严重的安全威胁。

导入属性通过允许作者明确指定如何验证模块来解决这个问题。特别是,type 属性允许你验证文件是否以特定媒体类型提供,如果使用不同的媒体类型,则导入失败。

例如,上面的代码可以写成指定预期类型为 "json",如果它以 text/javascript(或 application/json 以外的任何媒体类型)提供,则导入将失败:

js
import data from "https://example.com/data.json" with { type: "json" };

type 属性允许你指定模块以 JSON、CSS 或纯文本(以及隐式地作为 JavaScript)提供。

其他属性也可能受支持,并且可以影响加载过程不同部分的行为。如果使用未知属性,将抛出语法错误。

标准属性

可用属性取决于语言和运行时环境。ECMAScript 标准定义了值为 "json""text"type 属性

HTML 规范也定义了值为 "json""text""css"type 属性——这些是在浏览器环境中受支持的属性。

JSON 模块({ type: "json" }

json 类型表示导入的文件必须包含 JSON。 你可以使用以下代码将 JSON 从文件加载到 data 对象中:

js
import data from "https://example.com/data.json" with { type: "json" };

如果文件以 "application/json" 以外的任何媒体类型提供,导入将失败。

type 属性会改变模块的获取方式(浏览器发送请求时带有 Accept: application/json 标头),但不会改变模块的解析或执行方式。运行时已经知道根据响应的 MIME 类型将模块解析为 JSON。它仅使用该属性进行事后检查,以确保 data.json 模块确实是 JSON 模块。例如,如果响应标头更改为 Content-Type: text/javascript,程序将以上述类似的错误失败。

规范明确要求支持 type: "json"——如果模块被声明为 type: "json" 且运行时未使该导入失败,则必须将其解析为 JSON。

然而,除此之外没有其他行为要求:对于没有 type: "json" 属性的导入,如果此环境中安全问题不是问题,运行时仍可能将其解析为 JSON。

另一方面,浏览器隐式假设如果未指定 type,则模块是 JavaScript,如果模块不是 JavaScript(例如 JSON),则失败。这确保了模块类型始终经过严格验证,并防止任何安全风险。 Node 和 Deno 等非浏览器运行时与浏览器语义保持一致,并对 JSON 模块强制要求 type

换句话说,如果你省略 type 并尝试以 "application/json" 导入文件,通常会收到如下错误:

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.

CSS 模块({ type: "css" }

HTML 规范定义了 css 类型,它将样式表作为 CSSStyleSheet 对象导入到脚本中。

下面的代码展示了如何导入样式并将其添加到你的文档中。如果 example_styles.css"text/css" 以外的任何媒体类型提供,导入将抛出异常。

js
import exampleStyles from "https://example.com/example_styles.css" with { type: "css" };

document.adoptedStyleSheets.push(exampleStyles);

请注意,通常不支持将 CSS 模块导入到 worker 中,因为 CSSOM 规范仅在 window 上下文中暴露 CSSStyleSheet

文本模块({ type: "text" }

text 类型允许将模块的源代码作为字符串值导入。你可以使用以下代码将文本从文件加载到 text 字符串中:

js
import text from "https://example.com/file.txt" with { type: "text" };

文件将使用 Accept: text/plain 标头进行请求,但响应的 Content-Type 标头的值被忽略,所有文件都以 UTF-8 解析。它可以包含任何文本数据,甚至是 JavaScript 代码(被视为纯文本)。

导入属性的预期语义

属性可以在模块加载过程的每个阶段改变运行时的行为:

  • 路径解析:该属性是模块标识符(from 子句中的字符串)的一部分。因此,给定相同的字符串路径,不同的属性可能导致加载完全不同的模块。例如,TypeScript 支持 resolution-mode 属性

    ts
    import type { TypeFromRequire } from "pkg" with {
      "resolution-mode": "require",
    };
    
  • 获取:例如,获取 CSS 模块时会将 destination 设置为 "style",获取 JSON 模块时 destination: "json",获取文本模块时 destination: "text"。这意味着即使目标 URL 相同,服务器仍可能返回不同的内容。

  • 语法解析和执行:运行时可以使用属性来确定如何解析和执行模块。

示例

使用 type 属性导入 JSON 模块

data.json 中:

json
{
  "name": "Shilpa"
}

index.html 中:

html
<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8" />
    <script type="module">
      import data from "./data.json" with { type: "json" };

      const p = document.createElement("p");
      p.textContent = `名称:${data.name}`;
      document.body.appendChild(p);
    </script>
  </head>
  <body></body>
</html>

启动本地 HTTP 服务器(请参阅故障排除)并访问 index.html 页面。你应该会在页面上看到 Shilpa

备注:JSON 模块只有一个默认导出。你不能对它们进行命名导入(如 import { name } from "data.json")。

在动态导入中使用导入属性

import() 语法的第二个参数同样支持传入导入属性。

js
const data = await import("./data.json", {
  with: { type: "json" },
});

请注意,与静态导入一样,动态导入在环境的生命周期内(例如,页面或 worker)会被缓存。如果你期望此数据会发生变化(例如最新新闻或用户的积分),请改用 Fetch API

规范

规范
ECMAScript® 2027 Language Specification
# prod-WithClause

浏览器兼容性

参见