Next.js と Markdown でニュースまとめや技術ブログを運用していると、外部サイトへの参照リンクが増えていきます。
このとき外部リンクを同じタブで開くと、読者がそのまま離脱しやすくなります。そこで本記事では、外部リンクだけを別タブで開く設定を、Markdown本文の書き方を変えずに実現する方法をまとめます。
重要:remark-html だけの構成に rehype-external-links を足しても動きません。この記事では、確実に効く「remark → rehype」経由の正統ルートを使います。
この記事で分かること
本記事では、Next.js + Markdown でブログやニュースまとめを運用している方向けに、「外部リンクだけを別タブで開く」設定方法を整理します。
Markdown本文を一切修正せず、変換レイヤーで安全かつ確実に制御するのが目的です。
✅ 本記事で学べるポイント
- なぜ外部リンクは別タブが適しているのか(運用視点)
- Markdownに手を入れない設計方針
rehype-external-linksが確実に効く理由と条件- 実務でそのまま使える
posts.tsの実装例 - 「効いているか」を判断するチェック方法
「設定したつもりなのに効かない」というハマりどころも含めて解説します。
下記記事を運用していくときに気づいた点です。

なぜ外部リンクを別タブにするのか
ニュースまとめや技術ブログでは、外部サイトへの参照リンクが記事の価値そのものになることも少なくありません。
しかし、リンクの開き方次第で読者体験と回遊率に大きな差が出ます。
📌 運用目線での違い
- 同一タブで開く場合外部サイトに遷移 → ブラウザバックされず、そのまま離脱しやすい
- 別タブで開く場合記事タブが残る → 読者が戻りやすく、回遊が継続しやすい
特に以下のようなサイトでは、別タブが有効です。
- ニュースキュレーション
- 技術記事のリンク集
- 公式ドキュメントへの参照が多いブログ
UI/UXというより、運用効率を上げるための設計判断と考えると納得しやすいでしょう。
結論:Markdownは触らず「変換レイヤー」で一括設定する
記事数が増えるほど、Markdown側でリンク挙動を管理するのは現実的ではありません。
結論としては、Markdown → HTML の変換レイヤーで一括制御するのが最も安定します。
❌ Markdown直書き運用の問題点
target="_blank"の書き忘れが起きる- 書き方が人によって揺れる
- 既存記事を後から一括修正しづらい
✅ 変換レイヤー制御のメリット
- Markdownは純粋に「内容」だけ書ける
- 外部リンク判定をコード側に集約できる
- 仕様変更があっても一箇所直すだけで済む
Next.js の場合、src/lib/posts.ts のようなMarkdown変換処理が集まるファイルで対応するのが王道です。
つまずきポイント:rehypeプラグインは「rehypeルート」でしか効かない
ここが最大のハマりどころです。
rehype-external-links は rehype 用プラグインであり、HTML文字列に対して直接は動きません。
❌ よくある失敗パターン
remark()
.use(remarkGfm)
.use(remarkHtml)// ここでHTML文字列になる
.use(rehypeExternalLinks)// 実は効かない
remark-html を通した時点で、AST(構文木)は remark 側で完結しています。
そのため、rehype プラグインを足しても処理対象が存在しません。
✅ 正しく効かせるための「正統ルート」
remark
→ remark-gfm
→ remark-rehype
→ rehype-external-links
→ rehype-stringify
この流れでは、
- remark:Markdown AST
- rehype:HTML AST
- stringify:HTML文字列化
という役割分担が明確になり、rehype-external-links が正しく動作します。
手順1:必要なパッケージを追加する
すでに remark-gfm を使っている前提で、以下を追加します。
すべて役割が異なるため、どれも省略できません。
npm i remark-rehype rehype-stringify rehype-external-links
📌 各パッケージの役割
- remark-rehype:Markdown AST → HTML AST へ変換
- rehype-external-links:外部リンク判定と属性付与
- rehype-stringify:HTML AST → 文字列へ変換
手順2:src/lib/posts.ts を修正する(コピペ版)
ここでは、実務でそのまま使える形の実装例を示します。
既存のカテゴリー・タグ・検索処理には一切手を加えていません。
✅ 修正ポイントの要点
- 変わるのは
getPostの変換パイプラインのみ - Markdownの書き方は一切変更不要
- 外部リンクにのみ
target="_blank"が付与される
Next.js + Markdown の例
// src/lib/posts.ts
import fsfrom"fs";
import pathfrom"path";
import matterfrom"gray-matter";
import { remark }from"remark";
import remarkGfmfrom"remark-gfm";
import remarkRehypefrom"remark-rehype";
import rehypeExternalLinksfrom"rehype-external-links";
import rehypeStringifyfrom"rehype-stringify";
// 途中省略(構造は質問文と同一)
exportasyncfunctiongetPost(slug:string) {
const processed =awaitremark()
.use(remarkGfm)
.use(remarkRehype)
.use(rehypeExternalLinks, {
target:"_blank",
rel: ["noopener","noreferrer"],
})
.use(rehypeStringify)
.process(parsed.content);
return {
slug,
contentHtml: processed.toString(),
...parsed.data,
};
}
rel="noopener noreferrer" を付けているのは、セキュリティとパフォーマンス対策として実務ではほぼ必須です。
手順3:動作確認のポイント
変換ロジックを変更した場合、Next.js の開発サーバーではキャッシュの影響を受けることがあります。
反映されない場合は、以下を必ず実施してください。
🔁 確認手順
Ctrl + Cで dev サーバー停止npm run devで再起動- ブラウザを強制更新(
Ctrl + F5)
これで変換結果が最新になります。
成功判定:DevToolsで target="_blank" が付いているか
最後はブラウザでの確認です。
Chrome DevTools の Elements タブでリンク要素をチェックします。
✅ 成功している状態
<a
href="<https://example.com>"
target="_blank"
rel="noopener noreferrer"
>
- 内部リンク:
targetなし - 外部リンク:
target="_blank"あり
この挙動になっていれば、設定は完全に成功しています。
まとめ
- 外部リンクを別タブにすると、読者が記事へ戻りやすくなる
- Markdownに手を入れず、変換レイヤーで制御するのが運用向き
rehype-external-linksは rehype ルートでしか効かない- 正統ルートは
remark-gfm → remark-rehype → rehype-external-links → rehype-stringify
ニュース記事や技術記事を継続的に増やすなら、
リンクの挙動も最初に設計として固めておくことで、後から確実に楽になります。
必要になったときに「もう一段上の運用」を支えてくれる、小さいけれど重要な設定です。

コメント