Skip to content

Place slides under public/ and tell them apart from articles by marp: true - #423

Merged
tomoasleep merged 3 commits into
mainfrom
move-slide-directory
Sep 28, 2026
Merged

tomoasleep merged 3 commits into
mainfrom
move-slide-directory

Conversation

@tomoasleep

@tomoasleep tomoasleep commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

What

スライドの置き場所をルート直下の slides/ から public/ 配下に移し、public/ 内の記事とスライドを frontmatter の内容で判別するようにする。

  • frontmatter に marp: true があるファイルをスライド、それ以外を記事として扱う。スライドは public/ 配下のどこに置いてもよい
  • qiita new --slide のデフォルト作成先と、qiita pull でローカルに無いスライドを書き出す先を public/slides/ にする。basename を明示すればそのパスに作成する(例: qiita new --slide talks/deck → public/talks/deck.md)
  • .remote ミラーは記事・スライドとも public/.remote/ を共有する
  • qiita new --slide で作るファイルの title は、basename からディレクトリを除いた部分にする(slides/newSlide001 ではなく newSlide001)

スライドの作成・pull・publish・preview は、これまでどおり experimentalSlideFeatureEnabled が有効なときだけ動く。一方、marp: true のファイルを記事の一覧・publish 対象から外す判定はフラグに関係なく常に効く。フラグを無効にしたあとに、スライドのファイルが記事として投稿されないようにするため。

動作確認

yarn lint / yarn build / yarn test(24 suites, 222 tests)がいずれも成功。

追加・更新した主なテスト:

  • src/lib/file-system-repo.test.ts: public/ 直下・public/slides/ 配下のスライドが記事の一覧・basename 指定・id 指定のいずれにも出ないこと / 既存のスライドと同じ basename で qiita new してもスライドを上書きしないこと
  • src/lib/slide-file-system-repo.test.ts: public/ 直下・配下のスライドが一覧に出て、記事は出ないこと / qiita new --slide のデフォルト作成先が public/slides/newSlide001.md になること / pull でローカルに無いスライドが public/slides/<uuid>.md に書き出されること / slides/ 以外の場所にあるスライドがその場所のまま更新されること / marp の無い markdown を取得したときに marp: true が付くこと / 既存の記事と同じ basename で qiita new --slide しても記事を上書きしないこと
  • src/lib/get-slide-file-system-repo.test.ts: ルートが public/ になり public/slides/ が作られること
  • src/commands/preview.test.ts: 監視対象が public/ の 1 つだけになること

ビルド済み CLI(node dist/main.js)で、experimental フラグを有効にした空のディレクトリに対して以下を確認した。

操作 結果
qiita new --slide public/slides/newSlide001.md が marp: true 付きで作成される
qiita new --slide talks/deck(public/talks/ 作成済み) public/talks/deck.md が作成される
qiita new article public/article.md が作成される

qiita publish / pull / preview は Qiita API との通信が必要なため、上記の自動テストでの確認のみ。

How

判別はディレクトリではなく内容で行う

FileSystemRepo#getItemData / SlideFileSystemRepo#getSlideData がファイルを読んだ直後に isSlideMarkdown(marp: true の厳密比較)で振り分ける。一覧・basename 指定・id 指定の読み込みはすべてここを通るので、記事の一覧にスライドが、スライドの一覧に記事が混ざらない。

一覧取得(readdir)の段階では振り分けない。ファイル名だけでは判別できず、そこで全ファイルを読むと basename 解決のたびに読み込みが増えるため。

Qiita から取得したスライドには marp: true を必ず付ける

Qiita 上で書かれたスライドの markdown に marp: true が無いと、pull したファイルが次回から記事として扱われ、qiita publish --all で記事として投稿されてしまう。SlideFileContent.fromSlide でミラー・ローカルとも marp: true を付与する。既に marp キーがある場合はキーの位置を保つので、ミラーとの差分判定には影響しない。

新規作成時の存在チェックはファイル名で行う

記事とスライドが同じ public/ を共有するので、qiita new / qiita new --slide で指定した basename のファイルが反対の種別で既にあることがある。createItem / createSlide の存在チェックを、種別で絞り込む loadItemByBasename / loadSlideByBasename ではなく、public/ 配下のファイル名一覧で行う。これで既存のファイルを空のテンプレートで上書きせず、'<basename>.md' is already exist のエラーになる。

preview / publish の後始末

  • qiita preview の監視対象は public/ だけになる(スライドのルートも public/ なので重複して登録しない)
  • qiita publish <basename> の「記事とスライドの両方に同じ basename がある」エラーは、1 ファイルがどちらか一方にしか判別されないため到達しなくなったので削除した

