HTML
JavaScript
Node.js

Node.jsで作ったライブラリをブラウザ上で使えるようにする


この記事を書いたきっかけ

Node.jsとかでライブラリ作りたいなと思いまして

基本はnpmでインストールしてNode.js上で動作するだけでもいいけど

ブラウザ上でscriptタグで読み込むだけでも使えるようにもしたいな

つまり、こういうことをやりたい


index.html

<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タグ


index.js

const message = "Hello World";



index.html

<script src="index.js"></script>

<script>
console.log(message);
</script>


console

Hello World


通常のjsはindex.jsで定義されたmessageがそのファイルの外でも使える。


scriptタグにtype=moduleを設定する

scriptタグにtype="module"を指定するとJavaScriptファイルがモジュールとして扱われ

ESModule仕様でimport/exportが使える。(一部ブラウザは非対応)


index.js

const message = "Hello World";



index.html

<script type="module" src="index.js"></script>

<script>
console.log(message);
</script>


console

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する


index.js

const message = "Hello World";

export default message;


index.html

<script type="module">

import message from './index.js'; // ./とか.jsをちゃんと書かないと怒られた
console.log(message);
</script>


console

Hello World


type="module"を指定し、Scriptをmoduleとして扱う事でimportすることができる。

(IE11が相変わらず対応してないが)


実験 その2

window.messageに突っ込む


index.js

const message = "Hello World";

window.message = message;


index.html

<script type="module" src="index.js"></script>

<script>
// 上記のスクリプトは非同期で読み込まれるので、ロード後に処理する
window.onload = function() {
console.log(message)
}
</script>


console

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.<プロパティ>にぶち込んで公開する。

という方法でいいという結論に落ち着きました。