はじめに
「ちょっとReactの挙動を試したいだけなのに、npm installして、bundlerを設定して……」そんな経験はありませんか?たった数行のコードを動かすために、node_modulesに数百MBのファイルが生成され、ビルド設定に時間を溶かす。モダンフロントエンド開発の"儀式"に疲れている方は多いはずです。
そこで注目したいのがesm.shです。URLをひとつ書くだけで、npmパッケージをESモジュールとしてブラウザから直接インポートできるCDNサービスです。この記事では、esm.shの基本から実践的な活用法までを解説します。
esm.shとは
esm.shは「A no-build JavaScript CDN」を掲げるコンテンツ配信サービスです。npmに公開されているパッケージを、リクエストに応じてESモジュール形式に変換して配信してくれます。CommonJS形式でしか提供されていない古いパッケージでも、esm.shを経由すればブラウザのimport文でそのまま読み込めるのが最大の魅力です。
Cloudflareのグローバルネットワーク上で動作しており、変換結果はエッジにキャッシュされるため、2回目以降のアクセスは高速です。
主な特徴
- ノービルド -
npm installもbundlerも不要。URLを書くだけでパッケージが使えます - CommonJSの自動変換 - ESM非対応のパッケージもESモジュールとして配信されます
- TypeScript型定義の自動配信 -
X-TypeScript-Typesヘッダで型情報が提供され、DenoやエディタでそのままIntelliSenseが効きます - 複数レジストリ対応 - npmだけでなく、JSR(
/jsr/)、GitHubリポジトリ(/gh/)からも取得できます - 豊富なビルドオプション - クエリパラメータでtree shakingやターゲット指定などを細かく制御できます
インストール
esm.shはCDNサービスなので、インストール作業は一切不要です。HTMLファイルとブラウザさえあれば始められます。
<script type="module">
import confetti from "https://esm.sh/canvas-confetti@1.9.3";
confetti();
</script>
このHTMLをブラウザで開くだけで、紙吹雪が舞います。package.jsonもnode_modulesも必要ありません。
基本的な使い方
バージョン指定
URLのパスでsemverによるバージョン指定ができます。本番で使う場合はバージョンを固定するのがおすすめです。
// 最新版(開発時のみ推奨)
import React from "https://esm.sh/react";
// バージョン固定
import React from "https://esm.sh/react@19.2.0";
// メジャーバージョンのみ指定
import React from "https://esm.sh/react@19";
// サブモジュールのインポート
import { renderToString } from "https://esm.sh/react-dom@19.2.0/server";
Import Mapsとの組み合わせ
URLを毎回書くのは冗長なので、実際の開発ではimport mapsと組み合わせるのが定番です。ベア指定子(reactのような通常のパッケージ名)で書けるようになります。
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@19.2.0",
"react-dom/client": "https://esm.sh/react-dom@19.2.0/client"
}
}
</script>
<script type="module">
import { createRoot } from "react-dom/client";
// 通常のnpmプロジェクトと同じ書き味で開発できます
</script>
便利なクエリパラメータ
esm.shの真骨頂は、クエリパラメータによる柔軟なビルド制御です。
// 必要なエクスポートだけを取得(tree shaking)
import { debounce } from "https://esm.sh/lodash-es@4.17.21?exports=debounce";
// 開発モードでビルド(Reactの詳細なエラーメッセージが出ます)
import React from "https://esm.sh/react@19.2.0?dev";
// ビルドターゲットを指定
import dayjs from "https://esm.sh/dayjs@1.11.13?target=es2022";
// Web Workerとしてロード
import workerFactory from "https://esm.sh/monaco-editor@0.52.0/esm/vs/editor/editor.worker?worker";
特に?exportsは効果が大きく、lodashのような大きなライブラリから関数ひとつだけを取り出す場合に転送量を大幅に削減できます。
実践的なユースケース
ビルドなしでReact + TSXを動かす
esm.shが提供するesm.sh/tsxという約1KBのスクリプトを読み込むと、HTML内に書いたTSXをそのまま実行できます。コンパイルはesm.shのサーバー側で行われ、結果はキャッシュされます。
<!DOCTYPE html>
<html>
<head>
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@19.2.0",
"react-dom/client": "https://esm.sh/react-dom@19.2.0/client"
}
}
</script>
<script type="module" src="https://esm.sh/tsx"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
import { useState } from "react";
import { createRoot } from "react-dom/client";
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
クリック数: {count}
</button>
);
}
createRoot(document.getElementById("root")).render(<Counter />);
</script>
</body>
</html>
このファイルをブラウザで開くだけで、状態を持つReactコンポーネントが動きます。プロトタイピングや社内ツール、技術検証にはこれで十分というケースも多いのではないでしょうか。
依存関係の共有とバージョン制御
複数のライブラリが同じ依存を持つ場合、?externalで外部化してimport mapsに解決を委ねることで、Reactの二重ロードのような問題を防げます。
<script type="importmap">
{
"imports": {
"preact": "https://esm.sh/preact@10.27.0",
"preact-render-to-string": "https://esm.sh/preact-render-to-string@6.6.1?external=preact"
}
}
</script>
https://esm.sh/*パッケージ名のようにアスタリスクを付けると、すべての依存を一括で外部化することもできます。
Denoでnpmパッケージを使う
esm.shはDenoフレンドリーな設計で、Node.jsの組み込みモジュール(fs、osなど)への依存も解決してくれます。型定義も自動で配信されるため、エディタ補完も効きます。
// main.ts
import chalk from "https://esm.sh/chalk@5.4.1";
console.log(chalk.green("DenoからnpmパッケージをESMで利用できます"));
deno run main.ts
GitHubリポジトリから直接インポート
npmに公開されていないパッケージでも、/gh/プレフィックスでGitHubから直接取得できます。タグやコミットハッシュの指定も可能です。
import tslib from "https://esm.sh/gh/microsoft/tslib@2.8.0";
まとめ
esm.shは、URLひとつでnpmパッケージをESモジュールとして利用できるノービルドCDNです。本記事のポイントを振り返ります。
- インストール・ビルド不要で、HTMLとブラウザだけで開発を始められます
- import mapsと組み合わせれば、通常のnpmプロジェクトに近い書き味になります
?exportsや?externalなどのクエリパラメータで、転送量や依存解決を細かく制御できますesm.sh/tsxを使えばTSXすらビルドなしで動かせます- Deno・JSR・GitHubにも対応した、モダンなエコシステムのハブ的存在です
大規模な本番アプリケーションではViteなどのビルドツールに軍配が上がる場面も多いですが、プロトタイピング、技術検証、小規模ツール、教育用途では、esm.shの手軽さは圧倒的です。まずはHTMLファイルをひとつ作って、お気に入りのライブラリをURLでインポートしてみてください。「ビルドしない開発」の快適さに驚くはずです。