メインコンテンツへスキップ

プロジェクトを作るときに考えたいこと

·962 文字·5 分
技術 Pnpm Npm Tauri Next.js Biome Storybook Changesets TypeScript Renovate Vitest

何か新しいものを作ろうとしたときに、毎回調べている気がするのでまとめてみた。

最近はWeb(Next.js)+Desktop(Tauri+Vite+React)で作ることが多いので、なんだかんだ偏っているけどnpm使うなら使えるはず

プロジェクトの構造を作る
#

基本的にpnpmを使う

pnpm init --init-type module

モノレポでやる場合はpnpm-workspace.yamlを追加する

pnpm-workspace.yamlの構文

大体こんな感じのディレクトリ構造でやることが多い desktopとwebのフォルダはpnpm create ほにゃららが作るので自分では作らない

tree .
.
├── apps
│   ├── desktop
│   └── web
└── packages
    ├── ui
    └── utils

7 directories, 0 files

Next.js
#

こんな感じで作成する ESLintではなくBiomeを使う

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.yamlbiome.jsonが作成されるが、プロジェクトルートで作成するので必要に応じて削除する。

Tauri
#

Rustがインストールされていることを確認する

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
#

pnpm add -D typescript
npx tsc --init

npm scriptにtypecheckを追加しておく 正直いらないが… AIが利用できるコマンドを制限するときに楽

"typecheck": "tsc --noEmit"

Vite(ライブラリモード)
#

npmに公開するかはともかくライブラリを作るときはViteのライブラリモードを利用するといいらしい やったことない

https://ja.vite.dev/guide/build#library-mode

単にモノレポの1パッケージとして作るだけなら不要


pnpmでモノレポ内のパッケージを追加する場合

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

pnpm add -w -D @biomejs/biome
pnpm exec biome init
  • JSONスキーマをURLからnode_modules内のファイルに変える
    • 自動的にインストールされているバージョンのスキーマを使うことができる
  • useIgnoreFile
  • *.d.tsファイルの除外
  • tailwindcss対応
{
  "$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オプションはご自由に 僕はつけます

"scripts": {
    "lint": "biome check",
    "lint:fix" : "biome check --write --unsafe"
  },

Vitest
#

テストにはVitestを使う 正直そんなに使ったことない

pnpm add -D vitest

npm scriptにtestを追加する

  "scripts": {
    "test": "vitest"
  },

Storybook
#

AIと色々やるときにあるとすごい便利

ReactとかのUIライブラリが依存関係に入っていないと自動作成に失敗するみたいなので注意

pnpm create storybook@latest

あとは画面の指示に従うだけ

Tailwindcssの設定もしておく

https://pystyle.info/react-vite-tailwind-storybook/

Storycap
#

ビジュアルリグレッションテストを簡単に行えるよう、コンポーネントのスクショを自動で取れるようにしておく

AIにUIコンポーネントを触らせるときにちょっとだけ安心できる

Storycapとあるが正確には改良版のStorycap-testrunというもの

pnpm add -D @storycap-testrun/browser

vitest.setup.tsに以下を追記

import { page } from "vitest/browser";
import { screenshot } from "@storycap-testrun/browser";


afterEach(async (context) => {
	await screenshot(page, context);
});

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敗)

git init .

.gitignoreの設定

https://github.com/github/gitignore

こういうところから持ってくる

コミット前に自動修正
#

lefthookとbiomeを組み合わせる

pnpm add -D -w lefthook

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}

適用

pnpm lefthook install

GitHub
#

とりあえずリポジトリを作る。masterとmainに注意 上でやった.gitignoreはここでやってもいい Renovateとかを有効化しておく

設定していく

  • オートマージを許可
  • デフォルトブランチをdevelopに
  • プルリクエストブランチの更新を常に提案する
  • ヘッドブランチを自動的に削除する
  • Dependabot Alertsを有効にする
  • ブランチプロテクションルールを作成する CIの構築をしてからの方が楽
    • Masterブランチは直Push禁止
      • CI全Passが必須
      • バイパス禁止
    • Developブランチは直Push許可
      • CI全Passが必要だがバイパスを許可
    • レビューが必要なら最少Approve数を設定
  • チーム開発ならWebhookを設定

Renovate
#

依存ライブラリのバージョン管理は自動化する

  • minorとpatchの自動マージを有効化
  • platformAutomergeを有効化
  • rebaseWhenをconflictedかneverに
  • lockFileMaintenanceをtrueに 正直いらんかも
{
  "$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に

"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コンポーネントのパッケージ名に変えると動くと思います。

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によるバージョン管理
#

自分は調べながら初めて使ったけど、とても便利そう

インストール

pnpm add -wD @changesets/cli

初期化

npx changesets init

変更を追記(GitHub Appで自動化可能)

npx changesets

追記した変更をまとめてリリース(GitHub Actionで自動化可能)

npx changesets version

変更の追記の確認をしてくれるBot

https://github.com/apps/changeset-bot

masterにpushがあったら自動でリリース(changesets version)を行うAction

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関連のことも書こうかと思ったけどだいぶ長い記事になったので一旦ここまで