Closed20

Turborepo & SvelteKit Starter の モノレポ構成を確認する

kazokmrkazokmr

こちらのページの手順に従ってプロジェクトを作成する
https://vercel.com/templates/svelte/turborepo-sveltekit-starter

作成したプロジェクトは IntelliJ IDEAから利用したいので、IdeaProjects ディレクトリに移動してから次のコマンドを実行する

pnpm dlx create-turbo@latest -e with-svelte

  • プロジェクト名(ディレクトリ名) -> デフォルトの ./my-turborepo のままにした
  • 利用する Package Manager -> pnpm workspace

あとはこんな感じでプロジェクトが作成される

kazokmrkazokmr

作成されたプロジェクトのうち、apps/docsapps/web は 異なるアプリだが 設定内容が同じなので apps/docs の方だけ見ていくことにする

kazokmrkazokmr

rootで確認しておきたいのは package.json eslintrc.cjs .prettierrc の3つかな
turborepo や workspace 自体は標準的な設定なので

kazokmrkazokmr

rootの package.json では、eslintprettier の実行に関係する依存関係をインストールしている
scripts を読むと prettierは rootから配下サブプロジェクト全体を一気に実行するみたいなので インストールが必要なのはわかるけど、lint は turboRepoを使っているから、rootじゃなくても良い気はするけど

./package.json
{
  "private": true,
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev",
    "lint": "turbo run lint",
    "format": "prettier --write ."
  },
  "devDependencies": {
    "eslint": "^8.56.0",
    "@repo/eslint-config": "workspace:*",
    "prettier": "^3.1.1",
    "prettier-plugin-svelte": "^3.1.2",
    "turbo": "latest"
  },
  "packageManager": "pnpm@8.9.0",
  "engines": {
    "node": ">=18"
  }
}
kazokmrkazokmr

packages/ui の package.json を 見ると eslint に関する 依存関係は 同じ packages/config-eslint だけを追加している。なのに scripts で、lintが実行できている。
また、packages/config-eslint の方も index.js で定義している lintの設定で使う依存関係しか追加していない

kazokmrkazokmr

apps/docs には eslint などの依存関係が追加されていたけど、削除して実行してみたところ lintが実行できたので、eslintrs.cjs で定義している依存関係だけがあれば良さそう

kazokmrkazokmr

同じ理由で、apps/docsprettier を依存関係から削除しても prettierは正常に動作できた。さらに .prettierrc に prettier-plugin-svelte が使われているけどこれも apps/docs から削除しても prettier は正常に動作した。 rootに prettier-plugin-svelte があれば大丈夫っぽいな

kazokmrkazokmr

root の .eslintrc.cjs は次の通り

./.eslintrc.cjs
module.exports = {
  root: true,
  // This tells ESLint to load the config from the package `eslint-config-custom`
  extends: ['custom']
};

プロジェクトの root であることを定義する root: true を指定している他、extends: ['custom'] で カスタム設定を参照しているが、この設定ファイルは実際は存在しないので、恐らく実際には利用されていない

kazokmrkazokmr

この .eslintrc.cjs を削除しても各プロジェクトの lint は正常に動作されることを確認した

kazokmrkazokmr

このプロジェクトのESLint設定は packages/config-eslint/index.js が請け負っている。rootではサブプロジェクトで eslint を実行するための依存関係をインストールしている

設定内容は rootを含む全サブプロジェクトを網羅する形の内容になっていた

./packages/index.js
module.exports = {
  root: true,
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:svelte/recommended',
    'prettier',
    'turbo'
  ],
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  parserOptions: {
    sourceType: 'module',
    ecmaVersion: 2020,
    extraFileExtensions: ['.svelte']
  },
  env: {
    browser: true,
    es2017: true,
    node: true
  },
  overrides: [
    {
      files: ['*.svelte'],
      parser: 'svelte-eslint-parser',
      parserOptions: {
        parser: '@typescript-eslint/parser'
      }
    }
  ]
};
kazokmrkazokmr

