--- author: usbharu draft: false categories: - 技術 date: 2026-02-01T13:07:30+09:00 tags: - pnpm - npm - Tauri - Next.js - Biome - Storybook - Changesets - TypeScript - Renovate - Vitest keywords: - pnpm - npm - Tauri - Next.js - Biome - Storybook - Changesets - TypeScript - Renovate - Vitest title: プロジェクトを作るときに考えたいこと relpermalink: posts/2026-01-31/ url: posts/2026-01-31/ decription: プロジェクトを作るときに考えたいこと --- 何か新しいものを作ろうとしたときに、毎回調べている気がするのでまとめてみた。 最近はWeb(Next.js)+Desktop(Tauri+Vite+React)で作ることが多いので、なんだかんだ偏っているけどnpm使うなら使えるはず ## プロジェクトの構造を作る 基本的にpnpmを使う ```bash pnpm init --init-type module ``` モノレポでやる場合は`pnpm-workspace.yaml`を追加する [pnpm-workspace.yamlの構文](https://pnpm.io/ja/next/pnpm-workspace_yaml) 大体こんな感じのディレクトリ構造でやることが多い desktopとwebのフォルダは`pnpm create ほにゃらら`が作るので自分では作らない ```bash tree . . ├── apps │ ├── desktop │ └── web └── packages ├── ui └── utils 7 directories, 0 files ``` ### Next.js こんな感じで作成する ESLintではなくBiomeを使う ```bash create next-app@latest web ✔ Would you like to use the recommended Next.js defaults? › No, customize settings ✔ Would you like to use TypeScript? … No / Yes ✔ Which linter would you like to use? › Biome ✔ Would you like to use React Compiler? … No / Yes ✔ Would you like to use Tailwind CSS? … No / Yes ✔ Would you like your code inside a `src/` directory? … No / Yes ✔ Would you like to use App Router? (recommended) … No / Yes ✔ Would you like to customize the import alias (`@/*` by default)? … No / Yes ✔ What import alias would you like configured? … @/* ``` `pnpm-workspace.yaml`と`biome.json`が作成されるが、プロジェクトルートで作成するので必要に応じて削除する。 ### Tauri Rustがインストールされていることを確認する ```bash pnpm create tauri-app ✔ Project name · desktop ✔ Identifier · dev.usbharu.test ✔ Choose which language to use for your frontend · TypeScript / JavaScript - (pnpm, yarn, npm, deno, bun) ✔ Choose your package manager · pnpm ✔ Choose your UI template · React - (https://react.dev/) ✔ Choose your UI flavor · TypeScript ``` ### TypeScript ```bash pnpm add -D typescript npx tsc --init ``` npm scriptにtypecheckを追加しておく 正直いらないが… AIが利用できるコマンドを制限するときに楽 ```json "typecheck": "tsc --noEmit" ``` ### Vite(ライブラリモード) npmに公開するかはともかくライブラリを作るときはViteのライブラリモードを利用するといいらしい やったことない https://ja.vite.dev/guide/build#library-mode 単にモノレポの1パッケージとして作るだけなら不要 --- pnpmでモノレポ内のパッケージを追加する場合 ```bash pnpm add --workspace @test/ui ``` npmではやったことないけど、バージョンカタログの仕組みであるpnpm catalogで管理するというのもいいかも https://pnpm.io/ja/catalogs ## テストとか諸々 ### Biome Biome君VSCodeの拡張機能がちょっと残念だけど基本的に優秀なので使ってます https://biomejs.dev/ja/guides/getting-started/#%E8%A8%AD%E5%AE%9A ```bash pnpm add -w -D @biomejs/biome pnpm exec biome init ``` - JSONスキーマをURLからnode_modules内のファイルに変える - 自動的にインストールされているバージョンのスキーマを使うことができる - useIgnoreFile - *.d.tsファイルの除外 - tailwindcss対応 ```json { "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true }, "files": { "ignoreUnknown": true, "includes": ["**", "!**/*.d.ts"] }, "formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2 }, "linter": { "enabled": true, "rules": { "recommended": true, "a11y": { "noStaticElementInteractions": "off" }, "nursery": { "useSortedClasses": { "fix": "safe", "level": "error", "options": { "functions": ["twMerge", "twJoin", "tv", "cn"] } } } } }, "javascript": { "formatter": { "quoteStyle": "double" } }, "css": { "parser": { "cssModules": true, "allowWrongLineComments": true, "tailwindDirectives": true }, "formatter": { "enabled": false }, "linter": { "enabled": false } }, "assist": { "enabled": true, "actions": { "source": { "organizeImports": "on" } } } } ``` npm scriptにlintとlint:fixを追加しておく --unsafeオプションはご自由に 僕はつけます ```json "scripts": { "lint": "biome check", "lint:fix" : "biome check --write --unsafe" }, ``` ### Vitest テストにはVitestを使う 正直そんなに使ったことない ```bash pnpm add -D vitest ``` npm scriptにtestを追加する ```json "scripts": { "test": "vitest" }, ``` ### Storybook AIと色々やるときにあるとすごい便利 ReactとかのUIライブラリが依存関係に入っていないと自動作成に失敗するみたいなので注意 ```bash pnpm create storybook@latest ``` あとは画面の指示に従うだけ Tailwindcssの設定もしておく https://pystyle.info/react-vite-tailwind-storybook/ ### Storycap ビジュアルリグレッションテストを簡単に行えるよう、コンポーネントのスクショを自動で取れるようにしておく AIにUIコンポーネントを触らせるときにちょっとだけ安心できる Storycapとあるが正確には改良版のStorycap-testrunというもの ```bash pnpm add -D @storycap-testrun/browser ``` vitest.setup.tsに以下を追記 ```typescript:vitest.setup.ts import { page } from "vitest/browser"; import { screenshot } from "@storycap-testrun/browser"; afterEach(async (context) => { await screenshot(page, context); }); ``` vitest.config.tsのプラグインに以下を追記 ```typescript:vitest.config.ts import storycap from "@storycap-testrun/browser/vitest-plugin"; storycap({ output: { file: (context) => `${context.id}.png`, }, }), ``` `.gitignore`に`__screenshots__`と書いておくと良い ## Git/GitHubとCI/CD 基本的にGit Flowをちょっと省略したブランチ戦略を取る `release`ブランチを省略(リリース作業は自動化、それ以外はdevelopでするので) `hotfix`ブランチも省略 ### Gitの設定 やっていなければリポジトリの初期化 masterとmainに注意(n敗) ```bash git init . ``` `.gitignore`の設定 https://github.com/github/gitignore こういうところから持ってくる ### コミット前に自動修正 lefthookとbiomeを組み合わせる ```bash pnpm add -D -w lefthook ``` lefthook.yamlを作成する ```yaml:lefthook.yaml pre-commit: commands: check: glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}" run: npx @biomejs/biome check --write --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {staged_files} stage_fixed: true pre-push: commands: check: glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}" run: npx @biomejs/biome check --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {push_files} ``` 適用 ```bash pnpm lefthook install ``` ### GitHub とりあえずリポジトリを作る。masterとmainに注意 上でやった`.gitignore`はここでやってもいい Renovateとかを有効化しておく 設定していく - オートマージを許可 - デフォルトブランチをdevelopに - プルリクエストブランチの更新を常に提案する - ヘッドブランチを自動的に削除する - Dependabot Alertsを有効にする - ブランチプロテクションルールを作成する CIの構築をしてからの方が楽 - Masterブランチは直Push禁止 - CI全Passが必須 - バイパス禁止 - Developブランチは直Push許可 - CI全Passが必要だがバイパスを許可 - レビューが必要なら最少Approve数を設定 - チーム開発ならWebhookを設定 - Issue追加・PR追加・リリースあたりを通知してスレッド運用が良さげ 正直SlackのGitHub Appが一番いい - Discord https://mekurun.com/tips/discord-github/ ### Renovate 依存ライブラリのバージョン管理は自動化する - minorとpatchの自動マージを有効化 - platformAutomergeを有効化 - rebaseWhenをconflictedかneverに - lockFileMaintenanceをtrueに 正直いらんかも ```json:renovate.json { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["config:recommended"], "packageRules": [ { "matchUpdateTypes": ["minor", "patch"], "automerge": true } ], "platformAutomerge": true, "rebaseWhen": "conflicted", "lockFileMaintenance": { "enabled": true, "recreateWhen": "always", "rebaseStalePrs": true, "branchTopic": "lock-file-maintenance", "commitMessageAction": "Lock file maintenance", "commitMessageTopic": null, "commitMessageExtra": null, "schedule": ["before 4am on monday"], "groupName": null, "prBodyDefinitions": { "Change": "All locks refreshed" } } } ``` ### Vitest package.json内に存在している不要なtestスクリプトは削除しておく ルートのpackage.jsonに ```json "test:all": "pnpm -r --reporter-hide-prefix test" ``` を追記しておく -rオプションで子プロジェクトでも再起的に実行 --reporter-hide-prefixオプションで後述するテストレポートの邪魔を防げる 簡単にテストレポートを手に入れる手段としてGitHubのアノテーションを使う https://vitest.dev/guide/reporters.html#github-actions-reporter ### VRT(ビジュアルリグレッションテスト) AIにUIを触らせるならあったらすごく便利です `reg-viz/reg-actions@v3`を使います。 playwrightとのインストールが必要な割に実行する必要があるタイミングが多く、コストが重め PRのコメントに差分を投稿してくれるけど、PRのマージ先のコミットで必ずVRTが実行されている必要があるため、マージコミットにもVRTのアクションを実行する必要がある(この仕様にめちゃくちゃハマった) 残っている最新のスクショ結果ではなく、最新のコミットのスクショを探すという点に注意 簡単に書くのが凄く難しいので今動いているActionをそのまま書いておきます `@travel-scheduler/ui`の部分をUIコンポーネントのパッケージ名に変えると動くと思います。 ```yaml name: Visual Regression Test on: push: branches: [develop, main] pull_request: branches: [develop, main] permissions: contents: write actions: write pull-requests: write jobs: test: timeout-minutes: 10 runs-on: ubuntu-latest strategy: fail-fast: false matrix: shard: [1/3, 2/3, 3/3] steps: - uses: actions/checkout@v6 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v6 with: node-version: 22 cache: "pnpm" - name: Install dependencies run: pnpm install - name: Cache Playwright binaries uses: actions/cache@v5 id: playwright-cache with: path: ~/.cache/ms-playwright key: ${{ runner.os }}-playwright-${{ hashFiles('**/pnpm-lock.yaml') }} - name: Install Playwright Browsers if: steps.playwright-cache.outputs.cache-hit != 'true' run: pnpm -F @travel-scheduler/ui exec playwright install chromium - name: Install Playwright system dependencies run: pnpm -F @travel-scheduler/ui exec playwright install-deps chromium - name: Run storycap tests (shard ${{ matrix.shard }}) run: pnpm -F @travel-scheduler/ui exec vitest run --project=storybook --shard=${{ matrix.shard }} - name: Upload screenshots uses: actions/upload-artifact@v6 if: always() with: name: screenshots-${{ strategy.job-index }} path: packages/ui/__screenshots__ retention-days: 1 compare: needs: test if: always() timeout-minutes: 5 runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Download all screenshot artifacts uses: actions/download-artifact@v7 with: pattern: screenshots-* path: downloaded-screenshots - name: Merge screenshots run: | mkdir -p packages/ui/__screenshots__ for dir in downloaded-screenshots/screenshots-*; do if [ -d "$dir" ]; then cp -r "$dir"/* packages/ui/__screenshots__/ 2>/dev/null || true fi done echo "Merged screenshots:" ls -la packages/ui/__screenshots__/ - name: Upload merged screenshots uses: actions/upload-artifact@v6 with: name: storycap-report path: packages/ui/__screenshots__ retention-days: 30 - name: Run visual regression comparison uses: reg-viz/reg-actions@v3 with: github-token: "${{ secrets.GITHUB_TOKEN }}" image-directory-path: "./packages/ui/__screenshots__" ``` ### Changesetsによるバージョン管理 自分は調べながら初めて使ったけど、とても便利そう インストール ```bash pnpm add -wD @changesets/cli ``` 初期化 ```bash npx changesets init ``` 変更を追記(GitHub Appで自動化可能) ```bash npx changesets ``` 追記した変更をまとめてリリース(GitHub Actionで自動化可能) ```bash npx changesets version ``` 変更の追記の確認をしてくれるBot https://github.com/apps/changeset-bot masterにpushがあったら自動でリリース(changesets version)を行うAction ```yaml name: Release on: push: branches: - master concurrency: ${{ github.workflow }}-${{ github.ref }} jobs: release: name: Release permissions: pull-requests: write contents: write runs-on: ubuntu-latest steps: - name: Checkout Repo uses: actions/checkout@v3 - uses: pnpm/action-setup@v4 with: run_install: false - name: Setup Node.js 20 uses: actions/setup-node@v3 with: node-version: 22 - name: Install Dependencies run: pnpm install - name: Create Release Pull Request uses: changesets/action@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ``` ### npm versionによるバージョン管理 npmではやったことないけど、Gradleでは近い方法でバージョン管理をしていた 全パッケージが同じバージョン番号を持つプロジェクトやモノレポじゃないプロジェクトではGitに全部を合わせることができるので楽 https://qiita.com/minamo173/items/8b8b27bc6ecd17ad925e masterブランチにtagがpushされたときにfrom-gitで発動させる ### GitHub Copilotによるレビューを行う 自動でレビューさせるかはともかく設定する https://github.com/settings/copilot/features で有効化できる `.github/copilot-instructions.md`に日本語で頼む的な指示を書いておきましょう。 --- AI関連のことも書こうかと思ったけどだいぶ長い記事になったので一旦ここまで