Guides

Markdown でページを書く

Markdown コンテンツを Effront のページとして公開するためのガイド。

Markdown の記事を Effront アプリケーションのページとして表示し、記事へのリンクやローカルアセットの参照を公開 URL に解決できます。 この例では、@effront/markdown と Comark の React レンダラーで記事を表示します。

記事を追加する

コレクションとパーサー、React レンダラーをアプリケーションにインストールします。

vp add @effront/markdown@0.2.0

src/content/intro.md を作成します。

# Introduction

Welcome to the manual.

コレクションの import と解析処理はサーバー側のモジュールに置きます。

コレクションを読み込む

src/manual.ts を作成します。

import { createMarkdownCollection } from "@effront/markdown";

export const manual = createMarkdownCollection({
  basePath: "/manual",
  documents: import.meta.glob<string>("./**/*.md", {
    base: "./content",
    query: "?raw",
    import: "default",
    eager: true,
  }),
});

これで intro.md を /manual/intro として検索できますが、アプリケーションのルートはまだ登録されません。

ローカルの画像やダウンロードファイルを使う場合は、src/manual.ts で assets を定義して渡します。

// src/manual.ts: add before manual.
const assets = import.meta.glob<string>("./**/*.{svg,png,jpg,pdf}", {
  base: "./content",
  query: "?url",
  import: "default",
  eager: true,
});

// Replace the manual declaration, adding assets.
export const manual = createMarkdownCollection({
  basePath: "/manual",
  assets,
  documents: import.meta.glob<string>("./**/*.md", {
    base: "./content",
    query: "?raw",
    import: "default",
    eager: true,
  }),
});

参照するアセットのファイル形式をすべて glob に含めてください。 文書とアセットで同じ base を指定し、相対参照の基準位置を揃えてください。

記事を URL で表示する

Getting started の src/entry.effront.tsx に import と IntroPage を追加し、ホームページとともに登録します。

// src/entry.effront.tsx: add to the imports.
import { MarkdownDocument } from "@effront/markdown/document";
import "@effront/markdown/styles.css";
import { parseMarkdown } from "@effront/markdown";
import { manual } from "./manual";

// Add before the default export.
const IntroPage = EFFRONT.Page.make({
  render: Effect.fn("IntroPage.render")(function* () {
    const collection = yield* manual;
    const entry = collection.get("/manual/intro");
    if (!entry) throw new TypeError("Registered article is missing");
    const document = yield* parseMarkdown(entry);
    return (
      <article>
        <MarkdownDocument value={document} />
      </article>
    );
  }),
});

// Replace the default export.
export default EFFRONT.make({
  routes: EFFRONT.Routes.make({ layout: RootLayout })
    .page("/", HomePage)
    .page("/manual/intro", IntroPage),
});

ブラウザーで /manual/intro を開くと、Layout の内側に記事が表示されます。 Markdown 本文のスタイリングは提供しません。 アプリ側で独自にスタイリングするか、Tailwind Typography などを導入してください。 Styling も参照してください。

src/content/details.md の Page が /manual/details に登録されている場合、intro.md 内の [Details](./details.md#example) は /manual/details#example に解決されます。 アセットの相対参照は記事のディレクトリを基準に解決され、import 済みの URL を使います。 解決できない参照は MarkdownError になります。

catch-all ルートを使う場合は、コレクションの完全な例を参照してください。 HTTP middleware で要求された記事を検索し、get() が undefined を返したら描画前に 404 を返します。 上の固定ルートの例では、登録済みの記事が見つからない場合を設定ミスとして扱います。 コレクションや解析の失敗も、Effect のエラーチャネルで MarkdownError として返されます。

解析や表示を変更する

Comark の構文で記事を書き、parseMarkdown(entry) と Effront の標準設定で解析します。 解析を変えるには、parseMarkdown(entry, { linkify: false }) のように、第 2 引数に Comark の ParserOptions を渡します。

パーサープラグインを追加するには、comark@0.6.2 を直接の依存関係としてインストールし、src/entry.effront.tsx を変更します。

// src/entry.effront.tsx: add to the imports.
import toc from "comark/plugins/toc";

// Replace IntroPage, keeping its route registration unchanged.
const IntroPage = EFFRONT.Page.make({
  render: Effect.fn("IntroPage.render")(function* () {
    const collection = yield* manual;
    const entry = collection.get("/manual/intro");
    if (!entry) throw new TypeError("Registered article is missing");
    // Add the parser plugin to this call.
    const document = yield* parseMarkdown(entry, { plugins: [toc()] });
    return (
      <article>
        <MarkdownDocument value={document} />
      </article>
    );
  }),
});

追加プラグインは Effront の標準プラグインの後に実行され、標準プラグインを置き換えるものではありません。 上の MarkdownDocument とスタイルシートの import だけで、解析したドキュメントを表示できます。 Math と Mermaid は標準で登録されているため、個別の登録は不要です。 表示を変更するには、@effront/markdown/math の Math や @effront/markdown/mermaid の Mermaid を好みのオプションでラップするか、独自のコンポーネントを実装します。 差し替えるコンポーネントを MarkdownDocument の components に渡してください。 各コンポーネントのオプションは Comark の React レンダラーを参照してください。

オプションと参照解決の規則は Markdown リファレンスを参照してください。