apps/*packages/* の各サブプロジェクトでは、次のように この eslintの設定を取り込み検証を実施している

./apps/docs/.eslintrc.cjs
module.exports = {
  extends: ['@repo/eslint-config/index.js']
};
kazokmrkazokmr

消しちゃったけど、rootの eslintrc.cjs extends: ['custom']custom は、eslint-config-** に相当するpackageらしい。
つまり、packages/eslint-config-custom というサブパッケージを用意すればそれを参照する模様。(今回は作っていないので結局 参照されるわけではない)
この辺は TurboRepoの仕組みっぽい
https://turbo.build/repo/docs/handbook/linting/eslint

kazokmrkazokmr

root の .prettierrc は以下の通り
prettier の 実行は root から行い、全サブプロジェクトのファイルに対して適用される

./.prettierrc
{
  "singleQuote": true,
  "trailingComma": "none",
  "printWidth": 100
}
kazokmrkazokmr

例えば apps/docs には 次のような .prettierrc があり このサブプロジェクト配下では rootの設定が上書きされる

rootでは useTabs は指定されていないので default の false になるのだが、apps/docs では タブが使われるようになっていた

./apps/docs/.prettierrc
{
	"useTabs": true,
	"singleQuote": true,
	"trailingComma": "none",
	"printWidth": 100,
	"plugins": ["prettier-plugin-svelte"],
	"pluginSearchDirs": ["."],
	"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}
kazokmrkazokmr

余談だけど、IntelliJ IDEAの prittierの機能 で、.svelte ファイルをフォーマットする scriptタグが不正な形に変換されるバグがあるんだけど、ここで rootにインストールした prettier パッケージを手動設定することで正しくフォーマット変換されるみたい。使いながら様子を見ないとなんとも言えないけど

https://github.com/sveltejs/prettier-plugin-svelte/issues/242#issuecomment-1942611707

kazokmrkazokmr

tsconfigも 管理しようと思ってたけど、サンプルだと apps/* にしか tsconfig.json がなくて、さらにSveltekitだから "extends": "./.svelte-kit/tsconfig.json", になってて あまり意味が無いので今回は行わない

なお、作るときはこの辺も参考にする

https://turbo.build/repo/docs/handbook/linting/typescript
https://valcker.medium.com/configuring-typescript-monorepo-with-eslint-prettier-and-webstorm-61a71f218104
https://valcker.medium.com/unpacking-turborepo-configure-typescript-monorepo-with-eslint-prettier-and-webstorm-960bf9e65e60

kazokmrkazokmr

ところで、packages/ui プロジェクトでは、エントリファイルとして index.ts があるんだけど、このプロジェクトには tsconfig.json もないし、typescript も 依存関係に追加していない

これってこのプロジェクト単体ではビルドもコンパイル(トランスパイル)もしない前提だからなんだろうな

./packages/ui/package.json
{
  "name": "@repo/ui",
  "version": "0.0.0",
  "type": "module",
  "module": "index.ts",
  "main": "index.ts",
  "exports": {
    ".": {
      "types": "./index.ts",
      "svelte": "./index.ts"
    }
  },
  "scripts": {
    "lint": "eslint ."
  },
  "devDependencies": {
    "@repo/eslint-config": "workspace:*",
    "svelte": "^4.2.8"
  }
}
kazokmrkazokmr

IntelliJ IDEA で、このプロジェクトに typescriptで書いたコードちゃんと認識してくれるんだな。
Settings > Languages & Frameworks > Typescript で パッケージを指定しているからなんだろうな。
今は、apps/docs にインストールした パッケージを見ているけど rootとかベースになるプロジェクトを指してあげたほうが良さそう

kazokmrkazokmr

IDE (IntelliJ)でも参照するためにrootにこんな感じで typescriptの設定を行うと良いかな? CompilerOptionsは、Viteのビルドでトランスパイルを行うことを想定した設定にはした方が良さそう

  • packages/config-ts みたいな tsconfig.json 管理プロジェクトを置く
    • 他のプロジェクトもここの設定ファイルを参照する
  • Workspaceのroot に typescript パッケージ をインストールする
  • root に tsconfig.json を追加し、config-ts パッケージの 設定ファイルを継承する
  • IDEの Typescriptパスを root の typescript パッケージにする
  • 必要に応じて、root の tsconfig.json に paths も指定する
    • "必要に応じて"とは、IDEが内部パッケージの参照エラーを出す場合という意味
  • references (Project Referemce) は定義しなくて良いと考えてる
    • apps/* では個別に tsconfig.json, tsconfig.node.json を管理して vite でビルドするため
    • root にあるのは あくまでも IDE用の位置付けとし、アプリのビルド時のトランスパイルとは切り分ける
kazokmrkazokmr

今回の調査と直接関係ないんだけど、rootにインストールしたパッケージは サブプロジェクトでも利用できるようになるんだな
例えば、svelte とか vite, typescript なんかも rootにインストールしておけば、個々の package.json で定義しなくても使えるようになる
パッケージのバージョンを揃える必要がある時なんかはこれで良い気がする

このスクラップは2ヶ月前にクローズされました