【100h検証】ブログ構築に10回以上失敗したプログラマが ブログリリースまでの道のりを記録した 100時間のすべて

こんにちは。この記事は [個人開発 Advent Calendar 2021](https://qiita.com/advent-calendar/2021/personal-project) の23日目です✨

過去に何度かフルスクラッチで個人用の技術ブログを制作しているのですが、しっくりこなかったり、飽きたり、構成が悪くてサーバーの維持費が高かったり・・・
色々あって**ブログの構築に10回以上失敗**しましたwww (〃´∪｀〃)ゞ

こんなに失敗してしまうのは逆に貴重な経験だなーと思ったので、次こそは本気出す思いで100時間ガチで制作してみました。


## 1) 企画のルールとゴール

100時間を使って、ガチでブログを作ってみます。
ただし、100時間で自分が求めるブログが完成するとは思っていないので、今回のゴール設定は『完成したら』では無く、『アドベントカレンダー公開日をタイムリミットとして、出来たところまでをさらけ出す』にします。

作業時間には**コーディング中の時間だけでなく、技術選定やサーバー構築、この記事を書いている時間や、現状の分析など、この企画に関するすべてを計測**します。

なお、この記事は**企画の進行に合わせて執筆**しています。現在の日付は 2021/11/08 で、**アドベントカレンダー公開まであと 44 日**です。ざっくり、一日あたり 2.3 時間で 100 時間になりますね～


## 2) 状況分析 (なぜ今まで失敗したのか？)

まずは、なぜ失敗し続けたのか。状況を分析してみることにしました。
視野を広く、客観的に状況を把握することは重要だと偉い人が言っていました。

以下は『過去に失敗したブログ構築』の一覧です。

|   時期   |               サーバー               |              フロント               |                             分析                             |
| :------: | :----------------------------------: | :---------------------------------: | :----------------------------------------------------------: |
| ①2019/03 | `CloudRun` `CloudSQL` `CloudStorage` |            `nuxt2(SSR)`             | 記事エディタページも含めて作成、1年ぐらい運用していた。CloudSQL の料金を見誤ってやめた。 |
| ②2020/09 |             `NetlifyCMS`             |            `nuxt2(SSG)`             |      (未公開) Nuxt-Tailwind-NetlifyCMS boilerplate      |
| ③2020/10 |             `NetlifyCMS`             |     `nuxt2(SSG)` `nuxt/content`     | 公開した。テンプレートプロジェクトを活用。フォルダ構成をカスタマイズできず、画像の保存位置が気に入らなかった。テンプレートプロジェクトが JavaScript で TypeScript ではなかったのでカスタマイズが面倒になってしまった。 |
| ④2020/12 |             `NetlifyCMS`             |     `nuxt2(SSG)` `nuxt/content`     | (未公開) TypeScript でやりたくてフルスクラッチで作っていたが、途中で満足してしまい終了。 |
| ⑤2021/01 |             `NetlifyCMS`             |              `gatsby`               |                   (未公開) netlify-cms-react-gatsby                   |
| ⑥2021/02 |              `microCMS`              |            `nuxt2(SSG)`             |                           (未公開)                                   |
| ⑦2021/03 |            `parse-server`            |            `nuxt2(SSR)`             |                            (未公開)                                  |
| ⑧2021/08 |        `PHPレンタルサーバー` `GRAV`        |            －                  | 色々カスタムして公開した。管理画面が遅すぎて記事を更新する気が起きない。nuxt 使えず、PHP でのカスタマイズがつらい |
| ⑨2021/09 |               `strapi`               |            `nuxt2(SSR)`             |  (未公開)                                                            |
| ⑩2021/10 |               `strapi`               | `nuxt2(SSG)` `nuxt/composition-api` |  (未公開)                                                            |

私の性格上、新しいものや、やったことない技術に取り合えず手を付けてしまう癖があり、勉強や実験している間に満足したり、**別のことに興味が移ってしまって完成まで至らない**ことが多いように思いました。

かと言って、納得いかない技術や興味のない技術で作ると、**公開後にカスタマイズが億劫になって更新を止めてしまう**パターンもあったので、これはどうしたものかといった具合です。

悩んだ末、長期的なモチベーションを考慮して `興味のある技術は使う`。途中で飽きても開発を諦めないように『アドベントカレンダーで公開する』という期限を設けて、仕事のように開発を進めてみることにしました。

## 3) 目標と課題

### ～ 伝わりやすい言葉で目標を表すなら？ ～

『気軽にサッと書けて、サクッとカスタマイズしやすいブログ』

### ～ 求めるブログ像を明文化 ～

1. **自分で読み返す用に操作性の良い技術ブログが欲しい**
    色々な分野に手を出す癖があるので、やったことは技術ブログとしてまとめたい。
    最近のリファレンスドキュメントに多い、『左にページナビゲーション、中央に記事、右側が目次』の構成が技術ブログとしても読みやすそう。
    ![2021-12-23_00h50_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67192/ef35b6ca-1611-28bc-a409-3eb8aa11c92b.png)


2. **気持ちよく、サクサク書けるブログ**
    書くのにハードルが高かったり、書きにくいとそもそも書かない。

3. **おしゃれなデザインにしたい**
    せっかく作るならわくわくする感じのおしゃれさで。

4. **Markdown を使うことで汎用性と、資産としての将来性を確保したい**
    どうせ数年したら飽きてブログを作り直すので、記事だけでも Markdown + FrontMatter で汎用性を持たせ資産として使いまわせるようにする。

5. **最新の技術を使ってみたい**
    ⇨ OK やったれ。自分にはわくわくも必要だ。今は Nuxt3 がアツい。まだベータ版で SSG すらできんけどな！

> **⚠ご注意**
> ベータ版などの最新技術を使うことにはリスクもありますので、お仕事で使うのは控えたほうが良いかもしれません


## 4) 仕様

ガチでやるといいつつ、ここだけ手を抜いてしまいました。ごめんなさいとしか言えないです。

(個人開発であっても、仕様書を作っておけば制作中の思い付きや脱線を防ぐ意味でも有効活用できます。また頭の整理にもなるので書いた方が間違いないのですが、何度も作っているので仕様がほぼ固まっていること、100時間しかないことから省略してしまいました～)

必要なページとコンポーネントの一覧といった最低限のみとなります。(2021-12-23 状況を反映)
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67192/80e84ced-6825-b4e7-83d1-d689ca9e290f.png)


