esm.shは、npmのパッケージとかをブラウザのesmoduleで読めるようにしてくれるやつだね。
公式ドキュメントも存在するよ
nodejsでnpmパッケージを読み込むのとあまり変わらない感覚で使えるよ
※ URLからimportするから最初はちょっと戸惑うかもしれないけど
esm.shは内部でesbuildを使ってパッケージをビルドしててサーバーサイドはgolangで実装されてたりするよ https://github.com/esm-dev/esm.sh
だいたいこんな形式でimportできたりする
// URLから読み込むので `npm i ...` するも必要もない
import { h, render } from "https://esm.sh/preact";
render(
h("h1", null, "Hello, world!"),
document.body
);
こんなこともできる
import dayjs from "https://esm.sh/dayjs";
import * as Preact from "https://esm.sh/preact";
バージョンを指定するときはこんな感じ
import { h, render } from "https://esm.sh/[email protected]";
パッケージのサブパスを参照するときはこう
import { h, render } from "https://esm.sh/preact/hooks";
// バージョンを指定しながらだとこうする
import { useState } from "https://esm.sh/[email protected]/hooks";
nodejsには --experimental-network-imports
というフラグがあって、実行時にこれを付けてあげると一応nodejsからも読み込める
import { faker } from "https://esm.sh/@faker-js/faker";
console.log(faker.animal.type());
$ node --experimental-network-imports ./index.mjs
cow
通常のnodejs向けの言語サーバーだとURLから型情報の読み込みはできなかったりする。
nodejsとは別のDenoというjsのランタイム向けに作られた言語サーバーあれば対応しているのでVSCodeであればDenoプラグインをインストールすればURLから型情報を読み込んでくれたりする。
![NOTE] あくまでDeno用の言語サーバーなので、ブラウザにはない挙動をすることがある。
htmlで使うにはscriptタグのtype属性にmodule
を指定しないとesmoduleなコードとして読み込んでくれなかったりする
<script type="module">
import { h, render } from "https://esm.sh/preact";
function App() {
return (
h("h1",null, "Hello, esm.sh!")
);
}
window.addEventListener("load", () => {
render(h(App, null), document.body);
});
</script>
<!-- jsファイルを読むなら -->
<script type="module" src="./index.js"></script>
devtoolsのreplや、type="module"
を指定しなかったscriptタグだとimport文がつかえないから、動的インポートする必要があったりするね
(async() => {
const { ... } = await import("https://esm.sh/dayjs");
})();
手書きでimportするのは辛いから大体の場合はimportmapと併用されてたりするよ
<!--
importmapはjsonで書くよ
https://developer.mozilla.org/ja/docs/Web/HTML/Element/script/type/importmap
-->
<script type="importmap">
{
"imports": {
"preact/": "https://esm.sh/[email protected]/",
"preact": "https://esm.sh/[email protected]"
}
}
</script>
<!--
これは今の所できなかったりする
<script type="importmap" src="./importmap.json"></script>
この挙動についてはこのissueで議論されているらしい?
https://github.com/WICG/import-maps/issues/235
-->
<!--
urlを省略して書けるようになるのでとても便利
-->
<script type="module">
import { h, render } from "preact";
import { useState } from "preact/hooks";
function Counter() {
const [count, setCount] = useState(0);
return (
h("button", { onClick: () => setCount(count + 1) }, "count: ", count)
);
}
render(h(Counter, null), document.body);
</script>