[{"data":1,"prerenderedAt":427},["ShallowReactive",2],{"post-vuejs-language-tools-pr":3},{"id":4,"title":5,"body":6,"date":415,"description":416,"extension":417,"meta":418,"navigation":202,"path":423,"seo":424,"stem":425,"__hash__":426},"blog\u002Fblog\u002Fvuejs-language-tools-pr.md","vuejs\u002Flanguage-tools の PR を読み解く：DiffWindow のハイライト問題",{"type":7,"value":8,"toc":405},"minimark",[9,13,28,31,39,45,51,55,58,61,67,73,82,89,105,109,115,118,121,137,140,143,147,154,263,274,288,293,298,305,375,378,381,384,387,401],[10,11,12],"h2",{"id":12},"はじめに",[14,15,16,17,27],"p",{},"この記事は、📅 ",[18,19,20],"strong",{},[21,22,26],"a",{"href":23,"rel":24},"https:\u002F\u002Fqiita.com\u002Fadvent-calendar\u002F2025\u002Fvue",[25],"nofollow","Vue Advent Calendar 2025"," の 8 日目の記事です。",[14,29,30],{},"Visual Studio Code（以下、VS Code）で Vue.js を開発する際に便利な拡張機能である Vue (Official) を利用される場合が多いのではないでしょうか。",[14,32,33,34,38],{},"本日リリースされた ",[35,36,37],"code",{},"v3.1.7"," で気になる修正があったので、再現確認とコミットを追ってみました。",[14,40,41],{},[21,42,43],{"href":43,"rel":44},"https:\u002F\u002Fgithub.com\u002Fvuejs\u002Flanguage-tools\u002Freleases\u002Ftag\u002Fv3.1.7",[25],[14,46,47],{},[21,48,49],{"href":49,"rel":50},"https:\u002F\u002Fgithub.com\u002Fvuejs\u002Flanguage-tools\u002Fpull\u002F5811",[25],[10,52,54],{"id":53},"vuejslanguage-tools-とは","vuejs\u002Flanguage-tools とは",[14,56,57],{},"まず、vuejs\u002Flanguage-tools について簡単に紹介します。",[14,59,60],{},"Vue.js の公式ドキュメントでは、IDE サポートについて以下のように説明されています。",[62,63,64],"blockquote",{},[14,65,66],{},"The recommended IDE setup is VS Code + the Vue - Official extension (previously Volar). The extension provides syntax highlighting, TypeScript support, and intellisense for template expressions and component props.",[14,68,69],{},[21,70,71],{"href":71,"rel":72},"https:\u002F\u002Fvuejs.org\u002Fguide\u002Fscaling-up\u002Ftooling.html#ide-support",[25],[14,74,75,76,81],{},"この Vue - Official 拡張機能の中核となるのが ",[21,77,80],{"href":78,"rel":79},"https:\u002F\u002Fgithub.com\u002Fvuejs\u002Flanguage-tools",[25],"vuejs\u002Flanguage-tools"," です。",[14,83,84,85,88],{},"以下の図のように、複数のパッケージで構成されています。今回の修正は ",[35,86,87],{},"@vue\u002Flanguage-core"," に関するものです。",[14,90,91,96],{},[92,93],"img",{"alt":94,"src":95},"vuejs\u002Flanguage-tools のアーキテクチャ","https:\u002F\u002Fi.gyazo.com\u002F28ab68ee0e3ce23708c51c8522e7050c.png",[97,98,99,104],"em",{},[21,100,103],{"href":101,"rel":102},"https:\u002F\u002Fgithub.com\u002Fvuejs\u002Flanguage-tools\u002Fblob\u002Fmaster\u002FREADME.md#community-integration",[25],"Community Integration - vuejs\u002Flanguage-tools"," より",[10,106,108],{"id":107},"問題git-差分表示で色がおかしくなる","問題：Git 差分表示で色がおかしくなる",[14,110,111],{},[21,112,113],{"href":113,"rel":114},"https:\u002F\u002Fgithub.com\u002Fvuejs\u002Flanguage-tools\u002Fissues\u002F5572",[25],[14,116,117],{},"Git の差分表示（DiffWindow）で Vue ファイルを開くと、Semantic Highlighting が正しく適用されず、シンタックスハイライトの色が壊れてしまう現象が発生していました。",[14,119,120],{},"手元でも再現確認を行ったところ再現しました。参考までに環境は以下の通りです。",[122,123,124,128,131,134],"ul",{},[125,126,127],"li",{},"VS Code: 1.106.3 (Universal)",[125,129,130],{},"Vue - Official (vue.volar): 3.0.7 より前のバージョン",[125,132,133],{},"Vue: 3.5.25",[125,135,136],{},"vue-tsc: 3.0.2",[14,138,139],{},"PR を見るだけだと理解が深まらないので、フォークして実際のコードをいじりながらテストを回していくことにしました。",[14,141,142],{},"以下は検証に利用したコードなので、興味ある方は手元でも試して読んでみてください。",[10,144,146],{"id":145},"原因キャッシュキーの競合","原因：キャッシュキーの競合",[14,148,149,150,153],{},"原因は、仮想コードのキャッシュキーに ",[35,151,152],{},"fileName","（ファイルパスのみ）を使用していたことにあります。",[155,156,161],"pre",{"className":157,"code":158,"language":159,"meta":160,"style":160},"language-typescript shiki shiki-themes github-light github-dark","\u002F\u002F 変更前：fileName をキーに使用\nfileRegistry.get(fileName)\nfileRegistry.set(fileName, code)\n\n\u002F\u002F disposeVirtualCode も同様\ndisposeVirtualCode(scriptId) {\n    const fileName = asFileName(scriptId);\n    fileRegistry.delete(fileName);\n}\n\u002F\u002F キー例: '\u002Fpath\u002Fto\u002FApp.vue'\n","typescript","",[35,162,163,172,186,197,204,210,219,239,251,257],{"__ignoreMap":160},[164,165,168],"span",{"class":166,"line":167},"line",1,[164,169,171],{"class":170},"sJ8bj","\u002F\u002F 変更前：fileName をキーに使用\n",[164,173,175,179,183],{"class":166,"line":174},2,[164,176,178],{"class":177},"sVt8B","fileRegistry.",[164,180,182],{"class":181},"sScJk","get",[164,184,185],{"class":177},"(fileName)\n",[164,187,189,191,194],{"class":166,"line":188},3,[164,190,178],{"class":177},[164,192,193],{"class":181},"set",[164,195,196],{"class":177},"(fileName, code)\n",[164,198,200],{"class":166,"line":199},4,[164,201,203],{"emptyLinePlaceholder":202},true,"\n",[164,205,207],{"class":166,"line":206},5,[164,208,209],{"class":170},"\u002F\u002F disposeVirtualCode も同様\n",[164,211,213,216],{"class":166,"line":212},6,[164,214,215],{"class":181},"disposeVirtualCode",[164,217,218],{"class":177},"(scriptId) {\n",[164,220,222,226,230,233,236],{"class":166,"line":221},7,[164,223,225],{"class":224},"szBVR","    const",[164,227,229],{"class":228},"sj4cs"," fileName",[164,231,232],{"class":224}," =",[164,234,235],{"class":181}," asFileName",[164,237,238],{"class":177},"(scriptId);\n",[164,240,242,245,248],{"class":166,"line":241},8,[164,243,244],{"class":177},"    fileRegistry.",[164,246,247],{"class":181},"delete",[164,249,250],{"class":177},"(fileName);\n",[164,252,254],{"class":166,"line":253},9,[164,255,256],{"class":177},"}\n",[164,258,260],{"class":166,"line":259},10,[164,261,262],{"class":170},"\u002F\u002F キー例: '\u002Fpath\u002Fto\u002FApp.vue'\n",[14,264,265,266,269,270,273],{},"通常のファイルは ",[35,267,268],{},"file:\u002F\u002F"," スキームでアクセスされますが、Git の差分表示では ",[35,271,272],{},"git:\u002F\u002F"," スキームが使われます。",[122,275,276,282],{},[125,277,278,279],{},"通常: ",[35,280,281],{},"file:\u002F\u002F\u002Fpath\u002Fto\u002FApp.vue",[125,283,284,285],{},"Git差分: ",[35,286,287],{},"git:\u002Fpath\u002Fto\u002FApp.vue",[14,289,290,292],{},[35,291,152],{}," だけをキーにすると、両者が同じキャッシュエントリを参照してしまい、Git diff バッファが通常ファイルのスナップショットを上書きしてしまいます。",[294,295,297],"h3",{"id":296},"解決策scriptid-によるキャッシュ分離","解決策：scriptId によるキャッシュ分離",[14,299,300,301,304],{},"PR #5811 では、キャッシュキーを ",[35,302,303],{},"scriptId","（URI 全体）に変更することで、スキームごとに独立したキャッシュを保持するようにしました。",[155,306,308],{"className":157,"code":307,"language":159,"meta":160,"style":160},"\u002F\u002F 変更後：scriptId をキーに使用\nfileRegistry.get(String(scriptId))\nfileRegistry.set(String(scriptId), code)\n\ndisposeVirtualCode(scriptId) {\n    fileRegistry.delete(String(scriptId));\n}\n\u002F\u002F キー例: 'file:\u002F\u002F\u002Fpath\u002Fto\u002FApp.vue' または 'git:\u002Fpath\u002Fto\u002FApp.vue'\n",[35,309,310,315,330,343,347,353,366,370],{"__ignoreMap":160},[164,311,312],{"class":166,"line":167},[164,313,314],{"class":170},"\u002F\u002F 変更後：scriptId をキーに使用\n",[164,316,317,319,321,324,327],{"class":166,"line":174},[164,318,178],{"class":177},[164,320,182],{"class":181},[164,322,323],{"class":177},"(",[164,325,326],{"class":181},"String",[164,328,329],{"class":177},"(scriptId))\n",[164,331,332,334,336,338,340],{"class":166,"line":188},[164,333,178],{"class":177},[164,335,193],{"class":181},[164,337,323],{"class":177},[164,339,326],{"class":181},[164,341,342],{"class":177},"(scriptId), code)\n",[164,344,345],{"class":166,"line":199},[164,346,203],{"emptyLinePlaceholder":202},[164,348,349,351],{"class":166,"line":206},[164,350,215],{"class":181},[164,352,218],{"class":177},[164,354,355,357,359,361,363],{"class":166,"line":212},[164,356,244],{"class":177},[164,358,247],{"class":181},[164,360,323],{"class":177},[164,362,326],{"class":181},[164,364,365],{"class":177},"(scriptId));\n",[164,367,368],{"class":166,"line":221},[164,369,256],{"class":177},[164,371,372],{"class":166,"line":241},[164,373,374],{"class":170},"\u002F\u002F キー例: 'file:\u002F\u002F\u002Fpath\u002Fto\u002FApp.vue' または 'git:\u002Fpath\u002Fto\u002FApp.vue'\n",[10,376,377],{"id":377},"おわりに",[14,379,380],{},"日々お世話になっている Vue - Official 拡張機能の中核である vuejs\u002Flanguage-tools の改善により、Git 差分表示での Semantic Highlighting 問題が解決されました。",[14,382,383],{},"VS Code で Vue.js を開発されている方は、ぜひ最新バージョン（v3.1.7 以降）へアップデートしてみてください。",[10,385,386],{"id":386},"参考リンク",[122,388,389,395],{},[125,390,391],{},[21,392,394],{"href":49,"rel":393},[25],"PR #5811: feat(language-core): cache virtual code by scriptId",[125,396,397],{},[21,398,400],{"href":113,"rel":399},[25],"Issue #5572: Different font colors in DiffWindow",[402,403,404],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":160,"searchDepth":174,"depth":174,"links":406},[407,408,409,410,413,414],{"id":12,"depth":174,"text":12},{"id":53,"depth":174,"text":54},{"id":107,"depth":174,"text":108},{"id":145,"depth":174,"text":146,"children":411},[412],{"id":296,"depth":188,"text":297},{"id":377,"depth":174,"text":377},{"id":386,"depth":174,"text":386},"2025-12-08","Vue - Official 拡張機能 v3.1.7 で修正された Git 差分表示のハイライト問題について、PR を追いながら原因と解決策を解説します。","md",{"tags":419},[420,421,422],"vue","vscode","oss","\u002Fblog\u002Fvuejs-language-tools-pr",{"title":5,"description":416},"blog\u002Fvuejs-language-tools-pr","NTmMf3OFkOwbgGcZOAut8QCWwVMuDi0uJ0VLZs7FyX0",1773664053809]