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で引っかかっているのかも・・・?