[{"data":1,"prerenderedAt":380},["ShallowReactive",2],{"content-/external-link-target-blank-rule":3,"all-pages-for-dir":378,"og-image-/external-link-target-blank-rule":379},{"id":4,"title":5,"body":6,"category":359,"description":360,"extension":361,"meta":362,"navigation":363,"path":364,"project_name":365,"published":366,"publishedAt":367,"seo":368,"stem":369,"tags":370,"todo":376,"unpublished":366,"updatedAt":376,"__hash__":377},"pages/2026-06/2026-06-06/external-link-target-blank-rule.md","@nuxt/content で外部リンクを別タブで開く＋GFM autolinker の二重リンク回避ルールを永続化",{"type":7,"value":8,"toc":351},"minimark",[9,14,18,51,58,61,64,68,82,92,106,116,119,128,131,135,138,151,158,162,167,185,190,208,211,216,225,231,236,244,247,277,282,301,308,312,315,341,347],[10,11,13],"h2",{"id":12},"きっかけxポストを差し込んだら読者が外に飛んだまま戻ってこない構造になっていた","きっかけ：Xポストを差し込んだら、読者が外に飛んだまま戻ってこない構造になっていた",[15,16,17],"p",{},"Micron SOCAMM2 容量半減レポートの解説記事を書いていて、Dylan Patel 本人のXポストを Section 4 に引用した。最初は素直にマークダウンリンクで書いた。",[19,20,25],"pre",{"className":21,"code":22,"language":23,"meta":24,"style":24},"language-markdown shiki shiki-themes vitesse-light vitesse-light","[元ポスト（@dylan522p）](https://x.com/dylan522p/status/...)\n","markdown","",[26,27,28],"code",{"__ignoreMap":24},[29,30,33,37,41,44,48],"span",{"class":31,"line":32},"line",1,[29,34,36],{"class":35},"shFtX","[",[29,38,40],{"class":39},"sdGka","元ポスト（@dylan522p）",[29,42,43],{"class":35},"](",[29,45,47],{"class":46},"sE5Nq","https://x.com/dylan522p/status/...",[29,49,50],{"class":35},")\n",[15,52,53,54,57],{},"dev サーバーで描画を確認したあと、念のためリンクをクリックしてみたら、ブラウザの今開いているタブの URL が ",[26,55,56],{},"x.com/..."," に書き換わり、自分のブログ記事の本文が一瞬で消えた。Xに遷移したあと「戻る」を押せば戻れるが、読者はわざわざ戻ってこない。本文を読みかけのままタブを閉じる確率が高い。",[15,59,60],{},"長文の解説記事ほど、本文の途中に外部ソースへのリンクを差し込みたくなる。マークダウンの素直な書き方をそのまま使うと、ソースを示すたびに読者が本文から離脱する構造になってしまう。",[15,62,63],{},"別タブで開かせたい、と Claude Code に指示を出した。",[10,65,67],{"id":66},"段階的に分かった問題htmlアンカーに書き換えたらリンクが入れ子で2回光った","段階的に分かった問題：HTMLアンカーに書き換えたら、リンクが入れ子で2回光った",[15,69,70,73,74,77,78,81],{},[26,71,72],{},"target=\"_blank\""," を付けるには、マークダウンの ",[26,75,76],{},"[label](url)"," 記法では足りない。GitHub Flavored Markdown 自体に ",[26,79,80],{},"target"," 属性を指定する構文がない。仕方なく HTML アンカーを直書きする。",[19,83,85],{"className":21,"code":84,"language":23,"meta":24,"style":24},"\u003Ca href=\"https://x.com/dylan522p/status/...\" target=\"_blank\" rel=\"noopener noreferrer\">https://x.com/dylan522p/status/...\u003C/a>\n",[26,86,87],{"__ignoreMap":24},[29,88,89],{"class":31,"line":32},[29,90,84],{"class":91},"sG7-3",[15,93,94,95,98,99,102,103,105],{},"書き換えて dev サーバーをリロードしたら、画面の Section 4 で同じ URL が青く2回続けて光った。よく見ると、リンクテキストの URL が、HTMLアンカーの外側でさらに別の ",[26,96,97],{},"\u003Ca>"," タグに包まれている。DevTools で要素を覗くと、",[26,100,101],{},"\u003Ca target=\"_blank\">"," の中にもう一段 ",[26,104,97],{}," が入り、リンクが入れ子になっていた。",[15,107,108,109,111,112,115],{},"原因は @nuxt/content の GFM autolinker だった。ベアの URL 文字列を見つけると、自動で ",[26,110,97],{}," に変換する機能。マークダウンで ",[26,113,114],{},"https://example.com"," と書くだけでリンクになる、あの便利な挙動。今回は、自分で書いた HTML アンカーの中身がたまたまベアURLの文字列だったため、autolinker がそれを検出して二重にリンク化していた。",[15,117,118],{},"リンクテキストを URL でないラベルに変えた。",[19,120,122],{"className":21,"code":121,"language":23,"meta":24,"style":24},"\u003Ca href=\"https://x.com/dylan522p/status/...\" target=\"_blank\" rel=\"noopener noreferrer\">→ 元ポスト（@dylan522p, 2026-06-04）\u003C/a>\n",[26,123,124],{"__ignoreMap":24},[29,125,126],{"class":31,"line":32},[29,127,121],{"class":91},[15,129,130],{},"リロードすると、青く光るリンクが1回だけになった。クリックすると別タブで Xが開き、本文ページはそのまま残った。Meritz Securities のレポート出典も同じパターンで「Meritz Securities Research Center」というラベルに差し替えた。",[10,132,134],{"id":133},"永続化の判断明日また同じことを忘れる","永続化の判断：明日また同じことを忘れる",[15,136,137],{},"この種の罠は、記事を書くたびに踏みやすい。普通のマークダウンリンクは反射で書いてしまうし、HTMLアンカーに書き換えるときも「URLが見えた方が親切かな」と思ってリンクテキストに URL を入れがち。今日気づいた知見をまた検索し直すのは時間の無駄なので、その場でルールを書かせた。",[15,139,140,143,144,147,148,150],{},[26,141,142],{},".claude/rules/external-link-target-blank.md"," に外部リンクの書き方を固定し、プロジェクトルートの ",[26,145,146],{},"CLAUDE.md"," の「ルール所在マップ」表に1行追加した。Claude Code は親ディレクトリの ",[26,149,146],{}," を読みに行くので、マップから辿れば自動的にルール本体に到達する。",[15,152,153,154,157],{},"コミットも論理単位で3本に分けた。①Micron 記事本体、②ルール本体＋マップ追記、③表示確認のスクショ。ルールだけ独立コミットにしておくと、後から ",[26,155,156],{},"git log .claude/rules/"," で「いつ・なぜ追加されたか」を辿れる。",[10,159,161],{"id":160},"ルールの中身要点","ルールの中身（要点）",[15,163,164,166],{},[26,165,142],{}," の要点だけ抜き出す。",[15,168,169,173,174,177,178,177,181,184],{},[170,171,172],"strong",{},"外部リンクの定義",": 当ドメイン以外（",[26,175,176],{},"x.com","、",[26,179,180],{},"github.com",[26,182,183],{},"semianalysis.com","、ニュースサイト、論文、Wikipedia、メーカー公式、その他全て）。",[15,186,187],{},[170,188,189],{},"NG: 普通のマークダウンリンク",[19,191,193],{"className":21,"code":192,"language":23,"meta":24,"style":24},"[元ポスト](https://x.com/dylan522p/status/...)\n",[26,194,195],{"__ignoreMap":24},[29,196,197,199,202,204,206],{"class":31,"line":32},[29,198,36],{"class":35},[29,200,201],{"class":39},"元ポスト",[29,203,43],{"class":35},[29,205,47],{"class":46},[29,207,50],{"class":35},[15,209,210],{},"同タブで開いてしまう。",[15,212,213],{},[170,214,215],{},"NG: ベアURLの autolink",[19,217,219],{"className":21,"code":218,"language":23,"meta":24,"style":24},"https://x.com/dylan522p/status/...\n",[26,220,221],{"__ignoreMap":24},[29,222,223],{"class":31,"line":32},[29,224,218],{"class":91},[15,226,227,228,230],{},"GFM autolinker が ",[26,229,97],{}," に変換するが、これも同タブ。",[15,232,233],{},[170,234,235],{},"OK: HTMLアンカーで明示",[19,237,238],{"className":21,"code":121,"language":23,"meta":24,"style":24},[26,239,240],{"__ignoreMap":24},[29,241,242],{"class":31,"line":32},[29,243,121],{"class":91},[15,245,246],{},"ポイントは2つ：",[248,249,250,264],"ul",{},[251,252,253,255,256,259,260,263],"li",{},[26,254,72],{}," で別タブ、",[26,257,258],{},"rel=\"noopener noreferrer\""," でリンク先からの ",[26,261,262],{},"window.opener"," 参照と referrer 漏洩を遮断する",[251,265,266,269,270,272,273,276],{},[170,267,268],{},"アンカーテキストに URL そのものを書かない","。書くと GFM autolinker が中身をさらに ",[26,271,97],{}," で包み、",[26,274,275],{},"\u003Ca>\u003Ca>...\u003C/a>\u003C/a>"," の入れ子になって描画が崩れる。「→ 元ポスト」「Meritz Securities Research Center」のような URL でないラベルにする",[15,278,279],{},[170,280,281],{},"内部リンクはマークダウンのまま",[19,283,285],{"className":21,"code":284,"language":23,"meta":24,"style":24},"[CUDA入門](/cuda-programming-child-friendly-guide)\n",[26,286,287],{"__ignoreMap":24},[29,288,289,291,294,296,299],{"class":31,"line":32},[29,290,36],{"class":35},[29,292,293],{"class":39},"CUDA入門",[29,295,43],{"class":35},[29,297,298],{"class":46},"/cuda-programming-child-friendly-guide",[29,300,50],{"class":35},[15,302,303,304,307],{},"同サイト内遷移はSPAで切り替わるので、別タブにすると逆に読者の体験を壊す。",[26,305,306],{},"\u003CNuxtLink>"," 相当の動作で同タブ遷移させる。",[10,309,311],{"id":310},"今日の学びgfm-autolinker-は便利だがhtmlアンカーと混ぜるなら中身に-url-を入れない","今日の学び：GFM autolinker は便利だが、HTMLアンカーと混ぜるなら中身に URL を入れない",[15,313,314],{},"3つに言い換えられる学び。",[248,316,317,320,331],{},[251,318,319],{},"マークダウンの便利機能（GFM autolinker）と HTML 直書きは、意外なところで衝突する。両方が「URL を見つけたらリンク化する」仕事を持っているので、同じ URL文字列に両方が手を出すと入れ子になる",[251,321,322,323,330],{},"リンクテキストは URL でない言葉にした方が読者にも親切になる。「",[324,325,329],"a",{"href":326,"rel":327},"https://x.com/dylan522p/status/1830...%E3%80%8D%E3%82%88%E3%82%8A%E3%82%82%E3%80%8C%E2%86%92",[328],"nofollow","https://x.com/dylan522p/status/1830...」よりも「→"," 元ポスト（@dylan522p, 2026-06-04）」の方が文脈が伝わる",[251,332,333,334,337,338,340],{},"一度踏んだ罠は、忘れる前に ",[26,335,336],{},".claude/rules/"," に書いて ",[26,339,146],{}," のマップから参照を張る。次の記事を書き始めたとき、自分は罠の存在を覚えていない前提で設計する",[15,342,343,344,346],{},"ルールができたので、明日以降は外部リンクを書くたびに、Claude Code がこのルールを参照してアンカー形式で書いてくれるはず。覚えておく仕事を ",[26,345,336],{}," に外注した。",[348,349,350],"style",{},"html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .sE5Nq, html code.shiki .sE5Nq{--shiki-default:#393A3490;--shiki-default-text-decoration:underline;--shiki-dark:#393A3490;--shiki-dark-text-decoration:underline}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);}html pre.shiki code .sG7-3, html code.shiki .sG7-3{--shiki-default:#393A34;--shiki-dark:#393A34}",{"title":24,"searchDepth":352,"depth":352,"links":353},2,[354,355,356,357,358],{"id":12,"depth":352,"text":13},{"id":66,"depth":352,"text":67},{"id":133,"depth":352,"text":134},{"id":160,"depth":352,"text":161},{"id":310,"depth":352,"text":311},"dev","Micron記事のXポスト引用が同タブで開いてしまい読者の本文が消える問題から、target=\"_blank\" の運用と GFM autolinker と HTMLアンカーが入れ子で二重描画される事故を回避するルールを .claude/rules/ に固定した記録。","md",{},true,"/external-link-target-blank-rule","mdx-playground",false,"2026-06-06T00:00:00.000Z",{"title":5,"description":360},"2026-06/2026-06-06/external-link-target-blank-rule",[371,372,373,374,375],"Nuxt Content","Markdown","GFM","外部リンク","ルール永続化",null,"ZEuyRWWf451I0LQvWsECV5ODgZP9hUDT2eXjAmy_NlE",[],"https://log.eurekapu.com/og/blog/external-link-target-blank-rule.png?v=2026-06-06T00%3A00%3A00.000Z&title=%40nuxt%2Fcontent%20%E3%81%A7%E5%A4%96%E9%83%A8%E3%83%AA%E3%83%B3%E3%82%AF%E3%82%92%E5%88%A5%E3%82%BF%E3%83%96%E3%81%A7%E9%96%8B%E3%81%8F%EF%BC%8BGFM%20autolinker%20%E3%81%AE%E4%BA%8C%E9%87%8D%E3%83%AA%E3%83%B3%E3%82%AF%E5%9B%9E%E9%81%BF%E3%83%AB%E3%83%BC%E3%83%AB%E3%82%92%E6%B0%B8%E7%B6%9A%E5%8C%96&author=Kei%20Komatsu&sig=1ba479d98f91088e",1780786075992]