0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Qiita と Zenn の記事を1つの GitHub リポジトリで管理する

0
Posted at

この記事は Zenn にも同じ内容を投稿しています

やりたいこと

これから Qiita と Zenn の両方に記事を投稿していきたい。
最初からソースを GitHub で管理しておきたいけど、プラットフォームごとにリポジトリを分けるのは面倒なので、ひとつのリポジトリにまとめて git push で両方に自動公開できる構成にする。

結論:両方ともリポジトリのルートに置けば共存できる

Zenn の GitHub 連携は リポジトリのルートに articles/books/ がある前提 で、サブディレクトリ指定はできません。
機能リクエストは zenn-community#645 で議論されていますが、現時点では未実装です。

一方で、Qiita CLI と Zenn CLI が使うディレクトリ・設定ファイルは互いにぶつかりません。
ひとつの package.json に両方の CLI を入れて、両者をルートに同居させれば OK です。

Zenn Qiita
記事 articles/ public/
books/
設定 (なし) .qiita/, qiita.config.json
CLI zenn-cli @qiita/qiita-cli

完成形

qiita-zenn-content/
├── .github/workflows/publish.yml   # Qiita 自動投稿
├── articles/                        # Zenn 記事
├── books/                           # Zenn 本
├── public/                          # Qiita 記事
├── qiita.config.json
└── package.json

セットアップ手順

1. リポジトリ初期化と CLI のインストール

mkdir qiita-zenn-content && cd qiita-zenn-content
git init
npm init -y
npm install --save-dev zenn-cli @qiita/qiita-cli

2. Zenn / Qiita CLI を初期化

npx zenn init    # articles/ books/ README.md を生成
npx qiita init   # qiita.config.json と .github/workflows/publish.yml を生成

3. GitHub にプライベートリポジトリ作成 & push

gh repo create qiita-zenn-content --private --source=. --remote=origin
git add .
git commit -m "chore: initial setup"
git push -u origin main

4. プラットフォーム連携

これで main への push のたびに、Zenn は GitHub 連携で自動デプロイ、Qiita は GitHub Actions の publish.yml で自動投稿されます。

記事を書く

npx zenn new:article            # articles/<slug>.md が生成される
npx zenn preview                # http://localhost:8000

npx qiita new my-first-article  # public/my-first-article.md が生成される
npx qiita preview               # http://localhost:8888

フロントマターの published: true で公開、false で下書き保存になります(両方共通)。

同じ内容を Qiita と Zenn の両方に出したい場合

フロントマター形式が違うので、1ファイルで両方を兼ねることはできません
articles/<slug>.md(Zenn)と public/<slug>.md(Qiita)を別々に置いて、本文をコピーします。

Markdown の方言に注意する

似た機能でも構文が違うので、片方の独自記法を使うともう片方で崩れます。

機能 Zenn Qiita
メッセージ :::message / :::message alert :::note info / :::note warn
折りたたみ :::details タイトル <details><summary>
コードのファイル名 ```js:filename.js ```js:filename.js(同じ)
数式 $$ ... $$ $$ ... $$(同じ)

→ 両方に出す前提なら、標準 Markdown + ファイル名付きコードブロックに留める のが安全です。

画像はリポジトリの相対パスを使わない

Zenn は /images/... の絶対パス、Qiita は外部URLが必要で、両者で互換性のある参照方法がありません。
両方に出すなら、GitHub リポジトリの raw URL や Gyazo など 外部URLを ![](URL) で直接参照 するのが手っ取り早いです。

重複コンテンツの扱い

Zenn・Qiita とも canonical URL の指定はサポートされていないので、SEO 的に「正」を伝える手段は本文で示すしかありません。
慣例的には、後から出した方の冒頭にこう書いておきます。

> この記事は [Zenn にも同じ内容を投稿しています](https://zenn.dev/...).

運用フロー

  1. まず Zenn 用 (articles/<slug>.md) を書いて公開、URL を確定
  2. 本文をコピーして public/<slug>.md を作成、冒頭にクロスリンクを追加
  3. 以降の修正は両方のファイルに反映

頻繁に両方出すようになったら、フロントマター差し替えと方言変換をする小さなスクリプトを用意するとラクになります。

ハマりポイント

gh の OAuth トークンに workflow スコープが無い

qiita init が生成する .github/workflows/publish.yml を含めて push しようとすると、こんなエラーで弾かれます。

! [remote rejected] main -> main (refusing to allow an OAuth App to create or
update workflow `.github/workflows/publish.yml` without `workflow` scope)

gh auth refresh -s workflow でスコープを追加すれば push できます。

qiita init が生成する Workflow は Zenn 更新時にも動く

.github/workflows/publish.yml のトリガーはデフォルトで push: main のみで、パス指定がありません。
Zenn 記事だけ更新した push でも GitHub Actions が起動し、Actions の無料枠を無駄に消費します(差分がなければ Qiita 側に変更は出ませんが、ジョブは走る)。

paths フィルタを足して、Qiita 関連が変わった時だけ起動するようにしておきます。

.github/workflows/publish.yml
on:
  push:
    branches:
      - main
      - master
    paths:
      - 'public/**'
      - 'qiita.config.json'
      - '.github/workflows/publish.yml'
  workflow_dispatch:

Zenn のサブディレクトリ対応はまだ無い

「Qiita と Zenn を別々のサブディレクトリに分けたい」という直感的な構成は、Zenn が未対応なので諦めるしかありません。
ルートに同居させる方が結果的にシンプルです。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?