📝

Zennの執筆環境をdevcontainerで構築する

2024/01/20に公開

はじめに

Zennを初めて見たので、記事の公開練習も兼ねて、Zennの執筆環境をdevcontainerで構築してみました。

環境

OS
  • Windows 11 Home
    • WSL2セットアップ済み
使用ソフト

最終的な成果物

最終的な成果物を先に載せておきます。

使用する場合は、まずZennのリポジトリをcloneし、下記のフォルダ構成で各ファイルを配置してください。
次にVS CodeでZennのリポジトリを開き、devcontainerで開けば実行環境が整います。

フォルダ構成
zenn-content
├── .devcontainer
│   ├── devcontainer.json
│   ├── compose-dev.yml
│   └── Dockerfile
└── .vscode
    └── settings.json
devcontainer.json
{
  "name": "zenn-devcontainer",
  "service": "zenn-devcontainer",
  "workspaceFolder": "/workspace",
  "dockerComposeFile": "compose-dev.yml",
  "remoteUser": "node",
  "customizations": {
    "vscode": {
      "extensions": [
        "mhutchie.git-graph",
        "yzhang.markdown-all-in-one"
      ]
    }
  }
}
compose-dev.yml
version: "3.9"
services:
  zenn-devcontainer:
    container_name: zenn-dev
    build:
      context: .
      dockerfile: Dockerfile
    tty: true
    volumes:
      - ../:/workspace
Dockerfile
FROM node:18

# Install basic development tools
RUN apt update && apt install -y less man-db sudo

# Ensure default `node` user has access to `sudo`
ARG USERNAME=node
RUN echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
    && chmod 0440 /etc/sudoers.d/$USERNAME

# Set `DEVCONTAINER` environment variable to help with orientation
ENV DEVCONTAINER=true
settings.json
{
  "markdown.copyFiles.destination": {
    "articles/*.md": "/images/articles/${documentBaseName}/",
    "books/*.md": "/images/books/${documentBaseName}/"
  }
}

あとは公式の記事を参考に以下のコマンドを実行すれば、Zennの執筆環境が整います。

$ npm init --yes # プロジェクトをデフォルト設定で初期化
$ npm install zenn-cli # zenn-cliを導入
$ npx zenn init # zenn-cliの初期設定

具体的な手順

1. リポジトリとZennの連携

公式の記事を参考に、GithubにてZenn用のリポジトリを作成し、Zennと連携します。

https://zenn.dev/zenn/articles/connect-to-github

2. devcontainerの設定

Zennのリポジトリをcloneし、VS Codeで開きます。
左下の「>< WSL:...」をクリックし、「開発コンテナー構成ファイルを追加...」を選択します。
どのような開発環境を構築するかを選択する画面が表示されるので、「Node.js」を選択します。

すると、.devcontainerフォルダが作成され、devcontainer.jsonDockerfileが作成されます。
ほぼほぼデフォルトのままで問題ありませんが、以下2点の変更を加えます。

  1. devcontainer.jsonnameを任意の名前に変更します。
  2. devcontainer.jsonのにmountsオプションを追加し、コンテナ内で編集したファイルをホスト側に反映させるようにします。
devcontainer.json
{
-  "name": "Untitled Node.js project",
+  "name": "zenn-devcontainer",
  "build": {
    "dockerfile": "Dockerfile"
  },
  "remoteUser": "node",
+  "mounts": [
+    "source=../,target=/home/node/zenn-sample,type=bind"
+  ]
}

3. devcontainerの起動

VS Codeの左下の「>< WSL:...」をクリックし、「コンテナーで再度開く」を選択します。
VS Codeが再起動し、左下の「>< WSL:...」が「>< 開発コンテナー:<nameに指定した任意の名前>」に変わっていれば成功です。

4. 追加の便利系設定

実はこの時点で最低限の環境は整っていますが、もう少し便利に使うために、以下の設定を追加します。

4-1. 拡張機能の導入

