0Pricing
HTML Academy · 课时

ES 模块脚本:type=module

使用 type=module 将 JavaScript 作为 ES 模块加载

ES 模块脚本:type=module 是 CoddyKit 上的免费 HTML Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 HTML Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 HTML Academy 课程共包含 4 节课。

ES 模块是什么

ES 模块是使用 import 和 export 声明的 JavaScript 文件。模块拥有自己的作用域(不会污染全局作用域),默认采用严格模式,并显式声明依赖项,从而解决了数十年来脚本标签顺序带来的问题。

模块脚本标签

<script type="module" src="app.js"> 告诉浏览器该文件是一个模块。浏览器会解析导入,并行获取依赖项,只有在整个依赖关系图下载并编译完成后,才会执行入口模块。

<script type="module" src="app.js"></script>

模块默认延迟执行

模块脚本的行为如同设置了 defer:它们会与 HTML 解析并行下载,并在解析完成后按照声明顺序执行。您可以将 <script type="module"> 放在任意位置(甚至是 <head> 内),而不会阻塞页面。

导入使用说明符

导入声明使用说明符,可以是相对网址(./utils.js)、绝对网址(https://cdn.example.com/lib.js)或裸名称(lodash)。裸名称需要导入映射表(下一节介绍),因为浏览器不知道它们对应哪个文件。

// app.js
import { sum } from "./utils.js";
import { render } from "https://esm.sh/preact";
console.log(sum(1, 2));

必须提供文件扩展名

浏览器不会自动为导入说明符添加 .js。import "./utils" 会失败,而 import "./utils.js" 可以正常工作。打包工具和 Node 可能更加宽容;浏览器的规则很严格,因此请显式写出扩展名。

必须使用 CORS

模块始终通过 CORS 获取,即使模块与页面同源也是如此。跨源模块文件必须提供适当的 Access-Control-Allow-Origin 响应头,否则导入会失败。大多数 CDN(esm.sh、jsdelivr、unpkg)开箱即用地完成了正确配置。

顶层 await

模块支持在顶层使用 await,无需异步函数包装:const data = await fetch("/api").then(r => r.json())。模块的使用者会等待顶层 await 完成后再执行。

// data.js
export const config = await fetch("/config.json").then(r => r.json());
// app.js (waits for data.js)
import { config } from "./data.js";
console.log(config);

模块是单例

无论有多少其他模块导入,一个模块在每个会话中都只会求值一次。导出对象是共享的——每个使用者看到的都是同一个实例,因此模块是共享配置对象或状态存储等单例的简洁方式。

内联模块

您也可以直接内联编写模块:<script type="module">import x from "./y.js"; ...</script>。这适合编写引导代码或进行实验,不过外部文件更易于调试和缓存。

用 nomodule 实现旧版回退

您可以将 <script type="module"> 与 <script nomodule src="legacy.js"> 配对使用。现代浏览器会运行模块并忽略 nomodule 脚本;旧版浏览器会运行 nomodule 脚本并忽略模块。这种方式用于迁移到全部采用 ESM 的应用期间。

错误和 import 失败

导入失败(404、CORS 或语法错误)会抛出异常,并阻止整个模块图执行。请使用网络面板查找失败的模块请求,并在控制台中查看实际的导入错误消息。

知识检查

为什么模块脚本无需显式指定 defer,也会表现得像设置了 defer 一样?

摘要

<script type="module"> 会加载 ES 模块——这些文件采用严格模式,并包含用于解析依赖关系图的 import/export 声明。模块默认延迟执行,必须显式提供文件扩展名,通过 CORS 获取,并作为单例求值,同时支持顶层 await。请使用 nomodule 实现旧版回退,并注意导入缺少文件扩展名时可能会静默失败。

常见问题解答

「ES 模块脚本:type=module」课时是免费的吗?

是的 — 「ES 模块脚本:type=module」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 HTML Academy 课程的其余内容,请升级到 CoddyKit PRO。 HTML Academy 课程共包含 4 节课。

「ES 模块脚本:type=module」这节课中我会学到什么?

使用 type=module 将 JavaScript 作为 ES 模块加载 你通过在浏览器中直接运行的动手代码来练习 HTML Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 HTML Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 HTML Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「ES 模块脚本:type=module」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 HTML Academy 课中编写并运行代码吗?

能。每节 HTML Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. ES 模块脚本:type=module
  2. 导入映射:importmap
  3. 模块中的动态 import()
  4. 模块联邦基础
← 返回 HTML Academy