はじめに

こんにちは、Rerurate_514と申します。
今回は

の16日目ということで、この私のブログサイト

を作成した話をしようかと思います。

経緯

今年の初めぐらいにドメインを買いまして、それをずーーーーっと放置しておりました。

さらに、Obsidian上で自分だけのメモを作成していたので、どうにかそれを公開できないかと考えていました。
そこでいろいろ調べていたところ、このようなサイトを発見いたしました。

これを見たらめっちゃ簡単そうだったので、 Quartz を使用してのWebサイト構築をすることに。
ただ、GithubPagesでは既に自分のportfolioサイトを作っていたので、CloudflarePagesを使うことにしてみました。

Quartzでできること

  • Obsidianで書かれたマークダウンファイルをそのまま公開
    • wikilink形式(![[]][[]]をObsidianと同じようにレンダリング )
  • 簡単に静的サイト公開
    • 既にある程度サイト構築用のコンポーネントが用意されているので、最悪Quartzプロジェクトを作成して記事を放り込むだけでOK
  • すごいカスタマイズ
    • npmなどでライブラリが提供されているというわけでなく、すべてレンダリングなどのファイルをダウンロードする形式なので、内部構造までいじることができる。
    • 描画プラグインなど自分で作成して、適用できる。
      • 自分もAutoCardLinkTitleをレンダリングしたくて、プラグインを作成した。
  • レイアウト設定がすごい簡単
    • quartz.layout.tsをいじるだけ
    • ここに関してはFlutterよりも簡単だった
  • 標準でモバイル対応(レスポンシブデザイン)とダークモードライトモード対応がされている。
    • なので、その辺の面倒くさい部分を全部Quartzがやってくれた状態でサイトを公開することができる。

やりかた

ぶっちゃけQuartzのinstallとかは上のnoteの記事に載っているので、それをCloudflareに上げる手順の方を書きます。
(QuartzプロジェクトをGithubリポジトリにプッシュしたところまで。)

ドメインを買いましたら、Cloudflareのダッシュボード上でアプリケーションを作成するを選択。
そこからGitの接続の画面に行くので、いろいろ設定。
ただしここでコマンドなどを以下のように設定する。

  • ビルドコマンド
git fetch --unshallow && npx quartz build
  • デプロイコマンド
npx wrangler deploy --assets=./public --compatibility-date $(date +%Y-%m-%d)

あとはいじらない

Note

このデプロイコマンドが公式サイトに書かれていなくてめっちゃ苦戦した;;

あとは設定から、カスタムドメインの項目を自分が買ったドメインにするだけ

これでQuartzプロジェクトを更新するだけで勝手にデプロイが走って、勝手に公開されるようになる。
noteにあるようなObsidianGitを使用しているなら記事を書くだけで、勝手にサイトに公開されていくので、めっちゃ楽。

開発するときは、npx quartz build --serveとコマンドを打つとlocalhost:8080でローカルサーバが立ち上がる。
ホットリロードなので神、ただしFlutterと違って書いているときにエラーの状態で保存するとサーバがなくなるので、もう一度コマンドを打つ必要がある。

エラーログ

このようなエラーが現れることがあったら、以下のログを参照してください。
エラー:

23:47:00.313 sh: 1: quartz: Permission denied
23:47:00.335 Failed: error occurred while running build command

その時は、cloudflareのビルドコマンドを以下のものに変更するだけ。

git fetch --unshallow && node quartz/bootstrap-cli.mjs build

何が発生原因かはわかっていない。

カスタマイズ

先ほども説明した通り、Quartzはめっちゃカスタマイズができる。
例えば、 SCSS のスタイル。


自分でサイトの色合いやフォントをカスタマイズすることができる。既に存在しているコンポーネントやサイト全体の見た目も変えることができる。
デフォルトで用意されているコンポーネントも

このようにscssがダウンロードされる形式なので、それをいじるだけで簡単に見た目を変えることができる。

そして自分でコンポーネントを作成することもできる。
コンポーネントはすべて React で作成される。

Hookの使用について

ただし、QuartzではReactで使用できるuseRefuseStateが使用できない。
もし、コンポーネントに機能を持たせる場合は JavaScriptDOM操作を使用する必要がある。
Hookの代わりにこんな感じのスクリプトを書く。

import { getFullSlug } from "../../util/path"
 
const checkboxId = (index: number) => `${getFullSlug(window)}-checkbox-${index}`
 