## 5) 制作過程

状況分析と課題の洗い出し、目標の設定まで終わり、仕様もほぼ固まりました。ここから具体的に制作するのでプログラマーのターンです。

### 5-1) フロントエンドの選定

今年の10月にベータ版がリリースされたばかりの Nuxt3 を使います。今は `Next.js(React)` や `Nuxt2(Vue2)`、`Flutter` や `C#` などを触るよりも、`TypeScript + Nuxt3(Vue3)` が一番楽しいです。

ただし、何度も言っていますが Nuxt3 はまだベータ版なので、SSG (静的サイトジェネレーション) などに対応していません。なので、今回はしぶしぶ SSR (サーバーサイドレンダリング) で実装して、今後 SSG がサポートされたら修正しようと思います。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67192/e73a7617-71df-3607-b64d-f1ea17263f73.png)
> ↑ Nuxt3(β) の対応状況。https://v3.nuxtjs.org/getting-started/introduction/ より引用

なお、Nuxt3(β) は、ほぼ毎日のように更新されていて、『さっきまで動いていたのに、パッケージのバージョンを上げたら Nuxt 側のバグで動かなくなった～😝』なんてことも普通にあります。
なので、その辺も含めて楽しめるのであれば(許されるのであれば)、Nuxt3 は猛烈におすすめです。


### 5-2) サーバーの選定

