AstroJavaScriptMarkdoc

Astro + Markdocで、マークダウンファイルを取り込む

Astro2.1から追加された、Markdocインテグレーションを試してみました。 A new experimental Markdoc integration has also been published along […]

広告ここから
広告ここまで

Astro2.1から追加された、Markdocインテグレーションを試してみました。

A new experimental Markdoc integration has also been published alongside Astro 2.1.
https://astro.build/blog/astro-210/#markdoc-integration

Astroプロジェクトをセットアップ

まずはプロジェクトを立ち上げましょう。

% npm create astro@latest
Need to install the following packages:
  create-astro@latest
Ok to proceed? (y) 

対話形式でセットアップします。

   dir   Where should we create your new project?
         ./astro-markdoc

  tmpl   How would you like to start your new project?
         ○ Include sample files 
         ● Use blog template 
         ○ Empty

  deps   Install dependencies?
         Yes

    ts   Do you plan to write TypeScript?
         ● Yes  ○ No 

   use   How strict should TypeScript be?
         ● Strict (recommended)
         ○ Strictest 
         ○ Relaxed 

   git   Initialize a new git repository? (optional)
         ● Yes  ○ No 

Markdocを追加する

astroコマンドで、Markdocを追加しましょう。

@astrojs/markdocがインストールされます。

% npx astro add markdoc
✔ Resolving packages...

  Astro will run the following command:
  If you skip this step, you can always run it yourself later

 ╭────────────────────────────╮
 │ yarn add @astrojs/markdoc  │
 ╰────────────────────────────╯

✔ Continue? … yes

Configファイルの変更も、CLIに任せることができます。


  Astro will make the following changes to your config file:

 ╭ astro.config.mjs ──────────────────────────────╮
 │ import { defineConfig } from 'astro/config';   │
 │ import mdx from '@astrojs/mdx';                │
 │ import sitemap from '@astrojs/sitemap';        │
 │                                                │
 │ import markdoc from "@astrojs/markdoc";        │
 │                                                │
 │ // https://astro.build/config                  │
 │ export default defineConfig({                  │
 │   site: 'https://example.com',                 │
 │   integrations: [mdx(), sitemap(), markdoc()]  │
 │ });                                            │
 ╰────────────────────────────────────────────────╯

? Continue? › (Y/n)

次のメッセージが表示されれば完了です。

───────────────────────────╯

✔ Continue? … yes
  
   success  Added the following integration to your project:
  - @astrojs/markdoc

Markdocでコンテンツを追加しよう

早速コンテンツを追加しましょう。

まずはディレクトリとファイルを配置します。

% mkdir src/content/docs
% touch src/content/docs/hello-world.mdoc

Markdoc公式サイトのサンプルを、hello-world.mdocに追加しました。

---
title: What is Markdoc?
---

# {% $markdoc.frontmatter.title %} {% #overview %}

