ライブラリのロード回数を減らす
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ 親ページが子ページを window.open で開く
◆ →親ページが子ページの window にライブラリを代入
◆ 子ページで実行してもグローバル空間は親を参照するのでライブラリの処理によっては動かない場合もある
◆ →親ページが子ページの window にライブラリを代入
◆ 子ページで実行してもグローバル空間は親を参照するのでライブラリの処理によっては動かない場合もある
頻繁なリロードで毎回ロードしたくない
開発中ってちょっと修正してページリロードというのを何回も繰り返しますリロードしたいのはページ部分だけで ライブラリ部分はロードし直す必要はありません
毎回ライブラリ部分もすべてリロードってなんかもったいない気がします
開発中なら基本ローカルなのでネット接続が従量課金でもあまり関係ないかもしれませんが 従量課金のライブラリを使ってる場合もあるかもしれません
そういうのだとローカルに js ファイルを保存しておけず毎回サーバにリクエスト必要ですし 外部サーバなので ServiceWorker でキャッシュもできません
部分リロードは無理そう
一見できても良さそうな部分リロードですが 意外と難しいです完全にモジュール化して グローバルに登録する系を一切使わないのであれば DOM クリア後に新しいモジュールをロードして再実行だけで良さそうです
しかし実際にはあちこちグローバルなものが設定されます
CustomElement の登録やタイマーの登録もグローバルなものです
window や document にリスナがついてることもありますし ライブラリがリロード前のデータを内部で保持しているかもしれません
完全なクリアは難しいです
ロード済みページから渡してもらう
考え方を変えて ページ自体はリロードするけど ライブラリ部分は通常のロードとは別にロード済みの外部から渡されるという方法を考えました親となるページを用意してそこでライブラリをロードします
そのページが子ページを開き ライブラリのルートオブジェクトを渡します
リロードするときは親ページから開き直します
<!doctype html>
<meta charset="utf-8"/>
<input id="url">
<button id="btn">open</button>
<script src="lib.js"></script>
<script>
btn.onclick = eve => {
window.subwindow = window.open(url.value)
window.subwindow.addEventListener("load", () => {
window.subwindow.lib = lib
window.subwindow.main()
})
}
</script>
input に開く URL を入れて open ボタンを押したらページが開きます
開いたページがロードされると lib を開いたページの window.lib に代入して window.main 関数を実行します
開かれるページではライブラリのロード後に実行する内容を main 関数に書いておくだけです
問題点
これだけで問題ないことも多いですしかし この渡し方では ライブラリのロードは親ページで行われます
そのため ライブラリ内部で window や document などグローバル変数にアクセスすると親ページのものを参照してしまいます
それらを使わないライブラリなら問題ありませんが 使う場合は子ページを変えたいのに親ページが書き換わるだけで正しく動きません
[parent.html]
<h1>parent.html</h1>
<button onclick=x()>x()</button>
<button onclick=y()>open</button>
<script>
function x(){
console.log(document.body.firstElementChild)
}
function y(){
const w = window.open("child.html")
w.x = x
}
</script>
[child.html]
<h1>child.html</h1>
<button onclick=x()>x()</button>
これは child.html でボタンを押した時の x() で parent.html のページのコンソールに <h1>parent.html</h1> が表示されます
またライブラリが返す Array や RegExp も別ものです
文字列化して比較すればいいですが instanceof RegExp とした場合は正規表現オブジェクトでも false になります
親の JavaScript 空間の RegExp インスタンスは子の JavaScript 空間の RegExp のインスタンスですか?ということになるので false なのは仕方ないです
HMR
自分でがんばるのもいいですが parcel だと HMR があるのでモジュールだけを置き換えてくれますCustomElement を登録したり CSS Modules を使うと使いものにならないですが そういうことをしなければ JavaScript や CSS ファイル単位で変更を検知して自動で置き換えてくれます
バンドルツールを使うというのも手ですね