quartzで自分だけのデジタルガーデンを作ろう

デジタルガーデンとは，個人の考えや興味を自由に表現し育てていくネット上の庭のような空間を指していると解釈しています．（参考：[MIT Technology Reviewの記事](https://www.technologyreview.jp/s/218383/digital-gardens-let-you-cultivate-your-own-little-bit-of-the-internet/)）．

今回はそんなデジタルガーデンを簡単に構築できる [quartz](https://github.com/jackyzha0/quartz?tab=readme-ov-file) を紹介します．


# quartz の特徴

https://github.com/jackyzha0/quartz

## カスタマイズのしやすさ
quartzの特徴は何といっても高いカスタマイズ性にあると思っています．
組み込みの設定項目とプラグインによって，自分だけのデジタルガーデンを簡単に作るために仕組みが備わっています．


### シンプルなコンテンツ記述
コンテンツはMarkdownでシンプルに記述できます．
レイアウトに関しても簡単な[設定ファイル](https://quartz.jzhao.xyz/layout)１つで見た目を割と好きに変更できます．

### 強力な組み込み機能
[ObsidianのMarkdown記法](https://help.obsidian.md/Editing+and+formatting/Basic+formatting+syntax#Internal%20links)と互換性があるため，WikilinkやMermeidといった機能をデフォルトで使えます．
さらに[全文検索](https://quartz.jzhao.xyz/features/full-text-search)や[タグによる記事の関連付け](https://quartz.jzhao.xyz/features/folder-and-tag-listings#tag-listings)などのコンポーネントも利用できるため，お手軽に高機能なページを構築できます．


### プラグイン
quartzには[豊富なプラグイン](https://quartz.jzhao.xyz/plugins/)が組み込まれており，設定１つでオンオフが簡単に切り替えられます．
これらのプラグインはユーザ側でも簡単に作れるようになっており，必要に応じてカスタマイズができるようになっています．

### コードベースの小ささ
他のSSGツールに比べるとコードの行数がかなり少ないことも特徴の1つです．
著名なSSGのOSSと比べると一目瞭然です．

 * [quartz](https://github.com/jackyzha0/quartz)：約1万行（`.ts` ファイルの行数合計）
 * [gatsby](https://github.com/gatsbyjs/gatsby)：約12万行（`.ts` ファイルの行数合計）
 * [hugo](https://github.com/gohugoio/hugo)：約19万行（`.go` ファイルの行数合計）

実装が把握しやすいため，何かカスタマイズしたいことがあれば比較的簡単に追加・修正ができるようになっています．


## デプロイのしやすさ
SSGなのでビルドしてファイルをサーバに置くだけで簡単にデプロイができます．
公式が[GitHub Pagesへのデプロイ用workflow](https://quartz.jzhao.xyz/hosting#github-pages)を用意してくれているので，数分で自分だけのデジタルガーデンが作れます．

GitHub Pages以外にも [Cloufrage Pages](https://quartz.jzhao.xyz/hosting#cloudflare-pages) や [Vercel](https://quartz.jzhao.xyz/hosting#vercel) など各種ホスティングサービスに対応しているため，こちらの [Hosting](https://quartz.jzhao.xyz/hosting) を見てみてください．


# 5分で始めるデジタルガーデンの構築
自分がやっているAWS S3 + CloudFront でのホスティング手順を紹介します．

## 前提条件
* Node >= v20
* npm >= v9.3.1

## HelloWorld!
まずはquartzをクローンしてきましょう．
```bash
git clone https://github.com/jackyzha0/quartz.git
cd quartz
npm i
npx quartz create
```

お好みのオプションを選択するとコンテンツ用のフォルダとレイアウトファイルが作成されるので，下記のファイルを編集しましょう．

### コンテンツファイル
`content`ディレクトリの下に新しく `hello.md` でも作って新規ページを作成してみましょう．

```markdown:content/hello.md
---
title: Hello, world!
---

This is the first content.
```

### レイアウトファイル
[コンポーネントリスト](https://quartz.jzhao.xyz/tags/component)から好きなコンポーネントを選んで追加してみてください．

<details> <summary> 長いので省略 </summary>

```typescript:quartz.layout.ts
import { PageLayout, SharedLayout } from "./quartz/cfg"
import * as Component from "./quartz/components"

// components shared across all pages
export const sharedPageComponents: SharedLayout = {
  head: Component.Head(),
  header: [],
  afterBody: [],
  footer: Component.Footer({
    links: {
      GitHub: "https://github.com/jackyzha0/quartz",
      "Discord Community": "https://discord.gg/cRFFHYye7t",
    },
  }),
}

// components for pages that display a single page (e.g. a single note)
export const defaultContentPageLayout: PageLayout = {
  beforeBody: [
    Component.Breadcrumbs(),
    Component.ArticleTitle(),
    Component.ContentMeta(),
    Component.TagList(),
  ],
  left: [
    Component.PageTitle(),
    Component.MobileOnly(Component.Spacer()),
    Component.Search(),
    Component.Darkmode(),
    Component.DesktopOnly(Component.Explorer()),
  ],
  right: [
    Component.Graph(),
    Component.DesktopOnly(Component.TableOfContents()),
    Component.Backlinks(),
  ],
}

// components for pages that display lists of pages  (e.g. tags or folders)
export const defaultListPageLayout: PageLayout = {
  beforeBody: [Component.Breadcrumbs(), Component.ArticleTitle(), Component.ContentMeta()],
  left: [
    Component.PageTitle(),
    Component.MobileOnly(Component.Spacer()),
    Component.Search(),
    Component.Darkmode(),
    Component.DesktopOnly(Component.Explorer()),
  ],
  right: [],
}
```
</details>

## ビルド & デプロイ
下記のyamlを `.github/workflows/deploy.yaml` とかに置けば，mainブランチへのプッシュ時に勝手にビルド & デプロイしてくれます．
※ Secrets に適切に値を設定する必要があります

<details><summary>GitHub Actions定義</summary>

```yaml
name: Build And Deploy

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: 18
      - run: npm ci
      - run: npx quartz build --bundleInfo
      - name: Setup AWS CLI
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_DEFAULT_REGION }}
      - name: S3 sync
        working-directory: public
        run: aws s3 sync --delete . s3://xxx/yyy
      - name: Cloudfront invalidate cache
        run: aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*"
```
</details>


以上です！
デジタルガーデンの育成，思った以上にお手軽で面白いので，皆さんも是非楽しんでみて下さい．