Markdoc is a Markdown-based syntax and toolchain for creating custom documentation sites. Stripe created Markdoc to power [our public docs](http://stripe.com/docs).

{% callout type="check" %}
Markdoc is open-source—check out its [source](http://github.com/markdoc/markdoc) to see how it works.
{% /callout %}

## How is Markdoc different?

Markdoc uses a fully declarative approach to composition and flow control, where other solutions… [Read more](/docs/overview).

## Next steps
- [Install Markdoc](/docs/getting-started)
- [Explore the syntax](/docs/syntax)

{% $markdoc.frontmatter.title %}など、Markdoc独自の構文が含まれています。

今回のようなデモ・試してみた系には、ちょうどよさそうです。

Astrodえページを生成する

作成したファイルを元に、ページを生成しましょう。

まずはディレクトリとファイルを作成します。

% mkdir src/pages/docs 
% touch "src/pages/docs/[...slug].astro"

src/pages/docs/[...slug].astroにコンテンツの中身を表示するコードを追加します。

---
import { CollectionEntry, getCollection } from 'astro:content';

export async function getStaticPaths() {
    const posts = await getCollection('docs');
    return posts.map((post) => ({
        params: { slug: post.slug },
        props: post,
    }));
}
type Props = CollectionEntry<'docs'>;

const post = Astro.props;
const { Content } = await post.render();
---

<h1>{post.data.title}</h1>
<Content />

getStaticPathsで、getCollection('ディレクトリ名')からページに生成します。

この辺りは、Markdownやmdxを使う際とほぼ同じではないかと思います。

ローカルで動かしてみる

astro devを実行すると、mdocに記載した内容が描画されます。

Markdocでタグをカスタマイズする

ここまでだと、普通のMarkdownと変わり映えしないので、タグをカスタマイズしてみます。

src/components/Heading.astroを作成して、コードを追加しましょう。

<header id={Astro.props.id}>
    <h1 class={`level-${Astro.props.level}`}><slot></slot></h1>
</header>

astro.config.mjsで作成したタグとカスタマイズするMarkdocタグを関連づけます。

export default defineConfig({
  site: 'https://example.com',
  integrations: [mdx(), sitemap(), markdoc({
    nodes: {
      heading: {
        render: 'Heading',
        attributes: {
          level: {
            type: String
          }
        }
      }
    }
  })]
});

最後に、src/pages/docs/[...slug].astroでタグを読み込ませましょう。

---
import { CollectionEntry, getCollection } from 'astro:content';
import Heading from '../../components/Heading.astro'

export async function getStaticPaths() {
    const posts = await getCollection('docs');
    return posts.map((post) => ({
        params: { slug: post.slug },
        props: post,
    }));
}
type Props = CollectionEntry<'docs'>;

const post = Astro.props;
const { Content } = await post.render();
---

<h1>{post.data.title}</h1>
<Content
    components={{ Heading }}
/>

これでカスタマイズできます。

独自タグや既存のMarkdown構文のカスタマイズに、活用しましょう。

おまけ: Cloudflare Pagesへデプロイ

Cloudflare Pagesにデプロイしてみましょう。

SSGとしてデプロイするため、Astroでビルドしてからデプロイします。

% npm run build
% npx wrangler pages publish dist

新しいプロジェクトの作成や、既存プロジェクトへの連携が行えます。


No project selected. Would you like to create one or use an existing project?
❯ Create a new project
  Use an existing project
? Enter the name of your new project: › astro-markdoc
✔ Enter the production branch name: … main

デプロイが始まります。


POST /pages/assets/upload
POST /pages/assets/upload
POST /pages/assets/upload
result: null
result: null
result: null
🌍  Uploading... (20/20)

✨ Success! Uploaded 20 files (2.80 sec)

✨ Deployment complete! Take a peek over at https://xxxxx.astro-markdoc.pages.dev

アップロードできました。

これでAstroとMarkdocを利用したサイトを、Cloudflare Pagesでホストできます。

Markdownなどのファイル読み込み系は、SSR難しそうかも

AstroのSSRモードも、Cloudflare Pages(Workers)で試してみました。

次のようなエラーが出たため、現在はSSGでの利用が良いかもしれません。

 error   post.render is not a function
  File:
    /Users/sandbox/astro-markdoc/src/pages/docs/[...slug].astro:23:34
  Stacktrace:
TypeError: post.render is not a function
    at eval (/Users/sandbox/astro-markdoc/src/pages/docs/[...slug].astro:23:34)

 error   Could not resolve "module"
  File:
    dist/$server_build/_worker.mjs:10:7
  Code:
    9 | import 'string-width';
    > 10 | import 'module';
         |       ^
      11 | import 'node:fs/promises';
      12 | import 'node:url';
      13 | import 'html-escaper';

Markdocではなく、「ファイルを読み込む処理」がWorkersで引っかかっているのかも・・・?

参考

ブックマークや限定記事(予定)など

WP Kyotoサポーター募集中

WordPressやフロントエンドアプリのホスティング、Algolia・AWSなどのサービス利用料を支援する「WP Kyotoサポーター」を募集しています。
月額または年額の有料プランを契約すると、ブックマーク機能などのサポーター限定機能がご利用いただけます。

14日間のトライアルも用意しておりますので、「このサイトよく見るな」という方はぜひご検討ください。

広告ここから
広告ここまで

Related Category posts