今回、Nuxt3 の SSR (サーバーサイドレンダリング) を使う関係で、Node.js 環境が必要になります。過去に使用したことがある `Google App Engine` や `Google Cloud Run` でもよかったのですが、別件で[『はにゃーんボタン』を作った](https://qiita.com/alclimb/items/7cd50f716cecef753ec3) 際に Conoha VPS 環境に Dokku という、heroku のオンプレ版システムの様なものを構築していたので、このサーバーに今回のブログシステムをデプロイすることにしました。

Dokku は内部的に Docker を使用しているので、１つのサーバーに複数の Web サービスを構築することができて、しかもサンドボックスなので他の Web サービス環境に影響を与えず、heroku のようにゼロダウンタイムデプロイ(サービスを止めずにデプロイすること)ができ、Redis や Postgres などのデータベースを構築したり、Let's Encrypt SSL の自動更新ができたりと、様々なことをオンプレ環境で実現できます。**個人開発に、おあつらえ向きな環境だと思います。**


### 5-3) サーバーにデプロイ

何はともあれ、まずはサーバーにデプロイ。
『ローカルの開発環境では動作するけど、サーバーの本番環境では動かない！』『しかも、すでにプログラム規模が大きくなりすぎていて、本番環境のどの部分でエラーが発生しているのかわからない』なんて、笑い話のようでよくある話なので、最初に Hello World レベルのプログラムを作ったら、本番環境にデプロイして**最小限の構成で動作することを確認することを強くお勧めします。**

まずは、VPS サーバーなり、オンプレ環境なりで Ubuntu サーバーを用意して、SSH などで以下のコマンドを実行して Dokku 環境を構築します。

```shell:サーバー側ターミナル
# 
# Dokkuホスト上での共通設定
#  - Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-65-generic x86_64)
#  - Dokku v0.26.6
# 

# Dokkuインストール
$ wget https://raw.githubusercontent.com/dokku/dokku/v0.26.6/bootstrap.sh;
$ sudo DOKKU_TAG=v0.26.6 bash bootstrap.sh

# Dokkuのデプロイ先ブランチを変更する (master => main)
$ dokku git:set --global deploy-branch main

# Dokkuプラグインを追加
$ sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git

# 通知先メールアドレスの設定 (※アドレスはサンプル用※)
$ dokku config:set --global DOKKU_LETSENCRYPT_EMAIL=user@example.com

# 証明書を自動更新する設定
$ dokku letsencrypt:cron-job --add
```

続いて開発環境側でデプロイするプログラムを用意します。
適当に Nuxt3 のサンプルを用意して、以下の Dockerfile をプロジェクトのルートに追加します。

```dockerfile:./Dockerfile
# 
# サーバー用のビルド
# 

# (1) 環境を用意
FROM node:16-slim AS SERVER_BUILD

# (2) ビルドディレクトリを作成する
WORKDIR /build

# (3) 依存関係のライブラリ設定ファイルをコピー
COPY package*.json ./

# (4) 依存関係のライブラリをインストール
RUN npm install

# (5) アプリケーションのソースをコピー
COPY . ./

# (6) アプリケーションをビルド
RUN npm run build

# 
# ランタイム用
#  .output/
#  node_modules/
#  package.json
#  package-lock.json
# 

# (7) 環境を用意
FROM node:16-slim

# (8) アプリケーションディレクトリを作成する
WORKDIR /app

# (9) 依存関係のライブラリ設定ファイルをコピー
COPY package*.json ./

# (10) ランタイムに必要な依存パッケージのみインストールし、その後npmのcacheファイルを削除する
RUN npm install --production --cache /tmp/empty-cache && rm -rf /tmp/empty-cache

# (11) サーバービルド用中間イメージから必要なファイルのみコピー
COPY --from=SERVER_BUILD /build/.output ./.output/

ENV NUXT_PORT=5000
ENV NUXT_HOST=0.0.0.0

# アプリケーションを実行
CMD [ "npm", "start" ]
```

続いて、開発環境側からプログラムをデプロイします。ここでは Windows を使用していますが、基本的に macOS や Linux 環境でも問題ありません。

```shell:開発環境側ターミナル
# 
# ◇ sshキー関係の設定
#  - RLoginなどのソフトでsshのキーを生成
#  - 生成した秘密鍵をクライアント側の「C:\Users\<ユーザー名>\.ssh\id_rsa」に保存
#  - 生成した公開鍵(id_rsa.pub)をリモート側の「/home/dokku/.ssh/authorized_keys」に書き込んでおく
# 

# デプロイの準備 (gitのpush先にDokkuホストを追加) ※ドメイン名はサンプル用※
> git remote add dokku dokku@example.com:app001

# デプロイ (Dokkuにpushする)
> git push dokku main:main
```

最後に、再度サーバー側で以下のコマンドを実行してアプリケーションを登録します。
(なお、プログラムをデプロイする前に以下のアプリケーション登録作業をすると、80/443番ポートでアクセスできなくて dooku proxy の設定変更が必要になります)

```shell:サーバー側ターミナル
# アプリケーションを作成
$ dokku apps:create app001

# アプリケーションとドメインを連携 (※ドメイン名はサンプル用※)
$ dokku domains:set app001 example.com

# LetsEncryptを有効化
$ dokku letsencrypt:enable app001
```

設定したドメインで、アクセスできれば成功です。次回以降のデプロイは `git push dokku main:main` するだけです。

**あとは、ごりごりブログ(サービス)を作っていくだけ！！**


## 6) そして100時間経過

そして、現在この記事を執筆している時点で 102時間13分 経過しました。100時間やり切った～。
ブログの方は土台ができて最低限動作するようになりました！完成まではまだまだ時間がかかりそうです。

しかし、いつもなら１か月も続ければ他のことに興味がわいて投げやりになっていそうですが、今回はまだまだ続けれそうです。
この100時間挑戦する企画、結構面白かったです。ご興味があればぜひ試してみてはいかがでしょうか！

最後に、こちらが制作中のブログです。まだまだ未完成ですわ～😝

https://atr9.com/