百聞は一見に如かず
空のHTMLファイルにコピペしてウェブブラウザで開いてみてください。
<!doctype html>
<meta charset="utf-8">
<script async type="module">
import {transpile, ScriptTarget} from "https://esm.sh/typescript@5.3.3?bundle&target=esnext";
import {minify_sync} from "https://esm.sh/terser@5.27.0?bundle&target=esnext";
for(const {type, textContent} of document.getElementsByTagName("script")){
if(type !== "text/typescript" || !textContent){
continue;
}
const js = transpile(textContent, {
target: ScriptTarget.ESNext
});
const {code} = minify_sync(js, {
module: true
});
await import(`data:text/javascript;base64,${btoa([...new TextEncoder().encode(code)].map(v => String.fromCharCode(v)).join(""))}`);
}
</script>
<script type="text/typescript">
interface Test{
a: string;
b: number;
c: boolean;
}
const test:Test = {
a: "aaa",
b: 111,
c: true
};
await new Promise<void>(done => setTimeout(done, 100));
console.log(test);
document.getElementById("status").textContent = "Complete!";
</script>
<title>TypeScript on Web</title>
<h1>TypeScript on Web</h1>
<p>TypeScript realtime transpile and execution demo.</p>
<p>[Status] <span id="status">Processing...</span></p>
何が起きている?
まず esm.sh はESMを配信するCDNです。
新進気鋭ということで高機能かつ使いやすく、旧来の jsdelivr や unpkg などの上位互換となり得そうです。
1. TypeScript記述
ウェブブラウザは読み込み時に script
要素の type
属性を見てJavaScriptかどうかを識別し、実行する仕様となっています。
(無い場合は暗黙的にJavaScriptと見なす)
この挙動を利用し、明示的にメディアタイプを指定することでTypeScriptを記述しつつ実行を阻止しています。
2. トランスパイル
typescript をインポートしています。
これは本家本元のTypeScriptパッケージです。
script
要素のうち、メディアタイプがTypeScriptな要素のみを抽出しJavaScriptにトランスパイルします。
3. ソースコード圧縮
terser をインポートしています。
これはソースコード圧縮、いわゆる「ミニファイ」を行うパッケージです。
トランスパイルしたJavaScriptを圧縮します。
4. 動的インポート
実はESMの import
はDataURLも読み込めます。
つまりスクリプトを直接埋め込めるわけです。
圧縮したJavaScriptをDataURLへ変換し埋め込み実行します。
export
は存在せず、ただスクリプトの内容を上から実行できれば良いので、特に代入はしません。
このとき、スクリプトはUTF-8でエンコードしBASE64へ変換しています。
マルチバイト文字や空白をURLとして認識できないためです。
また、スクリプト(DataURL)の肥大化によりインポート処理が不安定になる可能性を低減するため、前項で圧縮しています。
まとめ
ちなみに同じ理論で SASS/SCSS も行けます。
が、こちらは既に CSS Nesting があるので...
是非 ECMAScript Type Annotations も何卒よろしくお願い致します...
意外とそのままウェブブラウザで動くnpmパッケージは多いので、ダメ元でesm.shに打ち込んで試してみるのはアリ。
Node.jsやOS固有の機能を呼び出してる場合は当然ながら動かないです。