ES Module Shims 2.0 发布公告
版权声明
翻译与转载须知:
本译文仅供教育和信息交流之用。所有知识产权(包括版权)均归原作者和/或出版商所有。本译文在保持原文内容完整性的同时,旨在使其更易于中文读者理解。
修改声明:
- 本文为原文的完整忠实译本,未进行任何实质性修改。
- 本译文包含为提升中文读者清晰度而做的微小调整,同时保留了所有基本信息和观点。
- 标有 [†] 的部分包含译者为提供文化或技术背景而添加的补充说明。
权利保留:
如果您是版权所有者,并认为本译文超出了合理使用范围,请通过 邮箱 与我们联系。我们致力于尊重知识产权,并将及时处理任何正当关切。
ES Module Shims 2.0 现已正式发布,这是一个全面的 13KB 轻量级 polyfill,支持 import maps、多重 import maps、CSS 和 JSON 导入、WebAssembly 模块以及 Source Phase 导入。
如果你不了解这些功能是什么,下文会有详细介绍。但首先,我想强调 2.0 版本中的一项重要新功能:TypeScript 类型擦除支持。
TypeScript类型擦除支持
为什么要在浏览器中编译 TypeScript?背景是,ES Module Shims 是一个 非常 快速的 module polyfill,目的是为了在支持基本的模块系统的浏览器上填补所有新的模块特性。因此,TC39 的类型注解提案恰好符合这个项目的 polyfill 定义。此外,通过在浏览器中使用来自 Node.js 的 Amaro 项目中定义的 TypeScript 变体,提供直接的逐源重写(类型擦除或可擦除语法),我们实际上获得了一个非常快速的工作流程。
它实现了 无构建 工作流 - TypeScript 作为最后一环,提供了一种无需构建工具、Node.js 或 npm 的精简型 Web 开发方法。
以下是一个实际的例子,这是一个用 TypeScript 编写的 Vue 组件:
import { defineComponent } from 'vue';
import style from './user-card.css' with { type: 'css' };
document.adoptedStyleSheets.push(style);
export interface User {
name: string;
age: number;
}
export default defineComponent({
props: {
user: {
type: Object as () => User,
required: true,
},
},
template: `<div class="user-card">{{ user.name }} <span class="age">({{ user.age }})</span></div>`,
});在上面的代码中,我们不仅使用了 TypeScript,还使用了新支持的 CSS Module Scripts 特性来模块化加载组件的 CSS:
.user-card {
padding: 1.2rem;
border-radius: 16px;
margin: 1rem;
font: 500 18px system-ui;
width: 300px;
background: linear-gradient(135deg, #eee 0%, #fafafa 100%);
box-shadow: 2px 5px 7px rgba(100, 100, 255, 0.2);
transition: transform 0.2s ease;
cursor: pointer;
}
.user-card:hover {
transform: translateY(-2px);
}
.age {
color: #726497;
}现在,使用 ES Module Shims,我们可以使用单个 HTML 文件和静态文件来运行这个应用,通过 polyfill 支持 CSS Module Scripts 和 TypeScript,而不需要任何构建过程或其他步骤:
<!doctype html>
<!-- 从你选择的CDN加载ES Module Shims -->
<script
async
src="https://ga.jspm.io/npm:es-module-shims@2.0.9/dist/es-module-shims.js"
></script>
<!-- 启用TypeScript和CSS导入功能(默认情况下只有import maps被polyfill) -->
<script type="esms-options">
{ "polyfillEnable": ["typescript", "css-modules"] }
</script>
<!-- 在import map中设置依赖项 -->
<script type="importmap">
{
"imports": {
"vue": "https://ga.jspm.io/npm:vue@3.5.13/dist/vue.esm-browser.prod.js"
}
}
</script>
<div id="app">
<user-card v-for="user in users" :key="user.name" :user="user" />
</div>
<!-- ES Module Shims会找到这个并处理剩余部分 -->
<script type="module" lang="ts">
import { createApp } from 'vue';
import UserCard, { type User } from './user-card.ts';
createApp({
setup() {
const users: User[] = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
];
return { users };
},
})
.component('user-card', UserCard)
.mount('#app');
</script>你可以在 这里 查看完整示例。
支持多个 Import Map
任何使用过 import maps 一段时间的人都会知道令人恐惧的 "An import map is added after module script load was triggered."(模块脚本加载触发后添加了 import map)错误。感谢 Yoav Weiss 的努力工作,我们现在在最新版本的 Chrome 中支持多重 import maps。
ES Module Shims 2.0 包含了这个功能的 polyfill,它能检测何时使用了多个 import maps,然后按照标准 polyfill 失败语义 检查模块是否依赖于新 import map 中存在但旧 import map 中不存在的映射。实际上,我们可以在单一 import maps 支持的基础上 polyfill 多重 import maps,现在可以在可能的情况下共享原生模块加载器和注册表,就像我们在旧浏览器中基于非 import maps 模块支持 polyfill import maps 本身一样。
此外,通过对 body 和 head 标签使用变异观察器(mutation observers),我们还可以检测何时动态注入 import map,然后为动态加载工作流程应用相同的 polyfill(前提是新的动态导入通过全局 importShim() 的 polyfill 来加载)。
Wasm 模块和 Source 语义导入规范
通常,WebAssembly 是使用 fetch('./module.wasm').then(WebAssembly.compileStreaming).then(...) 这样的方式加载,来获取 WebAssembly.Module 对象进行初始化。
在这些工作流程中,由于 baseURL 语义的存在,获取 Wasm 二进制文件的 URL 并不总是那么简单。此外,构建工具可能难以与这种代码良好配合,在许多情况下需要二进制路径的运行时配置。
通过 source 语义导入规范,我们现在可以通过可移植的方式直接导入 Wasm 二进制文件,当启用该功能时,ES Module Shims 完全支持:
<!doctype html>
<script
async
src="https://ga.jspm.io/npm:es-module-shims@2.0.9/dist/es-module-shims.js"
></script>
<!-- Enable the WebAssembly and Source Phase features -->
<script type="esms-options">
{ "polyfillEnable": ["wasm-modules", "source-phase"] }
</script>
<script type="module">
import source mod from './module.wasm';
const { fn } = new WebAssembly.Instance(mod, ...options...);
</script>最后,如果你仍然好奇 ES Module Shims 是如何工作的,我之前写过一篇关于 how ES Module Shims became a production import maps polyfill 的文章。