はじめに
HTMLを挿入するinsertAdjacentHTMLでscriptタグを挿入してもHTMLで実行できないよというお話しです。
scriptタグをJSから追加することはめったにないですが、備忘録として残します。
なぜscriptタグをJSから追加することになったのか
詳細を書くと長くなるので以下の記事を参照してほしいのですが、AWS S3で公開する静的サイトのコーディングをしていて、SSIやPHPインクルードが使えないのでJSで共通HTMLのインクルードを行いました。
JS特有の問題として、インクルードする側で行っている処理をインクルードファイルの読み込みが終わった後に実行させる必要があります。
インクルードしていたヘッダーに外部サービスで実装しているサイト内検索があり、HTMLに設置したscriptタグがサイト内検索の諸々の処理を実行していました。HTMLにscriptタグを書いてしまうと実行タイミングの違いでサイト内検索が動作しなくなっていたため、ならJSからscriptタグを追加すればいいじゃんとなって対応した際に当記事の問題が発覚しました。
問題となったコード
問題となったinsertAdjacentHTMLは以下です。
document.body.insertAdjacentHTML("beforeend", "<script src="url"></script>");
bodyタグの最後尾にscriptタグを追加しました。DOMとして追加はされていたものの、肝心のJSの処理は実行されていません。これはinnerHTMLでも同様です。
原因
HTML Living Standardの仕様書にinsertAdjacentHTMLで挿入されたscriptは、通常は実行されないと明記されていました。
insertAdjacentHTMLはあくまでHTML文字列をパースして、その結果のノードをDOMツリーへ挿入する処理です。DOMに挿入されたscriptタグが実行されてしまうのは、メソッドのそもそもの目的とは異なるので仕様で実行が出来ないようにしているのだと思われます。あとはセキュリティ対策もあると思います。
解決方法
const script = document.createElement("script");
script.src = 'url';
document.body.appendChild(script);
createElementでscriptタグを生成し、src属性にJSのパスを代入してappendChildでbodyタグの末尾に追加しています。このDOMに追加したscriptタグは実行されるので、あとはこれらの処理を自分が実行したいタイミングで発火させれば解決です。
おわりに
ちなみにdocument.writeでscriptタグを追加した場合はHTMLで実行も出来るそうです。非推奨なので使いませんが。
JSは何でも出来る反面、その裏に隠しルールがたくさんあるので改めて奥が深いなと思いました。