devcontainer内で使用する拡張機能をdevcontainer.jsonに追記します。
今回は以下の2つを追加しました。

  • Markdown All in One
    • Markdownの執筆を助けてくれる拡張機能です。
  • Git Graph
    • Gitのブランチを可視化してくれる拡張機能です。
devcontainer.json
+  "customizations": {
+    "vscode": {
+      "extensions": [
+        "mhutchie.git-graph",
+        "yzhang.markdown-all-in-one"
+      ]
+    }
+  }

4-2. 画像の貼り付け

Zennでは記事内に画像を貼り付ける場合は、/imagesに保存し、![](画像の絶対パス)という形式で記述する必要があるようです。

https://zenn.dev/zenn/articles/deploy-github-images

効率化のために、コピペしたら画像を自動で指定のフォルダに保存し、markdownの記述も自動で行ってくれると便利です。
これにはVS Codeの標準機能を使うやり方と、拡張機能のPaste Imageを使うやり方がありますが、調べてみるとどちらにしても問題があるようです。

VS Codeの標準機能
  • 設定は可能だが、画像のパスが相対パスになってしまうため、そのままだと記事を公開する際に画像が表示されない。

https://zenn.dev/temasaguru/scraps/1c234724218d4e

Paste Image
  • 拡張機能がリモート開発に対応していないため、devcontainer内で使用できない。

https://github.com/mushanshitiancai/vscode-paste-image/issues/56

とりあえずの対応

VS Codeの標準機能を使うやり方で、画像のパスを絶対パスに都度直すことにしました。
上記の記事を参考に、settings.jsonに以下の設定を追加し、画像が/images以下に保存されるようにしました。

settings.json
{
  "markdown.copyFiles.destination": {
    "articles/*.md": "/images/articles/${documentBaseName}/",
    "books/*.md": "/images/books/${documentBaseName}/"
  }
}

5. もやもやの解消(composeの導入)

ここまででZennの執筆環境は整いましたが、ふとdocker desktopを見ると、起動しているdevcontainerの名前がランダムな名称になっていることに気づきました。(しかもリビルドするたびに名前が変わる)

特に悪影響があるわけではないのですが、なんとなく気持ち悪いので、何とかできないか色々調べてみました。
しかし有効な解決策は見つからず、結局composeを導入することで、devcontainerの名前を任意のものに変更することにしました。

composeを導入するために、devcontainer.jsonを以下のように書き換えます。

devcontainer.json
{
  "name": "zenn-devcontainer",
-  "build": {
-    "dockerfile": "Dockerfile"
-  },
+  "service": "zenn-devcontainer",
+  "workspaceFolder": "/workspace",
+  "dockerComposeFile": "compose-dev.yml",
  "remoteUser": "node",
-  "mounts": [
-    "source=${localWorkspaceFolder},target=/workspace,type=bind"
-  ],
  "customizations": {
    "vscode": {
      "extensions": [
        "mhutchie.git-graph",
        "yzhang.markdown-all-in-one"
      ]
    }
  }
}

compose-dev.ymlを作成します。

compose-dev.yml
version: "3.9"
services:
  zenn-devcontainer:
    container_name: zenn-dev
    build:
      context: .
      dockerfile: Dockerfile
    tty: true
    volumes:
      - ../:/workspace

これらの設定を行ったら、VS Codeの左下の「>< 開発コンテナー:...」をクリックし、「コンテナーのリビルド」を選択します。

再度docker desktopを見ると、compose-dev.ymlで指定したservice名の中に、container_nameで指定した名前のコンテナが作成されていることが確認できます。
当然ですが、これらはリビルドしても名前が変わることはありません。

6. Zennの初期設定

最後にZennの初期設定を行います。
公式の記事を参考に、以下のコマンドを実行します。

$ npm init --yes # プロジェクトをデフォルト設定で初期化
$ npm install zenn-cli # zenn-cliを導入
$ npx zenn init # zenn-cliの初期設定

これでZennの執筆環境が整いました。


おわりに

サクッと環境構築して記事公開しようと思っていたのですが、結局色々調べているうちに時間がかかってしまいました。。。

ひとまず執筆環境は整いましたので、これから色々記事を書いていきたいと思います!

Discussion