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 反馈 — 无需本地设置。
此课程中的所有课时
- ES 模块脚本:type=module
- 导入映射:importmap
- 模块中的动态 import()
- 模块联邦基础