document.addEventListener("nav", () => {
  const checkboxes = document.querySelectorAll(
    "input.checkbox-toggle",
  ) as NodeListOf<HTMLInputElement>
  checkboxes.forEach((el, index) => {
    const elId = checkboxId(index)
 
    const switchState = (e: Event) => {
      const newCheckboxState = (e.target as HTMLInputElement)?.checked ? "true" : "false"
      localStorage.setItem(elId, newCheckboxState)
    }
 
    el.addEventListener("change", switchState)
    window.addCleanup(() => el.removeEventListener("change", switchState))
    if (localStorage.getItem(elId) === "true") {
      el.checked = true
    }
  })
})
 

コンポーネントはQuartzコンポーネントとして定義される。
下に例を示す。

import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
import { classNames } from "../util/lang"
 
const NoteStatus: QuartzComponent = ({ fileData, displayClass }: QuartzComponentProps) => {
    const status = fileData.frontmatter?.status
 
    if(status) {
        return (
            <strong class="status-container">
                <span>📋 Note Status: </span>
                <span class={classNames(displayClass, "status")}>
                    {status}
                </span>
            </strong>
        )
    } else {
        return (
            <strong class="status-container">
                <span class="note-status">📋 Note Status: </span>
                <span class={classNames(displayClass, "status")}>
                    📦 明示的な指定なし
                </span>
            </strong>
        )
    }
}
 
NoteStatus.css = `
    .status-container {
        display: flex;
        background-color: var(--dark);
        color: var(--light);
        padding: 8px;
    }
 
    .note-status {
        margin-right: 4px;
    }
`
 
export default (() => NoteStatus) satisfies QuartzComponentConstructor

ここでcssをそのまま挿入しているが、別でscssファイルを作成することもできる。
その場合はこのように書く。

import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
import { classNames } from "../util/lang"
import style from "./style/noteStatus.scss"
 
const NoteStatus: QuartzComponent = ({ fileData, displayClass }: QuartzComponentProps) => {
    const status = fileData.frontmatter?.status
 
    if(status) {
        return (
            <strong class="status-container">
                <span>📋 Note Status: </span>
                <span class={classNames(displayClass, "status")}>
                    {status}
                </span>
            </strong>
        )
    } else {
        return (
            <strong class="status-container">
                <span class="note-status">📋 Note Status: </span>
                <span class={classNames(displayClass, "status")}>
                    📦 明示的な指定なし
                </span>
            </strong>
        )
    }
}
 
NoteStatus.css = style
 
export default (() => NoteStatus) satisfies QuartzComponentConstructor

style変数として、scssファイルをimportし、コンポーネントに込めるだけである。

そして、このようにコンポーネントを定義したら、quartz/components/index.tsからexportするように設定するだけ。
あとはquartz.layout.tsで表示する場所を決めると描画されるようになる。
ちなみに上の例のNoteStatus


はここに書いていて、それが

ここに描画されていることがわかる。

私のサイトを見ても、デフォルトで存在しないコンポーネントがいくつかあるが、全部書いたり、コミュニティから持ってきたもの。

個人的にカスタマイズ大好き(Obsidianもめちゃくちゃプラグインとかテーマいじる)人間なので、こういうの好き

Quartzではさらにレンダリングパイプラインもいじることができるので、Obsidianにしかない独自記法、例えばAutoCardLinkTitle

```cardlink
url: https://rerurate.com/articles/%E3%83%97%E3%83%AA%E3%83%9F%E3%83%86%E3%82%A3%E3%83%96%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%AA%E3%81%84%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0
title: "プリミティブを使用しないプログラミング"
description: "はじめに こんにちは、Rerurate_514と申します。 adventar.org/calendars/12078 13日目の記事です。 元々は、PDFのオブジェクトとストリームを解説する記事を投稿する予定だったんですが、思ったより大変そうだったので辞めました。 最近はずっとPDFの内部構造について勉強していたので、いけるかなーって思ってたんですけど、だめでした;; 今回はプリミティブを使用しないプログラミングと題しまして、反プリミティブの私が説いていこうと思います。 Info プリミティブ型とは、stringやintなどのデフォルトで提供されている値のこと よく、アプリなどを作成する際には..."
host: rerurate.com
favicon: ../static/icon.png
image: https://rerurate.com/static/og-image.png
```

こういうやつも自分でどういうHTMLに変換するかを決めて書くことができます。
ちなみにこれは上で見るような画像+記事タイトル+説明+domainという形で書けます。

おわり

Quartzを使用するとめっちゃ簡単にObsidianで作成した記事やメモなどを公開することができるので、おすすめです。
公開するファイルとか指定することができるので、まんまObsidianPublishと同じような感じで無料でできます。(ドメイン料だけ、GithubPagesを使うなら完全無料)
自分もめっちゃメモ公開しているので見てみてね