JavaScriptでappendChildやinsertBeforeを使ってページhead内で外部リソースを読み込むscript要素に「crossorigin」タグを自動挿入しようと思ったのですが思ったように挿入されずに詰まりました。
最近のCDNサービスではcrossorigin属性がanonymousと指定されているものをヘッダーに埋め込むように指示するところが増え、この読み込みを制御していた時に苦労したので備忘録です。
JavaScriptとHTMLで大文字と小文字の扱いが異なるのが原因でした。
この記事の目次
createElementでcrossoriginが挿入できない
今回はちょっとマニアックな内容になります。
外部CDNを使ったサービスを遅延読み込み制御しようと思い、createElementでScript要素を生成後、insertBeforeを使って「crossorigin="anonymous"」を挿入しようと思ったのですが、うまく入りませんでした。
crossorigin属性について
crossorigin属性が空かanonymousと指定されているとクロスドメインで読み込んだリソースに承認なしでアクセスするようにCORS設定がされるという属性です。
【crossoriginが使える要素】
audio要素、img要素、link要素、script要素、video要素。
今回はCDN読み込み用のscript要素に指定されていました。
広告サービスなどの読み込み時のエラー回避みたいな感じなのでしょうか?
詳しくないので詳細は別サイト様に丸投げさせていただきます...
<script async src="https://cdn-hostserver.com/application.js" crossorigin="anonymous"></script>
こんな感じです。
とにかく始めから「crossorigin="anonymous"」の記述が引っ付いています。
JavaScriptで動的に生成してみる
割と有名でスタンダードな方法ですが、JavaScriptを使ってこのURLを動的に生成し、head(/body直前)に書き込むことでページのhead内でこのリソースが読み込まれるようなコードを作りました。
<script type="text/javascript"> (function(window, document) { function main() { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'https://cdn-hostserver.com/application.js'; script.crossorigin = 'anonymous'; var target = document.getElementsByTagName('script')[0]; target.parentNode.insertBefore(script, target); } main(); })(window, document); </script>
createElementでscript要素を生成後、srcなど挿入したい文字列を入れます。
7行目でcrossoriginにanonymousを設定しています。
その後insertBeforeを使って作ったscript要素に各項目を追加しました。
あとはこのコードをページ内で読み込めばJavaScriptによって動的にHTMLソースが生成されるはずですが…
読み込んでみると「crossorigin="anonymous"」がscript要素に入っていません。
ここでかなり詰まりました。
HTMLソースで確認するとしっかりとJavaScriptも読み込まれているし、他のtypeやsrcは入っているんです。
試しにasyncも追加してみましたが、問題なく入りました。
JavaScriptでは「crossOrigin」
ず~と原因を検索していたのですが、なかなか見つけられませんでした。
そんなとき海外のページに辿り着きあっけなく問題解決しました。
動的に読み込まれるスクリプトに「crossorigin」タグを追加するにはどうすれば?
という似たような質問がスタックオーバーフローにありました。
そして回答には
Note the capital "O". That attribute isn't capitalized in the HTML, but is capitalized in the JS interface. Good to know!
大文字の「O」に注意してください。その属性はHTMLでは大文字になりませんが、JSインターフェースでは大文字になります。知っておくと良い!
とありました。えぇ。。。
script.crossorigin = 'anonymous';
ではなく
script.crossOrigin = 'anonymous';
という風にJavaScriptで書く時にはOは大文字らしいです。
でも出力された後はHTMLなので小文字に見えると…なんという罠...
コードを書き換えて動作確認
先ほどのコードの7行目、「script.crossorigin」のoを大文字のOに書き換えます。
<script type="text/javascript"> (function(window, document) { function main() { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'https://cdn-hostserver.com/application.js'; script.crossOrigin = 'anonymous'; var target = document.getElementsByTagName('script')[0]; target.parentNode.insertBefore(script, target); } main(); })(window, document); </script>
もはや何が変わったのか言われないと分からないレベル。
そしてページを確認してみる。
しっかりと「crossorigin="anonymous"」が入りました・w・
そしてHTMLでの表示なのでOが小文字のoで出力されている...
ややこしすぎませんこれ?w
まとめ
JavaScriptのHTML動的生成でcrossoriginが上手く挿入されない場合はJavaScriptのコード内の「crossOrigin」のOが小文字のoになっていないか確認しましょう...
6年6カ月前の質問でしたが質問者様の意図で「同じ間違いを質問される方のためにこの質問は削除せずに残しておきます。」と最後に書かれていました。
おかげさまで助かりました!
そして回答者の「Good to know!」(知っておくと良い!)のかっこいいこと...