issue 左ペインから自分自身のページを開なおすと五線譜が消えてしまうし、そのときconsoleには何も出力されない(ナビゲーションを検知できていない) #71
補足情報
- このとき、画面右上のgraph viewの表示は初期化されている
- なのでSPAナビゲーション自体は行われている、と判断する
- その検知ができていない、と判断する
ブレインストーミング
- 公式はどうやっているのか、ここのREADME.ja.md等にノウハウをまとめたほうがいい。agentにやらせるつもり
- なぜなら「今の実装は、このような根本的な不具合があるので、おそらく方法に誤りがあり、正ではない」と判断するから
- 以前読ませたけどこうやって失敗している。無視しているのかもしれない。それも含めて整理がよさそう
- 理想は「同じ用途で、実際に動くもの」が見つかることだが、見つかっていない。チュートリアル記事(動くものはない)だとこういうときには不足である、と判断する
- agentは毎回TypeScriptコードをJavaScript部分に書いて破壊しているので、AGENTS.md系に書いておきましょう
公式
- https://quartz.jzhao.xyz/advanced/creating-components
nav
- 以下は左ペインのクリックでも確実にlogが出た
document.addEventListener("nav", () => { console.log("🔥 nav fired", location.pathname) }) - これも同じく、左ペインのクリックでも確実にlogが出た
(() => { const orig = EventTarget.prototype.dispatchEvent; EventTarget.prototype.dispatchEvent = function (event) { if (event?.type === "nav") { console.log("🚨 nav DISPATCHED", event, "on", this); console.trace(); } return orig.call(this, event); }; console.log("dispatchEvent patched"); })();結果は
🚨 nav DISPATCHED CustomEvent {isTrusted: false, detail: {…}, type: 'nav', target: null, currentTarget: null, …} on #document (https://cat2151.github.io/digital-garden/Quartz-%E3%82%B3%E3%83%BC%E3%83%89%E9%80%B2%E8%A1%8C%E3%82%92%E4%BA%94%E7%B7%9A%E8%AD%9C%E3%81%A7%E8%A1%A8%E7%A4%BA%E3%81%97%E3%81%A6%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%81%A7%E6%BC%94%E5%A5%8F%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%97%E3%81%9F) VM1879:6 console.trace EventTarget.dispatchEvent @ VM1879:6 qr @ postscript.js:1199 li @ postscript.js:1199 await in li Rr @ postscript.js:1199 (匿名) @ postscript.js:1199ブラウザconsoleだけでは復活せず
やったこと
// まず関数が見えるか確認 Object.keys(window).filter(k => k.includes("initialize")) -
見えない。init関数は IIFE の中に閉じ込められていて console から触れない
- そして以下を実行
document.addEventListener("nav", () => { console.log("🧪 console nav hook"); // 1. abcjs が触れる DOM を強制リセット document.querySelectorAll(".abc-notation").forEach(el => { // SVG を消す el.innerHTML = ""; }); // 2. Quartz の既存 nav 処理をもう一度走らせる setTimeout(() => { console.log("🧪 forcing mutation"); document.body.appendChild(document.createComment("force-rerender")); }, 0); }); - 結果、左ペインをクリックすると、五線譜は消えて、上記logは出力された
デバッグloggerをTypeScript側に書いて、問題を可視化をする
// ===== nav デバッグ可視化 =====
function logNavDebug(where) {
return function (e) {
const ce = e
const abcNodes = document.querySelectorAll('.abc-notation')
const processed = document.querySelectorAll('[data-mmlabc-processed]')
console.groupCollapsed('[nav @ ' + where + ']')
console.log('event:', e)
console.log('detail:', ce && ce.detail)
console.log('target:', e.target)
console.log('currentTarget:', e.currentTarget)
console.log('abc-notation count:', abcNodes.length)
console.log('processed count:', processed.length)
if (abcNodes.length > 0) {
const el = abcNodes[0]
console.log('sample abc element:', el)
console.log(
'sample processed?',
el.hasAttribute('data-mmlabc-processed')
)
}
console.groupEnd()
}
}
// capture → bubble → window
document.addEventListener('nav', logNavDebug('document-capture'), true)
document.addEventListener('nav', logNavDebug('document'))
window.addEventListener('nav', logNavDebug('window'))
// ===== 以上、nav デバッグ可視化 =====
- 左ペインの五線譜pageをクリック
- 結果、五線譜が消えて、以下のlogが出力された
[MML-ABC-Transformer] ナビゲーションを検知しました。ソース: MutationObserver VM66:116 [MML-ABC-Transformer] 五線譜表示処理を開始します VM66:125 [MML-ABC-Transformer] 処理対象の楽譜ブロック数: 6 3VM66:130 [MML-ABC-Transformer] スキップ: 既に処理済みの要素 VM66:136 [MML-ABC-Transformer] 新しい楽譜要素を処理します。Type: chord VM66:136 [MML-ABC-Transformer] 新しい楽譜要素を処理します。Type: mml VM66:136 [MML-ABC-Transformer] 新しい楽譜要素を処理します。Type: abc VM66:346 [MML-ABC-Transformer] 五線譜表示処理が完了しました。処理時間: 8.70 ms VM66:84 [nav @ document-capture] VM66:86 event: CustomEvent {isTrusted: false, detail: {…}, type: 'nav', target: document, currentTarget: document, …} VM66:87 detail: {url: 'Quartz-コード進行を五線譜で表示してクリックで演奏できるようにした'} VM66:88 target: #document (https://cat2151.github.io/digital-garden/Quartz-%E3%82%B3%E3%83%BC%E3%83%89%E9%80%B2%E8%A1%8C%E3%82%92%E4%BA%94%E7%B7%9A%E8%AD%9C%E3%81%A7%E8%A1%A8%E7%A4%BA%E3%81%97%E3%81%A6%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%81%A7%E6%BC%94%E5%A5%8F%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%97%E3%81%9F) VM66:89 currentTarget: #document (https://cat2151.github.io/digital-garden/Quartz-%E3%82%B3%E3%83%BC%E3%83%89%E9%80%B2%E8%A1%8C%E3%82%92%E4%BA%94%E7%B7%9A%E8%AD%9C%E3%81%A7%E8%A1%A8%E7%A4%BA%E3%81%97%E3%81%A6%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%81%A7%E6%BC%94%E5%A5%8F%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%97%E3%81%9F) VM66:91 abc-notation count: 3 VM66:92 processed count: 0 VM66:96 sample abc element: <div class="abc-notation chord-block" data-chord="C Dm7 G7^2, CM7" data-type="chord" role="button" tabindex="0" aria-label="Play music notation"></div> VM66:97 sample processed? false VM66:84 [nav @ document] VM66:86 event: CustomEvent {isTrusted: false, detail: {…}, type: 'nav', target: document, currentTarget: document, …} VM66:87 detail: {url: 'Quartz-コード進行を五線譜で表示してクリックで演奏できるようにした'} VM66:88 target: #document (https://cat2151.github.io/digital-garden/Quartz-%E3%82%B3%E3%83%BC%E3%83%89%E9%80%B2%E8%A1%8C%E3%82%92%E4%BA%94%E7%B7%9A%E8%AD%9C%E3%81%A7%E8%A1%A8%E7%A4%BA%E3%81%97%E3%81%A6%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%81%A7%E6%BC%94%E5%A5%8F%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%97%E3%81%9F) VM66:89 currentTarget: #document (https://cat2151.github.io/digital-garden/Quartz-%E3%82%B3%E3%83%BC%E3%83%89%E9%80%B2%E8%A1%8C%E3%82%92%E4%BA%94%E7%B7%9A%E8%AD%9C%E3%81%A7%E8%A1%A8%E7%A4%BA%E3%81%97%E3%81%A6%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%81%A7%E6%BC%94%E5%A5%8F%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%97%E3%81%9F) VM66:91 abc-notation count: 3 VM66:92 processed count: 0 VM66:96 sample abc element: <div class="abc-notation chord-block" data-chord="C Dm7 G7^2, CM7" data-type="chord" role="button" tabindex="0" aria-label="Play music notation"></div> VM66:97 sample processed? falseどうする?
- agentに
- まずリファクタリングさせる(別issue)
- でないと、ハルシネーションのリスクが大きいし、またjs部分にtsを書くミスをしそう
- 次に、上記をagentに投げて、対策案を検討させる。
- 性質上、documentにぶら下げる方式が、デバッグしやすく、よさそう
- ADRを書いておくのもよいだろう(documentにぶら下げる / 公式の方法だとDOM書き換えについてabcjsと公式とで処理がコンフリクトしやすく実装ミスのリスクが高そう)
LLMに生成させたもの
結論まとめ
現象
- 左ペインから 自分自身のページを開き直す と五線譜(abcjs描画)が消える
- console にはエラーが出ない
- graph view は初期化されているため、SPA ナビゲーション自体は発生している
document.addEventListener("nav", …)では 確実に nav イベントを検知できている
調査で確定した事実
- Quartz の
navイベントは 常に document に dispatch されている - 問題は「nav を検知できていない」ことではない
- 実際のログ順は以下:
1. DOM 差し替え
2. MutationObserver が反応
3. abcjs による五線譜描画が実行される
4. その後で nav イベントが dispatch される
- つまり nav より前に五線譜描画が走っている
- SPA 遷移の「中間状態の DOM」に対して描画してしまい、 その後 Quartz 側の処理で SVG が破棄される
根本原因
- 実装が MutationObserver 主導になっている
-
Quartz SPA において MutationObserver は
- DOM 差し替え途中の不安定な状態も拾う
- nav(=ライフサイクル完了)より早く発火する
-
結果として、
- 五線譜描画は実行されている
- しかし nav 後に再実行されず、表示が消えたままになる
👉 設計として Quartz の SPA ライフサイクルと噛み合っていない
結論
- 問題は「nav を検知できていない」のではなく 「nav より前に処理している」こと
- MutationObserver 主導の設計は、この用途では不適切
- 現状の実装は「たまたま動く」構造であり、根本的な不具合を内包している
採用する方針(推奨)
document 中央集権 + nav 主導
- client-side の状態・初期化・再描画トリガーを すべて document に集約
navを 唯一の再描画ライフサイクルイベントとして扱う- nav 後、DOM が安定してから五線譜描画を実行する
- MutationObserver は使わない、もしくは補助的に限定利用する
この構成は:
- Quartz SPA と整合する
- self ナビゲーション問題を自然に解決できる
- document が SPA 遷移を跨いで生存するため安定する
他の選択肢について
完全に公式コンポーネント方式に寄せる場合
- Quartz 公式は「軽量・非破壊・ステートレス」な処理を前提としている
- abcjs は DOM を破壊的に書き換えるため思想が合わない
- 公式どおり書いても、別の形で不安定になりやすい
Renderer / Transformer に寄せる場合
- build 時に描画すれば SPA 問題は消える
- ただしインタラクティブ性(クリック再生など)が犠牲になる
補足(ドキュメント化予定の注意点)
- Quartz では document が唯一信頼できるライフサイクル起点
- MutationObserver 単独実装は SPA 中間状態を拾い、描画消失の原因になる
-
エージェントによる実装修正対策として
- TypeScript と JavaScript の責務分離を AGENTS.md に明示する予定
まとめ(短く)
- nav は来ている
- 問題は「来る前に処理している」こと
- MutationObserver 主導が根本原因
- document + nav 主導に設計を切り替えるのが最も安定する
いろいろ
- AGENTS.md系の改善
- Quartz 3では有効だったがQuartz 4では意味のない方法、があるかもしれない
- 直近でagentが実施したのが、それかも
- なので、検証第一の方針でやる
- agentが机上でこれが正しいと確信していても、それがQuartz 3でのみ有効だと、
- 意味がない
- Quartz 3では有効だったがQuartz 4では意味のない方法、があるかもしれない
事実確認したもの
- 前述のloggerを追加したあと
- 左ペインをマウスホバーしたら表示されるlog
ナビゲーションを検知しました。ソース: MutationObserver- ~
五線譜表示処理が完了しました。- ※ただし、クリックして五線譜表示が消えたあとは、
- ホバーしてもlogが出なくなってしまう
- つまりナビゲーションの検知ができなくなっている
- こうなるとリロードするまでは、ずっとこのlogは出ない、のを確認した
- ホバーしてもlogが出なくなってしまう
- それをクリックしたときに表示されるlog
- nav が2つ
- 左ペインをマウスホバーしたら表示されるlog
特に致命的なパターン
- 五線譜のpageでリロード
- 左ペインで五線譜のpageをクリック
- これで消えるし、左ペインの五線譜のpageをホバーしても、logが出なくなる
- 最終ゴールの一つ:
- このパターンでもlogが出るようにすること、かな?
- あるいは
- 仮説
- ここは「破壊された五線譜で固定されたから、MutationObserverが反応しない」
- だけなので、
- 「正解の五線譜で固定されたあとなら、MutationObserverが反応しなくてもOK」
- になる可能性もある
- つまり
- 左ペインで五線譜のpageをクリックしたとき100%五線譜が出るようになれば、
- そのあと、左ペインの五線譜のpageをホバーしても、
- 「logは出ないが五線譜表示は正常にできている」
- となるなら、それは合格
- このパターンでもlogが出るようにすること、かな?