【Deno】準備編:MarkdocとFreshでドキュメントサイトを作る
MarkdocとFreshを使ってドキュメントサイトのテンプレートを作ろうとしている記事です。
MarkdocとFreshについては、以前記事を書きましたので良ければ読んでいただけると嬉しいです。
この二つの技術を選んだことに大きな理由はないのですが、強いて述べるとすれば、最近denoがnpmに対応したとのことで、そうであればdenoとMarkdocの組み合わせもできるかと思い試してみました。
とりあえず動かす
freshのプロジェクトを作る
deno run -A -r https://fresh.deno.dev doc-site
Markdocを読み込む
denoではパッケージをimport_map.json
で管理しているので、そこにmarkdocを追記します。
"markdoc": "npm:@markdoc/markdoc"
MarkdownをMarkdocで表示する
コンポーネントを作る
Makdownを表示するための、Pageというコンポーネントをcomponents/Page.tsx
に作ります。
注意点として、freshはpreactを使っているので、import React from "preact/compat";
でReactにレンダリングできるようにします。
import Markdoc from "markdoc";
import React from "preact/compat";
export function Page() {
const doc = `
# Hello world.
> My first Markdoc page
`;
const ast = Markdoc.parse(doc);
const content = Markdoc.transform(ast);
const html = Markdoc.renderers.react(content, React);
return html;
}
コンポーネントを表示
route/index.tsx
を書き換えて、Pageコンポーネントを表示します。
import { Page } from "../components/Paper.tsx";
export default function Home() {
return (
<div>
<Paper />
</div>
);
}
コマンドの書き換え
最後に、denoのnpmサポートはまだ実験段階なので、denoで動かすときには特別なフラグ--unstable
が必要です。そのため、deno.json
を書き換えます。
{
"tasks": {
"start": "deno run --unstable -A --watch=static/,routes/ dev.ts"
},
"importMap": "./import_map.json",
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact"
}
}
それでは、実行。
deno task start
Markdocをあっさりと読み込み、特に問題なく動いたので驚きました。denoすごい。
...と思ったのですが、deno deployにデプロイしようすると次のようなエラーが出て失敗。デプロイする方法は模索中です。
冒頭でも述べた通り、esm.sh
を使えばDeno Deployにデプロイしても問題なく使えます。
Error The deployment failed: Module not found "npm:@markdoc/markdoc".
ファイルを読み込む
Markdownを直書きしているので、ファイルを読み込むようにします。
static/docs/markdown.md
を追加。
markdown.md
# Headers
**Bold**
_Italic_
[Links](/docs/nodes)
![Images](/logo.svg)
Lists
- Item 1
- Item 1
- Item 1
> Quotes
`Inline code`
Code fences
pageコンポーネントが引数を受け取るように書き換える。
import Markdoc from "markdoc";
import React from "preact/compat";
export function Page(props: { doc:string }) {
console.log(props.doc.markdown);
const ast = Markdoc.parse(props.doc);
const content = Markdoc.transform(ast);
const html = Markdoc.renderers.react(content, React);
return html;
}
Handlerを使って、GETアクセスが来たらファイルを読み込んでコンポーネントに渡すようにする。
import { Handlers, PageProps } from "$fresh/server.ts";
import { Page } from "../components/Page.tsx";
interface Data {
markdown: string;
}
export const handler: Handlers = {
async GET(_req, ctx) {
const url = new URL(`../static/docs/markdown.md`, import.meta.url);
const fileContent = await Deno.readTextFile(url).catch( _ => {
return "Page Not Found"
});
const page = {markdown : fileContent}
const resp = ctx.render(page);
return resp;
},
};
export default function Home(props: PageProps<Data> ) {
return (
<div>
<Page doc={props.data.markdown} />
</div>
);
}
ここまでで、基本的な準備が完了したので、あとはルーティングやサイドバー、ヘッダーを作成していきます(未完成)
デプロイが出来たら現時点でのサイトのリンクを貼りたかったのですが、上手くいっていないのでスクショだけ貼っておきます。
デザインは完全にFreshのドキュメントを真似ています。
また、今回の内容はMandarinという名前でリポジトリを作っています。
もし、この組み合わせでやってみたい方がいらしたら参考になるかも?
Discussion