qiita-cliを使った記事執筆環境をdevcontainerで作成した


`qiita-cli`が8月に正式リリースされてました。

https://qiita.com/Qiita/items/563a6ea111709a03fbea

複数端末で環境共有できる＋VScodeで記事を執筆できる環境構築を目指してdevcontainerを作ってみました。

参考にさせていただいたのは、[qiita content boilerplate](https://github.com/waicode/qiita-content-boilerplate)[^1]です。


## 1. 動作環境

以下の環境で動作しています。環境依存部分は少ないのでVS CodeとDockerが動けば使えるはず。

- MacOS Sonoma 14.0
- VSCode version 1.83
- Docker Desktop 4.24.2

## 2. フォルダ／ファイル構成

作成したファイル・フォルダは以下の通り

### 2.1. フォルダ構成

```bash:folder structure
.
├── .devcontainer
│   └── devcontainer.json
├── .vscode
│   ├── tasks.json
│   └── setting.json
├── .gitignore
├── .github
│   └── workflows
│       └── publish.yml
├── credentials.json
├── docker
│   └── Dockerfile
├── docker-compose.yml
├── node_modules
├── package.json
├── public
└── qiita.config.json

```

### 2.2. `.gitignore` と qiita設定関係ファイル（ `credentials.json`、`qiita.config.json`

:::note warn
釈迦に説法とは思いますが。全ての準備をするまえに `.gitignore` を作成する事を強くおすすめします。特にgithub連携を使う際には注意が必要です。
:::
アクセストークンを `credentials.json` に記載して `qiita.config.json` とともにDockerイメージにコピーしておくことで初期化とログインの処理を割愛できます。

```txt:.gitignore
credentials.json
node_modules
.remote
*.log
.DS_Store
```

```json:credentials.json
{
  "default": "qiita",
  "credentials": [
    {
      "name": "qiita",
      "accessToken": "YOUR CREDENTIAL"
    }
  ]
}
```

```json:qiita.config.json
{
    "includePrivate": false,
    "host": "localhost",
    "port": 8888
  }
```

### 2.3. `devcontainer.json` の構成

vscodeの機能拡張を記載しておくとdevcontainer上で利用可能になる。

事例として入れてある、[qiita markdown preview](https://marketplace.visualstudio.com/items?itemName=ryokat3.vscode-qiita-markdown-preview) はインストールお勧め。[^2]
VS Codeのプレビュー画面で記事のイメージを確認しながらの執筆が可能になる。

その他自分が設定しているのは以下のプラグイン

#### Markdown関連

個人的お勧め順

- :star:[qiita markdown preview](https://marketplace.visualstudio.com/items?itemName=ryokat3.vscode-qiita-markdown-preview): Preview出力をQiitaフォーマットに。
- [Markdown All in One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one): ヘッダーへの項目番号追加、markdownテーブルの補助などmarkdown関連の便利機能追加
- [vscode-textlint](https://marketplace.visualstudio.com/items?itemName=taichi.vscode-textlint): テキストリンター
- [markdownlint](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint): Markdown構文のリンター
- [markdown footnote insert command](https://marketplace.visualstudio.com/items?itemName=houkanshan.vscode-markdown-footnote):脚注（フットノート）入力補助
- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker): スペルチェッカー
- [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode): フォーマッター
- [:emojisense:](https://marketplace.visualstudio.com/items?itemName=bierner.emojisense): Emoji入力補助 🤗
- [markdown-emoji](https://marketplace.visualstudio.com/items?itemName=bierner.markdown-emoji): Previewで絵文字表示
- [markdown footnote preview](https://marketplace.visualstudio.com/items?itemName=bierner.markdown-footnotes): Previewで脚注表示

##### ここからはQiita記事作成だと出番が少ないかも

- [Copy file name](https://marketplace.visualstudio.com/items?itemName=nemesv.copy-file-name): ファイル名コピー補助
- [Path Intellisense](https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense): パス入力補助
- [Insert Date String](https://marketplace.visualstudio.com/items?itemName=jsynowiec.vscode-insertdatestring): フォーマット指定しての日付入力補助

#### Git関連

- [Git Graph](https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph)
- [gitignore](https://marketplace.visualstudio.com/items?itemName=codezombiech.gitignore)
- [Github Actions](https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-github-actions): Github連携＋Actions使っている場合モニタリングに便利

GitHub連携+branchでの記事管理などするなら入れておいた方が良いかも。
- [GitHub Pull Requests and Issues](https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-pull-request-github)

#### その他

- [Japanese Language Pack for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja): メニューなどの日本語化
- [Output Colorizer](https://marketplace.visualstudio.com/items?itemName=IBM.output-colorizer): 出力パネルメッセージのカラー化
- [Todo Tree](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.todo-tree): TODOの便利機能追加


```json:devcontainer.json
{
  "dockerComposeFile": ["../docker-compose.yml", "docker-compose.yml"],
  "service": "qiita",
  "workspaceFolder": "/workspace",
  "customizations": {
    "vscode": {
      "extensions": [
        // 利用したいvscodeのエクステンションをこちらに記載しておく。
        // qiita markdown preview はインストールお勧め。
        // https://marketplace.visualstudio.com/items?itemName=ryokat3.vscode-qiita-markdown-preview
        "ryokat3.vscode-qiita-markdown-preview"
      ]
    }
  }
}
```

### 2.4. `Dockerfile` `docker-compose.yml` のファイル構成

先例を参考に、軽量を目指して `node:lts-slim` をbase imageに採用。

```docker:Dockerfile
FROM node:lts-slim

WORKDIR /workspace

COPY credentials.json ~/.config/qiita-cli/credentials.json

RUN apt-get update && apt-get install -y git yarn && yarn

EXPOSE 8888
```

`.devcontainer/docker-compose.yml`


```yml:devcontainer/docker-compose.yml
version: "3.9"

services:
  qiita:
    command: /bin/sh -c "while sleep 1000; do :; done"
```

`docker-compose.yml`
```yml:docker-compose.yml
version: "3.9"

services:
  qiita:
    container_name: qiita
    build:
      context: .
      dockerfile: docker/Dockerfile
    volumes:
      - .:/workspace:delegated
      - node_modules:/workspace/node_modules
    ports:
      - 8888:8888
    restart: always

volumes:
  node_modules:

```

### 2.5. package.json

後述の `tasks.json` だけでなく、こちらの `scripts` にもnpxコマンドを仕込んでおくと便利かもしれない。 VS CodeのNPM SCRIPTSパネルからコマンド実行ができる。

:kissing_closed_eyes: chu☆



```json: package.json
{
    "name": "qiita-content",
    "version": "1.0.0",
    "private": true,
    "description": "Qiita content",
    "scripts": {
      "login": "npx qiita login",
      "preview" : "npx qiita preview"
    },
    "devDependencies": {
        "@qiita/qiita-cli": "^1.3.0"
      }
}
```


### 2.6. `.vscode`フォルダ内ファイル

`cspell.json`, `tasks.json`, `setting.json`の3ファイルを作成して.vscodeフォルダに保存しておく。

`cspell.json` にはあらかじめ登録したい単語を記載しておいてもいい。

```json:cspell.json
{
    "words": [
        "devcontainer",
        "qiita"
    ]
}
```

`tasks.json` にnpx qiita commandを登録しておくとVS codeのコマンドパレット-タスクから新規ファイル作成、プレビューを呼び出せる。

```json:tasks.json
{
    "version": "2.0.0",
    "tasks": [
      {
        "label": "Create New Qiita Article",
        "type": "shell",
        "command": "npx qiita new ${input:fileName}",
        "problemMatcher": [],
        "presentation": {
          "reveal": "always"
        },
        "group": {
          "kind": "build",
          "isDefault": true
        }
      },
      {
        "label": "Preview",
        "type": "shell",
        "command": "npx qiita preview",
        "problemMatcher": [],
        "presentation": {
          "reveal": "always"
        },
        "group": {
          "kind": "build",
          "isDefault": true
        }
      }
    ],
    "inputs": [
      {
        "id": "fileName",
        "type": "promptString",
        "description": "Enter the base name for the article file:",
        "default": "new-article"
      }
    ]
  }

```
`settings.json` はお好みの設定で。自分の設定は下記。

```json:settings.json
{
// Markdown word wrap & suggestions
"[markdown]": {
    "editor.wordWrap": "on",
    "editor.quickSuggestions": {
    "other": true,
    "comments": true,
    "strings": true
    },
    "editor.snippetSuggestions": "top"
},

// `published_at` format
"insertDateString.format": "YYYY-MM-DD hh:mm",

// Markdownlint
"markdownlint.config": {
    "line-length": false, // MD013: Disable the maximum number of characters per sentence
    "no-duplicate-heading": false, // MD024: Allow duplicate heading text
    "single-h1": false, // MD025: Allow multiple top-level headings in the same document
    "no-trailing-punctuation": false, // MD026: Allow headings with . ,;:
    "no-inline-html": false, // MD033: Allow HTML description
    "no-bare-urls": false // MD034: Allow URLs to be written as is
},
}

```

### 2.7. Github用ファイル

Github同期設定を利用する場合は`/workspace/.github/workflows/publish.yml`を作成しておく必要あり。（`npx qiita init`実行でも作成される）

```yml:.github/workflows/publish.yml
name: Publish articles

on:
  push:
    branches:
      - main
      - master
  workflow_dispatch:

permissions:
  contents: write

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: false

jobs:
  publish_articles:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: increments/qiita-cli/actions/publish@v1
        with:
          qiita-token: ${{ secrets.QIITA_TOKEN }}
          root: "."

```

## 3. 最後に

Node.js環境を汚さず環境が構築できる点も良いかもしれません。
（自分はNode.jsをよく理解できていないのですが。。。何かにつけてエラー経験しているので。。。）

おかしな所ご指摘あればお願いします。

今後、Qiita Markdown記法用のsnippet等も追加検討していこうかと思います。


[^1]: こちらは[Qiita sync](https://github.com/ryokat3/qiita-sync)を使ったテンプレート

[^2]: [【Qiita拡張記法プラグイン】Qiita記事をVSCodeで書くなら今すぐインストール！](https://qiita.com/ryokat3/items/fe61d9234be2e147cb7f)