GitHub Actions の actions/publish/action.yml は git add ${{ inputs.root }}/public/* で public/ 配下を再帰的にステージするので変更していない。

Why

public/ と slides/ を並列に置くと、何を意味するディレクトリなのか分かりにくく、ユーザーがファイルを置く場所も別々に縛られる。スライドを public/ の中に入れ、場所ではなく内容で判別すれば、public/slides/ はデフォルトの置き場所に留まり、記事とスライドを好きなディレクトリ構成で管理できる。

移行について

実験的機能のため、既存の slides/ 配下のファイルは自動で移行しない。投稿済みのスライドは次回の qiita pull で public/slides/ に取得し直される。未投稿のローカルのみのスライドは public/ 配下へ手動で移動する必要がある。

Refs

既存の挙動(この PR のスコープ外)

qiita new --slide talks/deck は、public/talks/ が存在しないと書き込みに失敗する。記事の qiita new talks/article も同じ挙動なので、この PR では揃えたままにしている。

🤖 Generated by Claude Code

🤖 Generated with Claude Code

tomoasleep and others added 2 commits September 25, 2026 16:36
… true

Slides now live in the same public/ directory as articles, with public/slides/
as the default location for new and pulled slides. A file is treated as a
slide when its frontmatter has `marp: true`, so it can be placed anywhere
under public/. Both repositories share public/.remote/ as the mirror.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The slide repository now shares public/ with the article repository, so
preview watches it once, and one file can no longer be both an article and a
slide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tomoasleep

This comment was marked as outdated.

Items and slides now share public/, so checking the target basename
through loadItemByBasename / loadSlideByBasename missed files of the
other kind and overwrote them with an empty template.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tomoasleep

Copy link
Copy Markdown
Member Author

AI Review の指摘に対応しました(a4b9c05)。

  • createItem / createSlide の存在チェックを、種別で絞り込む loadItemByBasename / loadSlideByBasename から public/ 配下のファイル名一覧での判定に変更しました。反対の種別のファイルがある basename を指定すると、上書きせずに '<basename>.md' is already exist のエラーになります
  • 両方向の回帰テストを file-system-repo.test.ts / slide-file-system-repo.test.ts に追加しました
  • 確認事項として挙がっていた「marp: true による記事の除外はフラグに関係なく常に効く」点は、フラグを切ったあとにスライドが記事として投稿されない安全側の挙動として実装を維持し、PR description の記述を実装に合わせて修正しました

🤖 Generated by Claude Code

@tomoasleep tomoasleep left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI Review 🤖

問題はありません。

その他確認した項目

何を確認したか

  • PR: #423
  • diff: main...move-slide-directory
  • CI state: success(6/6: check_test_execution_conditions, lint, test x3, build)
  • 既存レビュー: 行コメント 0 件(unresolved なし)、general comment 1 件(tomoasleep 本人、commit a4b9c05 で対応済み)

見たが問題にしなかった観点

  • general comment にある createItem / createSlide の存在チェック変更は commit a4b9c05 で実装済みと確認した。file-system-repo.ts / slide-file-system-repo.ts の該当箇所は、種別で絞り込む loadItemByBasename / loadSlideByBasename ではなく public/ 配下のファイル名一覧(getItemFilenames / getSlideFilenames)と照合するよう変わっており、反対の種別の basename を指定すると '<basename>.md' is already exist に到達することをテストとコードの両方で確認した。
  • 同コメントにある「marp: true による記事の除外はフラグに関係なく常に効く」という記述も、FileSystemRepo#getItemData の isSlideMarkdown チェックが experimentalSlideFeatureEnabled を見ずに常に適用される実装と一致しており、PR description もこの挙動に合わせて修正済みであることを確認した。
  • publish.ts から「記事とスライドの両方に同じ basename がある」エラー分岐を削除した点も、両 repo が同一ファイルを marp: true で排他的に判定するようになったため到達し得なくなった分岐であり、対応するテストも削除されていて妥当と判断した。
  • SlideFileContent.fromSlide は Qiita 側の markdown に marp キーが無くてもオブジェクトスプレッドで marp: true を付与する実装になっており、ミラーとの差分判定を崩すような roundtrip の不整合はない。
  • .remote ミラーが記事・スライドで共有ディレクトリになった点も、getItemData / getSlideData がそれぞれ isSlideMarkdown で読み分けるため実害はない。

tomoasleep に確認するべき点

ディレクトリ付き basename で作成したとき、記事だけ title にディレクトリ名が残る

qiita new --slide slides/newSlide001 は title を path.basename した newSlide001 にする一方、qiita new talks/article は basename をそのまま title に使うため talks/article が title に残る。PR description にはスライド側でこの変更をした理由は書かれているが、記事側を揃えなかった理由には触れていない。意図した非対称であれば問題ないが、単なる対応漏れであれば記事側も揃える余地がある。記事でディレクトリ付き basename を使うケース自体が今回のスコープの中心ではないため、ブロッキングではない。

補足

CI は全 6 チェックが成功しており、conflict もない(mergeable: MERGEABLE)。ただし本 PR にはまだ人間の承認レビューが付いておらず(reviewDecision: REVIEW_REQUIRED、reviewRequests は空)、このリポジトリの branch protection は承認レビューを必須としている。


head: a4b9c05

@tomoasleep
tomoasleep requested a review from ohakutsu September 25, 2026 09:35
@tomoasleep

Copy link
Copy Markdown
Member Author

#421 の上の stacked PR にしてほしい

@ohakutsu ohakutsu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@tomoasleep
tomoasleep merged commit bd2a831 into main Sep 28, 2026
6 checks passed
@tomoasleep
tomoasleep deleted the move-slide-directory branch September 28, 2026 07:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants