この記事を書いたきっかけ
Node.jsとかでライブラリ作りたいなと思いまして
基本はnpm
でインストールしてNode.js上で動作するだけでもいいけど
ブラウザ上でscript
タグで読み込むだけでも使えるようにもしたいな
つまり、こういうことをやりたい
<script src="mylib.js"></script>
<script>
MyLib.init();
</script>
あれ、でもNode.jsで作ったライブラリって
どうやってブラウザ上で使えるようにするんだろう。
普通にwindow.<プロパティ>
にぶち込むだけ?
というのを調べてみたお話。
この記事の結論
現時点ではブラウザ上で動作してるってことをなんらかで判定しつつ
最終的にwindow.<プロパティ>
にぶち込むのが安定という気がしました。
const message = "Hello World";
if (typeof window !== "undefined") {
window.message = message;
}
あとは現在ECMAScriptにglobalThis
というものが試験実装されてるようなので
この先のどこかのタイミングではglobalThis
に統一される事になる?という妄想をしています。
普通のJavaScriptとscriptタグ
const message = "Hello World";
<script src="index.js"></script>
<script>
console.log(message);
</script>
Hello World
通常のjsはindex.js
で定義されたmessage
がそのファイルの外でも使える。
scriptタグにtype=moduleを設定する
script
タグにtype="module"
を指定するとJavaScriptファイルがモジュールとして扱われ
ESModule仕様でimport/exportが使える。(一部ブラウザは非対応)
const message = "Hello World";
<script type="module" src="index.js"></script>
<script>
console.log(message);
</script>
Uncaught ReferenceError: message is not defined
結果はmessage
が定義されてないとエラーになる。
エラーになる原因は2つ。
1. モジュール内の変数はファイル内スコープである
モジュールの外で使うにはそもそもexport
しなきゃいけないし
使うときはimport
してやらないとだめ。
2. index.js
が読み込まれる前にconsole.logが実行されちゃう
そもそもconsole.log
のタイミングでまだindex.js
がロードされてない。
(モジュールだと非同期読み込みになるから)
HTML上で変数(message)を使えるようにする
index.js
の変数をどうやってhtml
側で利用するか
実験 その1
export
してimport
する
const message = "Hello World";
export default message;
<script type="module">
import message from './index.js'; // ./とか.jsをちゃんと書かないと怒られた
console.log(message);
</script>
Hello World
type="module"
を指定し、Scriptをmoduleとして扱う事でimport
することができる。
(IE11が相変わらず対応してないが)
実験 その2
window.message
に突っ込む
const message = "Hello World";
window.message = message;
<script type="module" src="index.js"></script>
<script>
// 上記のスクリプトは非同期で読み込まれるので、ロード後に処理する
window.onload = function() {
console.log(message)
}
</script>
Hello World
これは昔ながらの方法なのでtype="module"
だろうと
昔ながらのJavaScriptだろうと
どっちでもいけるパターン。
type="module"ってどうなの
色々とあるけど、type="module"
を実用化するにはあともう少しという気がします。
(もうIE11もなくなるっぽいし、古いブラウザやニッチなブラウザを捨てちゃえばいいんだよもうって思う)
最終的にこれに統一される日は早くきて欲しい。
Node.jsのモジュールがcommonjs(亜種)仕様だったり
Node.jsでも拡張子を.mjs
にすればESModule構文使えるけど、.mjs
で作るのも微妙だったり
結局はwebpackやらparcelやらxxxxxfyなど何らかのバンドラーでバンドルしちゃうのが安定かなぁ。
そしてバンドルするなら`type="module"も直近ではいらないという結論に落ち着く
まとめ
諸々の状況を鑑みると、Node.jsで作ったクラスなり関数なりを
HTML上で使えるようにするには
必要なものをwindow.<プロパティ>
にぶち込んで公開する。
という方法でいいという結論に落ち着きました。