ES Module Shims 2.0 发布公告
Refer
Source
: Announcing ES Module Shims 2.0
Author
: Guy Bedford
Translator
: SenaoXi
Release Time
: February 24, 2025
Copyright Statement
Translation and Republication Notice:
This translation is provided for educational and informational purposes only. All intellectual property rights, including copyright, remain with the original author and/or publisher. This translation maintains the integrity of the original content while making it accessible to chinese readers.
Modifications Disclosure:
- This is a complete and faithful translation of the original content with no substantive modifications.
- This translation includes minor adaptations to improve clarity for chinese readers while preserving all essential information and viewpoints.
- Sections marked with [†] contain supplementary explanations added by the translator to provide cultural or technical context.
Rights Reservation:
If you are the copyright holder and believe this translation exceeds fair use guidelines, please contact us at email. We are committed to respecting intellectual property rights and will promptly address any legitimate concerns.
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
的文章。