Skip to content

Instantly share code, notes, and snippets.

@ikasoba
Last active January 30, 2024 06:56
Show Gist options
  • Save ikasoba/2aec36e5d5ea697665401c2866e635f3 to your computer and use it in GitHub Desktop.
Save ikasoba/2aec36e5d5ea697665401c2866e635f3 to your computer and use it in GitHub Desktop.
esm.shについて

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から読み込む場合

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用の言語サーバーなので、ブラウザにはない挙動をすることがある。

ブラウザのesmoduleの挙動のメモ

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment