Web日記構築備忘録

# 概要
よく妻に「何をやっているのかよくわからない…」と言われるので、以前からTimeTreeに研究の日記をつける様にしていた（よく三日坊主するので怒られる）。
が、結局TimeTreeだと普段の予定と混ざってしまって見にくい。別でまとめて欲しいということで、自宅Webサーバを立ててローカルネットワーク内で見れるWebページを作り、そこにまとめることにした。

この記事では、自宅Webページ構築の手筈をまとめる。

# 完成図
こんな感じ。

![スクリーンショット 2022-12-07 1.37.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235241/3dd8715c-16e5-2c45-93b0-15b7eec447c5.png)
![スクリーンショット 2022-12-07 1.37.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235241/ff4b3ccb-c75c-1cc3-6e41-88e97fcd5d8e.png)
![スクリーンショット 2022-12-07 1.37.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235241/423a0a94-c57e-5ec1-5782-08fdfd3d58db.png)


# 要件
Webページ構築にあたっての要件は以下の通り。
- 簡単に作れること（そんなに時間をかけていられない。１~2日で構築を完了したい）
- 更新が簡単なこと（いちいちめんどくさいと更新しなくなる）
- 各日ごとに日記を付けられること
- どこでも（どの端末からでも）日記を付けられること
- 日記だけでなく、扱っている事柄について別で個別に解説ページなどが書けること

また、
- 最近[Obsidian](https://obsidian.md/)というMarkdownエディタ（ナレッジベース）を知り、色々まとめるのに使っている。
Obsidianには標準で日記機能がついており、`YYYY-MM-DD.md`というファイル名で日記を付けることができる。
あわよくばこれを有効活用したい。[^1]

以上のような要件のもとで実現できる方法を考えた。

# Obsidian
まずObsidian側では、Google DriveにVault（書庫）を置くことにした。これによりPC・スマホのどちらからでも日記を付けることができる。
PC側では問題ないが、スマホだとローカルフォルダしか書庫にできないので、ファイル同期アプリを使って`Google Drive上のVault`<->`ローカルのVault`の同期をとった。

フォルダの構成としてはこんな感じ。

```bash
Obsidian Vault
    |- daily note
        |- 2022-01-01.md
        |- 2022-01-02.md
        |- ...
        |- note1.md
        |- note2.md
        |- ...
```
各記事間はmarkdownのリンクを使えば自由に行き来できる様にしてあり、例えばこんな使い方をしたい。
```markdown:2022-01-01.md
# 2022-01-01
今日は[ほげほげ](note1.md)についてやりました
```

```markdown:note1.md
# ほげほげ
「ほげほげ」とは、....
```

こういうmarkdownファイルを前提としてWebページづくりを始めた。

# MDWiki
そういえばWikipediaにもその日の記事とかあるよな？と思い出したので、Wiki的な物を簡単に作れないかと考えた。
[MDWiki](http://dynalon.github.io/mdwiki/#!index.md)は、単一のhtmlファイルで、Markdownを簡単にWiki的に（ただし編集機能とかはない）を作ることができる。

具体的には、
```bash
|- Sites
    |- mdwiki.html
    |- index.md
    |- 2022-01-01.md
    |- 2022-01-02.md
    |- ...
    |- note1.md
    |- note2.md
    |- ...
```
というふうに置いておくと、`http://www.example.com/mdwiki.html#!myfile.md`みたいにして各markdownをページとして表示できる様になる。

## 構成
以上を踏まえて、次のような構成・運用をすることにしてみた。
1. 毎日一回、Google Drive上の各markdownファイルを`mdwiki.html`と同じディレクトリまでコピー
1. 更新したファイルを元に`index.md`を更新

`index.md`は、日記のページ一覧と個別記事へのリンクを含む様にする。
これを実現するために、以下のようなシェルスクリプト(`update.sh`)を書いた。

```bash:update.sh
rsync ~/Google\ Drive/マイドライブ/Obsidian\ Vault/daily\ notes/*.md ~/Sites/ -vu

echo '# 最近更新したページ' > recent_changes.md
for fpath in `ls -t ~/Sites/*.md`; do
  f=${fpath##*/}
  echo "- [${f%.*}]($f) >> recent_changes.md"
  echo "- [${f%.*}]($f)" >> recent_changes.md
done
echo >> recent_changes.md
echo Last Update\: `date` >> recent_changes.md

cat .index.md > index.md
for fpath in `ls -r ~/Sites/*-*-*.md`; do
  f=${fpath##*/}
  echo "- [${f%.*}]($f) >> index.md"
  echo "- [${f%.*}]($f)" >> index.md
done
echo >> index.md

echo '## 項目一覧' >> index.md
for fpath in `ls -r ~/Sites/*.md | grep -v '[0-9]*\-[0-9]*\-[0-9]*.md' | grep -vE '(index|template|navigation|recent_changes)\.md'`; do
  f=${fpath##*/}
  echo "- [${f%.*}]($f) >> index.md"
  echo "- [${f%.*}]($f)" >> index.md
done  
echo >> index.md
echo Last Update\: `date` >> index.md
```

上では`index.md`を`.index.md`に各ページへのリンクを追加する形で生成している。
```markdown:.index.md
# 日記
## はじめに
日記をまとめたサイトです。手動更新中...

## 日記一覧
<!---
  ここに個別ページへのリンクが入る
-->
```

また、最近更新したページを表示するために、`recent_changes.md`というページも個別で生成する様にした。
MDWikiでは、`navigation.md`というファイルを用意しておくとページ上部に表示されるナビゲーションバーを作ることができるので、トップページと最近更新したページへのリンクをそこに表示させることにした：
```markdown:navigation.md
# 日記  <!--- ページタイトル --->

[トップページ](index.md)　　<!--- 項目をかいとくとバーに表示される --->
[最近更新したページ](recent_changes.md)　　
[gimmick: math]()　　　<!--- 各ページでLaTeX表記を有効化 --->

```

この`update.sh`を`cron`で定期実行する様にし、
```bash
python -m http.server 8000
```
でサーバーを立ち上げ、ローカル環境からMDWikiで作られたページにアクセスできる様になった。

完成物はこんな感じ。

![スクリーンショット 2022-12-07 1.53.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235241/f88019c4-33ab-cada-6355-6272d12574bb.png)

# Docusaurus
MDWikiのままでもいいのだが、更新が2014年あたりで止まっており、もうちょっとモダンなのに移行したい感があった。
よくよく考えてみるとやりたいことは別にWikiを作ることではなくて静的Webサイトを簡単に作ることなのである。
その上で改めて調べてみると[Docusaurus](https://docusaurus.io/)というのがあった。
Docusaurusも結局markdownを元にページを生成することができるので、これに移行してみることにした。

## 構成
まずはDocusaurusのガイドに従って、Node.jsを入れ、
```bash
npx create-docusaurus@latest my-website classic
```
でテンプレートを生成する。

Docusaurusにはいくつかのページスタイルが用意されている。
- Pages
  - 一番シンプルなページ。ただ内容を表示するだけ。
- Docs:
  - ナビゲーションバーを表示させ、Docs間を階層的・順序的に見せることができる。
- Blog:
  - 各記事を`/blog`に一覧表示させることができる。各記事をクリックすると個別のページに飛び、前後の日の記事に遷移するボタンなども挿入される。

今回は日記をBlogスタイルで、個別記事をDocsスタイルで表示させることにした。

Docusaurusでは各スタイルの記事ごとに別のディレクトリに置かないといけないので、まずVaultのディレクトリ構造を少し変更し、
```bash
Obsidian Vault
    |- daily note
        |- blogs
            |- 2022-01-01.md
            |- 2022-01-02.md
            |- ...
        |- docs
            |- note1.md
            |- note2.md
            |- ...
```

`update.sh`は以下の様に変更した。

```
rsync ~/Google\ Drive/マイドライブ/Obsidian\ Vault/daily\ notes/blog/*.md ~/Sites/research-diary/blog -vu
rsync ~/Google\ Drive/マイドライブ/Obsidian\ Vault/daily\ notes/docs/*.md ~/Sites/research-diary/docs -vu
```

余計なテンプレートは削除した上で、トップページ(`src/pages/index.js`)の余計なボタンを削除し：
```javascript:index.js
import React from 'react';
import clsx from 'clsx';
import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import Layout from '@theme/Layout';
import HomepageFeatures from '@site/src/components/HomepageFeatures';

import styles from './index.module.css';

function HomepageHeader() {
  const {siteConfig} = useDocusaurusContext();
  return (
    <header className={clsx('hero hero--primary', styles.heroBanner)}>
      <div className="container">
        <h1 className="hero__title">{siteConfig.title}</h1>
        <p className="hero__subtitle">{siteConfig.tagline}</p>
        {/* <div className={styles.buttons}>
          <Link
            className="button button--secondary button--lg"
            to="/docs/intro">
            Docusaurus Tutorial - 5min ⏱️
          </Link>
        </div> */}
      </div>
    </header>
  );
}

export default function Home() {
  const {siteConfig} = useDocusaurusContext();
  return (
    <Layout
      title={`Hello from ${siteConfig.title}`}
      description="Description will go into a meta tag in <head />">
      <HomepageHeader />
      <main>
        <HomepageFeatures />
      </main>
    </Layout>
  );
}
```

バナー下に表示されるFeatures(`src/components/HomepageFeatures/index.js`)を以下の様に変更した。
```javascript:index.js
import React from 'react';
import clsx from 'clsx';
import styles from './styles.module.css';

const FeatureList = [
  {
    title: '日記',
    Svg: require('@site/static/img/diary.svg').default,
    description: (
      <>
        日々の研究日記です
      </>
    ),
    to: '/blog',
  },
  {
    title: 'メモ帳',
    Svg: require('@site/static/img/diary.svg').default,
    description: (
      <>
        研究日記に関連したメモ帳です
      </>
    ),
    to: '/docs/top',
  },
];

function Feature({Svg, title, description,to}) {
  return (
    <a href={to}>
    <div className={clsx('col col--12')}>
      <div className="text--center">
        <Svg className={styles.featureSvg} role="img" />
      </div>
      <div className="text--center padding-horiz--md">
        <h3>{title}</h3>
        <p>{description}</p>
      </div>
    </div>
    </a>
  );
}

export default function HomepageFeatures() {
  return (
    <section className={styles.features}>
      <div className="container">
        <div className={styles.mycontainer}>
          {FeatureList.map((props, idx) => (
            <Feature key={idx} {...props} />
          ))}
        </div>
      </div>
    </section>
  );
}
```

```css:styles.modulus.css
.features {
  display: flex;
  align-items: center;
  padding: 2rem 0;
  width: 100%;
}

.featureSvg {
  height: 200px;
  width: 200px;
}

.mycontainer {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
```

ここで表示が崩れるため`<div className={clsx('col col--12')}>`に修正し、FeaturesListをコンテナで囲んだ。
これで、トップページのFeatureをクリックすると日記、個別記事のトップページに遷移する様にできた。
個別記事のトップページ`docs/top`は使い方を書いただけ。

あとは`npm run start`でサーバーが立ち上がる。お疲れ様でした。
完成物は本記事一番上の通り。

## 注意点
DocusaurusではMarkdownリンク`[text](markdown.md)`をhtmlリンクに変換してくれるのだが、DocsとBlogの間ではリンクがうまく生成されない。
対処として,markdownリンクを絶対リンクにし、`update.sh`で`.md`を除去しhtmlリンクにすることで解消した。
これがめんどくさい場合は Docs-only　modeで運用してもいいかもしれない。

# まとめ

とりあえず満足するものができたのでよしとする。また気になることがあれば追記予定。

[^1]:有料プラン（[Obsidian Publish](https://obsidian.md/publish)）で記事を公開することもできるのだが、無料で済ませたいのと、特定のプラットフォームにあまり依存したくないというのがあり、今回は断念した。