Uh oh!
There was an error while loading. Please reload this page.
main.jsのasync読み込みをやめてDOM参照処理の実行タイミングを保証する - #49
Open
sugawara-appleple wants to merge 2 commits into
Open
Conversation
vite() の出力は <script type="module"> で、仕様上すでに defer 相当 (HTMLのパース完了後に実行)になる。async はその defer を打ち消し、 モジュールの読み込みが終わった時点で即実行させるため、HTMLのパースが <body> に達する前に main.js が走ることがある。 その場合、DOMを参照する処理が対象0件で空振りする。 - Alpine が「Unable to initialize. Trying to load Alpine before <body> is available.」を警告する。Alpine は警告後も MutationObserver で 後から流れてくる要素を拾うため、x-data の動作自体には実害が出にくい - externalLinks(次のコミットで対応)が空振りし、外部リンクに target="_blank" / rel="noopener noreferrer" が付かない。文書末尾に あるフッターのリンクはどのページでも処理に間に合わない このテーマを出発点にした複数のサイトで、main.js の実行開始時点で document.body が存在しないこと(readyState=loading)と、それによる フッターの外部リンクの付与漏れを実測で確認している。Chrome / Edge で 再現し、Safari では実行が遅く再現しないことがある。ビルドし直すと出て 古いビルド生成物では出ないため、原因を掴みにくい。 ダウンロードは modulepreload が先行するので、async を外しても取得は 遅くならない。むしろ <head> のパース中に大きなモジュールを同期実行 しなくなる分、初回描画には有利。
組み込みJSは他すべてが domContentLoaded() で包まれているのに externalLinks だけ同期実行されており、DOM構築前に呼ばれると querySelectorAll が0件を返して外部リンクに target/rel が付かないまま 終わる。 前のコミットの async 削除で実行タイミング側は解消しているが、この処理 自体はDOMを参照するため、他の組み込みJSと揃えて domContentLoaded を 待たせ、読み込み方法の変更に依存しないようにする。 htmx のスワップ後に window.dispatch(event.target) から呼ばれる経路では、 既にDOMに入った要素が context になるため domContentLoaded は即時発火し、 挙動は変わらない。
uidev1116
approved these changes
Aug 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
変更内容の概要
vite()に渡していたscriptTagAttributes: { async: true }を削除し、あわせてexternalLinksをdomContentLoaded()で包みました。変更は2ファイルです。themes/develop/include/head/js.twigasync: trueを削除(Touch_NotAdmin/Touch_Adminの2箇所)。理由をコメントで残すthemes/develop/src/js/lib/build-in.jsexternalLinksの中身をdomContentLoaded()で包む背景
vite()の出力は<script type="module">で、仕様上すでに defer 相当(HTMLのパース完了後に実行)になります。asyncはその defer を打ち消し、モジュールの読み込みが終わった時点で即実行させるため、HTMLのパースが<body>に達しているかどうかが保証されません。<body>の生成前にmain.jsが実行されると、DOMを参照する処理が対象0件で空振りします。Unable to initialize. Trying to load Alpine before <body> is available.を警告する(Alpine は警告後も MutationObserver で後から流れてくる要素を拾うため、x-dataの動作自体には実害が出にくい)externalLinksが空振りし、外部リンクにtarget="_blank"/rel="noopener noreferrer"が付かない。externalLinksは組み込みJSの中で唯一domContentLoadedを待っていません。 文書末尾にあるフッターのリンクはどのページでも処理に間に合いませんasyncを外してもダウンロードはmodulepreloadが先行するため取得は遅くなりません。むしろ<head>のパース中に大きなモジュールを同期実行しなくなる分、初回描画には有利です。このテーマを出発点にしたサイトでの実測
Chrome / Edge で再現し、Safari では実行が遅く再現しないことがあります。ビルドし直すと出て古いビルド生成物では出ないため、原因を掴みにくい症状です。
asyncあり)main.js実行開始時にdocument.bodyなし(readyState=loading)。Alpine 警告あり。外部リンクの付与漏れありasyncあり)targetが付かないasync削除後)確認したこと
npm --prefix themes/develop run lint✅npm run package✅themes/developのnpm run build✅x-data5/5 初期化 /x-cloak残0 / 外部リンク 処理対象6件→6件付与。トップと/news/で初回+キャッシュ済み各4回、回帰なし実機では修正前の症状を再現できませんでした
develop テーマのローカル環境では、
asyncあり(修正前)でも警告0件・外部リンク全件付与で正常でした。傍受なしの素の条件、CPU 8倍/20倍スロットル、キャッシュ有無、src/js/alpinejs/のサンプルコンポーネント削除、pdfPreview無効化によるモジュールグラフ縮小まで試しましたが再現せず、この環境で再現しない理由は特定できていません。そのため本PRは「現に壊れているから直す」ではなく、実行タイミングを保証しない指定を外し、DOMを参照する処理はDOMを待たせるという趣旨です。症状が出るかどうかはHTMLサイズ・JSサイズ・回線・キャッシュ・ブラウザで変わり、事前に予測できません。
関連Issue
なし