🙏

Zenn本のチャプターファイルの作成方法が変わりました

commits3 min read 8

2020/10/10〜、GitHubリポジトリで本のチャプターを管理する方法が変わりました。新しい管理方法はこのページでも説明しますが、CLIで本を管理するで確認することもできます。

Web上(zenn.dev上)で本を作成・編集している場合には影響はありません。

これまでの方法と問題点

GitHubリポジトリでコンテンツを管理している場合、本のチャプターファイルは以下のように作成する必要がありました。

books
└── my-awesome-book
    ├── 1.md # チャプター1
    ├── 2.md # チャプター2
    ├── 3.md # チャプター3
    └── 4.md # チャプター4

この方法だと、以下のような問題がありました。

  • 後から「チャプター2と3の間に新しいチャプターを差し込みたくなった」ような場合、1つずつファイル名を書き直さなければならない
  • チャプター番号がずれるとビューアー上でのリンクが維持されない
  • ファイル名からチャプターの内容を推測できない

新しい方法

問題を解消するため、以下のような構成へ変更を行いました。

books
└── my-awesome-book
    ├── config.yaml # ここでチャプターの並び順を指定
    ├── about.md # チャプター
    ├── conclusion.md # チャプター
    ├── create-book.md # チャプター
    └── update-book.md # チャプター

👆 各チャプターのファイル名には好きな文字列(a-z0-9、ハイフン-、アンダースコア_の1〜50字の組み合わせ)を使い、チャプターの並び順はconfig.yamlで指定します。

config.yamlでチャプターの並び順を指定

title: "本のタイトル"
summary: "本の紹介文"
topics: ["markdown", "zenn"]
published: true
price: 0
# 👇 ここでチャプターの並び順を指定する
chapters:
  - about
  - create-book
  - update-book
  - conclusion

👆 デプロイされた本ではchaptersに配列で指定された順番にチャプターが並ぶことになります。この例の場合「aboutcreate-bookupdate-bookconclusion」の順に並びます。なお、config.yamlのchaptersに指定されなかったチャプターはzenn.devに同期されません。

現時点ではチャプターを入れ子にする(子チャプターを作る)ことはできません

チャプターのファイル名はURLの一部に

チャプターのファイル名はURLの一部となります。例えばabout.mdのチャプターのURLは/ユーザー名/本のスラッグ/viewer/aboutとなります。

🚩 configで指定されなかったチャプターは削除されることに注意

すでにaboutcreate-bookupdate-bookconclusionという4つのチャプターを持つ本がzenn.devに同期されているとします。この後、config.yamlにて、以下のように指定したうえでデプロイした場合…

chapters:
  - about
  - conclusion

指定されなかった既存のチャプター(create-bookupdate-book)はzenn.dev上からは削除されることにご注意ください。

すでに同期済みの本の対応について

すでにzenn.devに同期されている本については、以前の方法を継続して使用することができます。
ただし、以前の方法は非推奨とされ、しばらく期間が経った後に廃止される可能性があります。
(その場合、本の内容を修正するためには、新しい方法への移行を行う必要があります)

以前の方法から移行する方法

手順0: CLIを最新版にする

プロジェクトのルートディレクトリで下記のコマンドを実行してください。

$ npm install zenn-cli@latest

現在のディレクトリ内のファイルが以下のようになっているとします。

books
└── my-awesome-book
    ├── 1.md
    ├── 2.md
    ├── 3.md
    └── 4.md

手順1:ファイル名の書き換え

まず、各チャプターのファイル名を「a-z0-9、ハイフン-、アンダースコア_の1〜50字の組み合わせ」に変更します。この文字列はURLに使われるため、チャプターの内容を表すものにすることをおすすめします。

books
└── my-awesome-book
    ├── introduction.md # チャプター1
    ├── getting-started.md # チャプター2
    ├── development.md # チャプター3
    └── deployment.md # チャプター4

手順2:config.yamlにチャプターの並び順を指定

そのうえで、config.yamlにチャプターの並び順を指定します。

...省略...
# 👇 下記を追加
chapters:
  - introduction
  - getting-started
  - development
  - deployment

手順3:デプロイ

この状態でリポジトリへプッシュすれば移行完了です。(各チャプターのURLは変更されます)


ご迷惑をおかけして申し訳ありませんが、ご協力よろしくお願いします。

GitHubで編集を提案

Discussion

私の環境だけかもしれないですが、

npm install zenn-cli@latest

を実行するとエラーが発生して正常にアップデートできないですね。

エラー内容については文字数制限で入力できないので2回に分けます。

npm WARN deprecated chokidar@2.1.8: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.
npm WARN deprecated mkdirp@0.5.3: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)
npm WARN deprecated fsevents@1.2.13: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.   
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated

> markdown-it-prism@2.1.3 prepack C:\Users\midoliy\AppData\Roaming\npm-cache\_cacache\tmp\git-clone-e0625dd9
> npm-run-all build:*

'npm-run-all' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。
npm WARN Local package.json exists, but node_modules missing, did you mean to install?
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.1.2 (node_modules\chokidar\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules\next\node_modules\chokidar\node_modules\fsevents):       
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN notsup Unsupported engine for watchpack-chokidar2@2.0.0: wanted: {"node":"<8.10.0"} (current: {"node":"14.5.0","npm":"6.14.5"})
npm WARN notsup Not compatible with your version of node/npm: watchpack-chokidar2@2.0.0
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules\watchpack-chokidar2\node_modules\chokidar\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

npm ERR! premature close

すみません、npm packageのリリースでミスしてしまったようです。
修正済みなのでお手数ですが再度npm install zenn-cli@latestを実行していただければと思います。

正常にアップデートできました。
ありがとうございます。

仕様意図確認に近いのですが「configで指定されなかったチャプターは削除される」を、「configで指定しないことで意図的に非公開(Ex.下書き)に制御できる」と解釈してもよいでしょうか?
"削除" という不可逆的な単語を使われているので気になった次第です。

はい、意図的にzenn.devへの同期対象外にすることができます。
(リポジトリで内容を復元できるためzenn.devからは削除して問題ないはず…という考えでそのような仕様にしています)

回答ありがとうございました。
(Editorial提案ですが、"削除" ではなく "非公開" や "除外" 表記の方が混乱が少ないかもです。最初はデータがどこからから恒久的に削除されるのかと思ってしまったので...)

分かりづらくてすみません。
config.yamlに指定されなかったチャプターはzenn.dev上からは完全に削除されるため、Zennというサービスのドキュメント上の表現としては「削除」が適切だと考えています。
(ユーザーがGitHubでリポジトリも消すと、データは恒久的に失われることになります)

ユーザー頼みになるため、「非公開」と書くとzenn.devに残っていると誤解を招く可能性がありそうだなと。良い表現があれば良いのですが、今のところ思いつかず…。

ログインするとコメントできます