paint-brush
Vite、Cloudflare、Remix、PNPM、Turborepo を使用してモノレポを作成する方法 (ビルド手順なし)@josejaviasilis
1,365 測定値
1,365 測定値

Vite、Cloudflare、Remix、PNPM、Turborepo を使用してモノレポを作成する方法 (ビルド手順なし)

Jose Javi Asilis19m2024/08/28
Read on Terminal Reader

長すぎる; 読むには

これにより、ビルドステップなしでRemixのVite Cloduflareデプロイメント用のモノレポが作成されます。これにより、複数のターゲットに拡張できます。
featured image - Vite、Cloudflare、Remix、PNPM、Turborepo を使用してモノレポを作成する方法 (ビルド手順なし)
Jose Javi Asilis HackerNoon profile picture
0-item




導入

最小限の構成で、Remix を Vite および Cloudflare Workers-Pages とともに使用する方法が必要でした。


次のような他のリポジトリも確認しました:


しかし、いくつかの制限がありました。

  1. リポジトリにさらに多くの構成ファイルを追加したくなかったので、事前にビルドしたくありませんでした。


  2. Cloudflare Workers/Pages はターゲットが異なります。Postgres などのパッケージは、Remix にインポートされるとノードの依存関係が壊れるため、tsup でターゲットにすることが難しくなりました。


  3. また、異なるターゲット(Remix-Cloudflare、Node/Bun)を消費する方法も必要でした。


それでも、これを可能にする道を開いてくれた彼らに感謝したいと思います。


下部の落とし穴のセクションを必ず読んでください。

ソーシャルで私をフォローしてください!

私は、本番環境での 1% のエラーを検出するための自動テスト プラットフォームを公開で構築しています。


私は以下の進捗状況を共有しています:


X/Twitter @javiasilis

LinkedIn @javiasilis

GitHub リポジトリ

完全な実装については、ここからアクセスできます。

ステップバイステップ

要件

  1. ノードJS
  2. PNPM
  3. Docker (オプション - ローカル データベースの例)


ここでは新しいモノリポジトリについて説明しますが、既存のモノリポジトリをモノリポジトリに変換することも完全に有効です。


また、モノリポジトリに関する知識があることも前提としています。


注記:

  • 「ルート」はモノリポジトリの開始パスを指します。このプロジェクトの場合、 libsおよびpackagesディレクトリの外側になります。

Turborepoをインストールする

Turborepo はパッケージ マネージャーのワークスペース上で動作し、プロジェクトのスクリプトと出力を管理します (出力をキャッシュすることもできます)。これまでのところ、Rush (試したことがなく、好きではありません) 以外で機能する唯一のモノ リポジトリ ツールです。


NX には Remix の Vite サポートがありません (この記事の執筆時点 - 2024 年 8 月 28 日)。


https://turbo.build/

 pnpm dlx create-turbo@latest

1. PNPMワークスペースを構成する

依存関係を管理するには、PNPM のワークスペース機能を使用します。


Monorepo ディレクトリにpnpm-workspace.yamlを作成します。


その中に以下を追加します:

 packages: - "apps/*" - "libs/*"


これにより、すべてのリポジトリがappslibs内に存在することが pnpm に通知されます。libs またはpackages (他の場所で見たように) libs使用は重要ではないことに注意してください。

2. プロジェクトのルートに空の package.json を作成します。

 pnpm init
 { "name": "@repo/main", "version": "1.0.0", "scripts": {}, "keywords": [], "author": "", "license": "ISC" }


name:@repo/mainこれは、これがアプリケーションのメイン エントリであることを示しています。特定の規則に従ったり、 @プレフィックスを使用したりする必要はありません。これは、ローカル/リモート パッケージと区別したり、組織にグループ化しやすくしたりするために使用されます。

3. プロジェクトのルートにturbo.jsonファイルを作成します。

 { "$schema": "https://turbo.build/schema.json", "tasks": { "build": {}, "dev": { "cache": false, "persistent": true }, "start": { "dependsOn": ["^build"], "persistent": true }, "preview": { "cache": false, "persistent": true }, "db:migrate": {} } }


turbo.json ファイルは、turbo リポジトリにコマンドの解釈方法を指示します。tasks キー内にあるものはすべてtasks all package.json にあるものと一致します。


4 つのコマンドを定義していることに注意してください。これらは、各リポジトリの package.json のスクリプト セクションにあるコマンドと一致します。ただし、すべての package.json でこれらのコマンドを実装する必要はありません。


例: devコマンドはturbo devによってトリガーされ、package.json 内でdevが見つかったすべてのパッケージを実行します。turbo に含めない場合は実行されません。

4. プロジェクトのルートにappsフォルダを作成する

mkdir apps

5. appsフォルダにリミックスアプリを作成する(または既存のアプリを移動する)

 npx create-remix --template edmundhung/remix-worker-template


Install any dependencies with npmように求められたら、いいえと答えます。


  • これが本来の姿だ

6. package.json のname@repo/my-remix-cloudflare-app (またはあなたの名前) に変更します。

 { - "name": "my-remix-cloudflare-app", + "name": "@repo/my-remix-cloudflare-app", "version": "1.0.0", "keywords": [], "author": "", "license": "ISC" }

7. Dependencies と devDependencies をapps/<app>/package.jsonからルートのpackage.jsonにコピーします。

例えば:

<ルート>/package.json

 { "name": "@repo/main", "version": "1.0.0", "scripts": {}, "keywords": [], "author": "", "license": "ISC", "dependencies": { "@markdoc/markdoc": "^0.4.0", "@remix-run/cloudflare": "^2.8.1", "@remix-run/cloudflare-pages": "^2.8.1", "@remix-run/react": "^2.8.1", "isbot": "^3.6.5", "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { "@cloudflare/workers-types": "^4.20240222.0", "@octokit/types": "^12.6.0", "@playwright/test": "^1.42.1", "@remix-run/dev": "^2.8.1", "@remix-run/eslint-config": "^2.8.1", "@tailwindcss/typography": "^0.5.10", "@types/react": "^18.2.64", "@types/react-dom": "^18.2.21", "autoprefixer": "^10.4.18", "concurrently": "^8.2.2", "cross-env": "^7.0.3", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "husky": "^9.0.11", "lint-staged": "^15.2.2", "msw": "^2.2.3", "postcss": "^8.4.35", "prettier": "^3.2.5", "prettier-plugin-tailwindcss": "^0.5.12", "rimraf": "^5.0.5", "tailwindcss": "^3.4.1", "typescript": "^5.4.2", "vite": "^5.1.5", "vite-tsconfig-paths": "^4.3.1", "wrangler": "^3.32.0" } }


8. ルート レベルで Turbo を devDependency として追加します (これにより、Remix のすべてのパッケージがインストールされます)。

turbo が package.json の devDependencies 内にあることを確認します。リストされていない場合は、次のコマンドを実行します。

 pnpm add turbo -D -w


-wフラグは、pnpm にワークスペースのルートにインストールするように指示します。

9. ルートpackage.jsonに次のエントリを追加します。

  • scriptsdevコマンドを追加する

  • オプションにpackageManagerを追加する


{ "name": "@repo/main", "version": "1.0.0", "scripts": { "dev": "turbo dev" }, "keywords": [], "author": "", "license": "ISC", "packageManager": "[email protected]", "dependencies": { // omitted for brevity }, "devDependencies": { // omitted for brevity } }

10. pnpm devを実行してすべてが機能していることを確認する

pnpm dev

11. プロジェクトのルートに Libs フォルダを作成します。config、db、utils を追加します。

 mkdir -p libs/config libs/db libs/utils

12. 各パッケージにsrc/index.tsを追加します。

 touch libs/config/src/index.ts libs/db/src/index.ts libs/utils/src/index.ts
  • すべてのパッケージをエクスポートするには、index.ts ファイルが使用されます。
  • すべてをコンパクトにするために、フォルダーをエントリ ポイントとして使用します。
  • これは慣例であり、これに従わないこともできます。

13. 空の package.json を作成し、 libs/config/package.jsonファイルに次の内容を追加します。

 { "name": "@repo/config", "version": "1.0.0", "type": "module", "exports": { ".": { "import": "./src/index.ts", "default": "./src/index.ts" } } }

14. libs/db/package.jsonに対しても同じ操作を行います。

 { "name": "@repo/db", "version": "1.0.0", "exports": { ".": { "import": "./src/index.ts", "default": "./src/index.ts" } } }

15. そしてlibs/utils/package.json :

 { "name": "@repo/utils", "version": "1.0.0", "exports": { ".": { "import": "./src/index.ts", "default": "./src/index.ts" } } }


  • 「exports」フィールドを指定します。これにより、他のリポジトリにパッケージをインポートする場所が通知されます。
  • 「name」フィールドを指定します。これは、パッケージをインストールし、他のリポジトリに参照するために使用されます。

16. (DB) - DrizzleとPostgresを追加する

注:

  • 私は ORM を軽蔑し始めています。私は 10 年以上かけて 6 つの異なる ORM を学習しましたが、その知識は移転できません。

  • 新しいテクノロジーが登場すると問題が発生します。Prisma は、そのままでは Cloudflare ワーカーをサポートしていません。

  • LLM を使用すると、複雑な SQL クエリをこれまで以上に簡単に記述できます。

  • SQL の学習は普遍的な言語であり、変更される可能性は低いです。


 pnpm add drizzle-orm drizle-kit --filter=@repo/db


ワークスペース レベルで Postgres をインストールします。 「落とし穴」セクションを参照してください

 pnma add postgres -w


注:

  • --filter=@repo/dbフラグは、pnpm にパッケージを db リポジトリに追加するように指示します。

17. ワークスペースリポジトリにdotenvを追加する

pnpm add dotenv -w

注記

  • -wフラグはpnpmにルートのpackage.jsonにインストールするように指示します。

18. Config プロジェクトをすべてのプロジェクトに追加します。

 pnpm add @repo/config -r --filter=!@repo/config

注記:

  • -rフラグは、pnpm にパッケージをすべてのリポジトリに追加するように指示します。
  • --filter=!フラグは、pnpm に設定リポジトリを除外するように指示します。
  • パッケージ名の前の!に注意してください

19. (オプション) 上記のコマンドが機能しない場合は、.npmrc を使用してください。

pnpm がリポジトリからパッケージをプルしている場合は、プロジェクトのルートに.npmrcファイルを作成できます。


.npmrc

 link-workspace-packages= true prefer-workspace-packages=true


  • これにより、pnpm は最初にワークスペース パッケージを使用するようになります。
  • .nprmcファイルの作成を手伝ってくれたRedditのZoWnxに感謝します

20. Libs/Config 内の共有tsconfig.jsonを構成する

pnpm ワークスペースの機能を活用して、プロジェクト間で共有できる構成ファイルを作成できます。


ライブラリに使用する基本の tsconfig.lib.json を作成します。


libs/config内でtsconfig.lib.jsonインスタンス化します。

 touch "libs/config/tsconfig.base.lib.json"


次に、次のコードを追加します。

tsconfig.base.lib.json

 { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": ["ES2022"], "module": "ESNext", "moduleResolution": "Bundler", "resolveJsonModule": true, "target": "ES2022", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "allowImportingTsExtensions": true, "allowJs": true, "noUncheckedIndexedAccess": true, "noEmit": true, "incremental": true, "composite": false, "declaration": true, "declarationMap": true, "inlineSources": false, "isolatedModules": true, "noUnusedLocals": false, "noUnusedParameters": false, "preserveWatchOutput": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, "sourceMap": true, } } 


21. db リポジトリに db 接続を追加します。

 // libs/db/drizzle.config.ts (Yes, this one is at root of the db package, outside the src folder) // We don't want to export this file as this is ran at setup. import "dotenv/config"; // make sure to install dotenv package import { defineConfig } from "drizzle-kit"; export default defineConfig({ dialect: "postgresql", out: "./src/generated", schema: "./src/drizzle/schema.ts", dbCredentials: { url: process.env.DATABASE_URL!, }, // Print all statements verbose: true, // Always ask for confirmation strict: true, });


スキーマ ファイル:

 // libs/db/src/drizzle/schema.ts export const User = pgTable("User", { userId: char("userId", { length: 26 }).primaryKey().notNull(), subId: char("subId", { length: 36 }).notNull(), // We are not making this unique to support merging accounts in later // iterations email: text("email"), loginProvider: loginProviderEnum("loginProvider").array().notNull(), createdAt: timestamp("createdAt", { precision: 3, mode: "date" }).notNull(), updatedAt: timestamp("updatedAt", { precision: 3, mode: "date" }).notNull(), });


クライアント ファイル:

 // libs/db/src/drizzle-client.ts import { drizzle, PostgresJsDatabase } from "drizzle-orm/postgres-js"; import postgres from "postgres"; import * as schema from "./schema"; export type DrizzleClient = PostgresJsDatabase<typeof schema>; let drizzleClient: DrizzleClient | undefined; type GetClientInput = { databaseUrl: string; env: string; mode?: "cloudflare" | "node"; }; declare var window: typeof globalThis; declare var self: typeof globalThis; export function getDrizzleClient(input: GetClientInput) { const { mode, env } = input; if (mode === "cloudflare") { return generateClient(input); } const globalObject = typeof globalThis !== "undefined" ? globalThis : typeof global !== "undefined" ? global : typeof window !== "undefined" ? window : self; if (env === "production") { drizzleClient = generateClient(input); } else if (globalObject) { if (!(globalObject as any).__db__) { (globalObject as any).__db__ = generateClient(input); } drizzleClient = (globalObject as any).__db__; } else { drizzleClient = generateClient(input); } return drizzleClient; } type GenerateClientInput = { databaseUrl: string; env: string; }; function generateClient(input: GenerateClientInput) { const { databaseUrl, env } = input; const isLoggingEnabled = env === "development"; // prepare: false for serverless try { const client = postgres(databaseUrl, { prepare: false }); const db = drizzle(client, { schema, logger: isLoggingEnabled }); return db; } catch (e) { console.log("ERROR", e); return undefined!; } }


移行ファイル:

 // libs/db/src/drizzle/migrate.ts import { config } from "dotenv"; import { migrate } from "drizzle-orm/postgres-js/migrator"; import postgres from "postgres"; import { drizzle } from "drizzle-orm/postgres-js"; import "dotenv/config"; import path from "path"; config({ path: "../../../../apps/my-remix-cloudflare-app/.dev.vars" }); const ssl = process.env.ENVIRONMENT === "development" ? undefined : "require"; const databaseUrl = drizzle( postgres(`${process.env.DATABASE_URL}`, { ssl, max: 1 }) ); // Somehow the current starting path is /libs/db // Remember to have the DB running before running this script const migration = path.resolve("./src/generated"); const main = async () => { try { await migrate(databaseUrl, { migrationsFolder: migration, }); console.log("Migration complete"); } catch (error) { console.log(error); } process.exit(0); }; main();

これは移行後に実行する必要があります


そして、 src/index.tsファイルにクライアントとスキーマをエクスポートします。その他は特定の時間に実行されます。

 // libs/db/src/index.ts export * from "./drizzle/drizzle-client"; export * from "./drizzle/schema "


package.jsonに、 drizzle-kit generateと、移行コマンドを実行するコードを追加します。

 { "name": "@repo/db", "version": "1.0.0", "main": "./src/index.ts", "module": "./src/index.ts", "types": "./src/index.ts", "scripts": { "db:generate": "drizzle-kit generate", "db:migrate": "dotenv tsx ./drizzle/migrate", }, "exports": { ".": { "import": "./src/index.ts", "default": "./src/index.ts" } }, "dependencies": { "@repo/configs": "workspace:^", "drizzle-kit": "^0.24.1", "drizzle-orm": "^0.33.0", }, "devDependencies": { "@types/node": "^22.5.0" } }

22. libs/dblibs/utilsに共有tsconfig.jsonを使用する

libs/dblibs/utilsの tsconfig.json を作成します。

 touch "libs/db/tsconfig.json" "libs/utils/tsconfig.json"


次に、それぞれに以下を追加します。

 { "extends": "@repo/configs/tsconfig.base.lib.json", "include": ["./src"], }
  • @repo/configsが tsconfig.base.lib.json を参照するパスとして使用されていることを確認します。
  • それは私たちの道をきれいにします。

23. TSXをインストールする

TypeScript Execute (TSX) は、ts-node の代替となるライブラリです。これを使用して、drizzle の移行を実行します。

 pnpm add tsx -D --filter=@repo/db

24. libs/dbディレクトリに空の.envを追加する

touch "libs/db/.env"


次の内容を追加します。

 DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres" NODE_ENV="development" MODE="node" 


こんな感じになるはずです


25. Remix プロジェクトにlibs/dbリポジトリを追加する

プロジェクトのルートから、次のコマンドを実行します。

 pnpm add @repo/db --filter=@repo/my-remix-cloudflare-app


これが機能しない場合は、 apps/my-remix-cloudflare-appの package.json に移動し、依存関係を手動で追加します。

 { "name": "@repo/my-remix-cloudflare-app", "version": "1.0.0", "dependencies": { "@repo/db": "workspace:*" } }

バージョン フィールドのworkspace:*に注意してください。これにより、pnpm はワークスペース内のパッケージの任意のバージョンを使用するように指示されます。


pnpm add,おそらくworkspace:^のようなものが表示されます。ローカル パッケージのバージョンを上げない限り、問題にはなりません。


これを手動で追加した場合は、プロジェクトのルートからpnpm install実行します。


プロジェクトで @repo/db を使用できるはずです。

26. ユーティリティに共有コードを追加する:

次のコードをlibs/utils/src/index.tsファイルに追加します。

 // libs/utils/src/index.ts export function hellowWorld() { return "Hello World!"; }


27. Remix アプリにライブラリ/ユーティリティをインストールします。

 pnpm add @repo/db --filter=@repo/my-remix-cloudflare-app

28. (オプション) Docker コンテナから Postgres を起動する

Postgres インスタンスを実行していない場合は、docker-compose を使用して起動できます。なお、ここでは Docker について知っていることを前提としています。


プロジェクトのルートにdocker-compose.ymlファイルを作成します。

 # Auto-generated docker-compose.yml file. version: '3.8' # Define services. services: postgres: image: postgres:latest restart: always environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres - POSTGRES_DB=postgres ports: - "5432:5432" volumes: - ./postgres-data:/var/lib/postgresql/data pgadmin: # To connect PG Admin, navigate to http://localhost:8500 use: # host.docker.internal # postgres # (username) postgres # (password) postgres image: dpage/pgadmin4 ports: - "8500:80" environment: PGADMIN_DEFAULT_EMAIL: [email protected] PGADMIN_DEFAULT_PASSWORD: admin


次に、次のコマンドを実行します。

 docker-compose up -d

-dフラグは、docker-compose にデタッチされた状態で実行するように指示し、ターミナルに再度アクセスできるようにします。

29. DBスキーマを生成する

次に、libs/db リポジトリに移動して、 db:generate実行します。

 cd `./libs/db` && pnpm db:generate
  • db:generate drizzle-kit generateの別名であることに注意してください。
  • 適切な .env があることを確認します。
  • さらに、Postgres インスタンスが実行されていることを前提としています。

30. 移行を実行します。

データベース内のすべてのテーブルをスキャフォールディングするには、移行を実行する必要があります。


libs/db リポジトリに移動し (まだそこにない場合)、 db:generate実行します。

 cd `./libs/db` && pnpm db:migrate
  • db:migrate dotenv tsx ./drizzle/migrateのエイリアスであることに注意してください。
  • 適切な .env があることを確認します。
  • さらに、Postgres インスタンスが実行されていることを前提としています。

31. Remix アプリ内に DB 呼び出しを挿入します。

 // apps/my-remix-cloudflare-app/app/routes/_index.tsx import type { LoaderFunctionArgs } from '@remix-run/cloudflare'; import { json, useLoaderData } from '@remix-run/react'; import { getDrizzleClient } from '@repo/db'; import { Markdown } from '~/components'; import { getFileContentWithCache } from '~/services/github.server'; import { parse } from '~/services/markdoc.server'; export async function loader({ context }: LoaderFunctionArgs) { const client = await getDrizzleClient({ databaseUrl: context.env.DATABASE_URL, env: 'development', mode: 'cloudflare', }); if (client) { const res = await client.query.User.findFirst(); console.log('res', res); } const content = await getFileContentWithCache(context, 'README.md'); return json( { content: parse(content), // user: firstUser, }, { headers: { 'Cache-Control': 'public, max-age=3600', }, }, ); } export default function Index() { const { content } = useLoaderData<typeof loader>(); return <Markdown content={content} />; }


  • ここではベストプラクティスに従っていないことに注意してください。
  • ローダー内で直接 DB 呼び出しを行わず、それらを呼び出す抽象化を作成することをお勧めします。
  • Cloudflareは環境変数の設定が難しい。環境変数はリクエストによって渡される。

32. .dev.vars に以下を追加します。

アプリ/my-remix-cloudflare-app/.dev.vars

 DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres"

33. リミックスプロジェクトを実行する!

postgresインスタンスを起動します(準備ができていない場合)

 docker-compose up -d


プロジェクトを開始する

pnpm turbo dev 


高度な使用例 - Cloudflare Workers の GetLoadContext における CQRS。

私のプロジェクトでは、 CQRS パターン2を実装する傾向があります。これはこのチュートリアルの範囲外です。


それでも、ロード コンテキスト内では、Remix アプリケーション全体をビジネス ロジックから切り離すメディエーター (および Cookie フラッシュ メッセージ) を挿入する傾向があります。


これは次のようになります:

 export const getLoadContext: GetLoadContext = async ({ context, request }) => { const isEnvEmpty = Object.keys(context.cloudflare.env).length === 0; const env = isEnvEmpty ? process.env : context.cloudflare.env; const sessionFlashSecret = env.SESSION_FLASH_SECRET; const flashStorage = createCookieSessionStorage({ cookie: { name: "__flash", httpOnly: true, maxAge: 60, path: "/", sameSite: "lax", secrets: [sessionFlashSecret], secure: true, }, }); return { ...context, cloudflare: { ...context.cloudflare, env, }, dispatch: (await dispatchWithContext({ env: env as unknown as Record<string, string>, request, })) as Dispatch, flashStorage, }; };

ディスパッチ コードが省略されていることに注意してください。詳細については、TypeScript 開発エクスペリエンスを 10 倍にする方法に関する私の記事ご覧ください。


コードを変更せずに、Remix を削除したり、別のコンシューマーを使用したりできます。


しかし…。


turborepo を使用してモノレポ構造で作業する場合は、追加の課題があります。


ロード コンテキスト内のパッケージから TypeScript ファイルをインポートすると、 @repo/db Vite は拡張子.tsのファイルが不明であるというエラーを返し、そのファイルを処理する方法がわかりません。


これは、load-context + ワークスペースがサイトのメインのインポート グラフの外側にあり、TypeScript ファイルが再生されないために発生します。


コツは、 tsx使用して、Vite を呼び出す前にロードすることです。これは、次の制限を克服するため重要です。


Cloudflare パッケージの依存関係。


Cloudflare パッケージの依存関係と事前ビルド

まず第一に、これは私が避けようとしていたステップでした。パッケージごとにビルド ステップを導入する必要があり、構成が増えることを意味していたからです。


幸いなことに、これは Cloudflare Pages では機能しませんでした。Postgres などの特定のライブラリがランタイムを検出し、必要なパッケージを取得します。


回避策があります。tsx を使用してすべての TypeScript ファイルを読み込み、実行前にトランスパイルすることができます。


これはビルド前のステップだと主張することもできますが、まだリミックスのリポジトリ レベルであるため、このアプローチに大きな問題はないと思います。


これを解決するには、依存関係として tsx を追加します。

 pnpm add tsx -D --filter=@repo/my-remix-cloudflare-app


次に、 package.json変更し、各リミックス スクリプトに tsx プロセスを追加する必要があります。

 { "name": "@repo/my-remix-cloudflare-app", "version": "1.0.0", "scripts": { // Other scripts omitted "build": "NODE_OPTIONS=\"--import tsx/esm\" remix vite:build", "dev": "NODE_OPTIONS=\"--import tsx/esm\" remix vite:dev", "start": "NODE_OPTIONS=\"--import tsx/esm\" wrangler pages dev ./build/client" } }

特典

.npmrcファイルの作成

コマンドラインを使用してローカル パッケージを追加するときに問題が発生する場合は、プロジェクトのルートに.npmrcファイルを作成できます。

.npmrc

 link-workspace-packages= true prefer-workspace-packages=true

これにより、pnpm は最初にワークスペース パッケージを使用するようになります。


.nprmcファイルの作成を手伝ってくれたRedditのZoWnxに感謝します

落とし穴 -

  1. ファイル内の.clientおよび.server命名には注意してください。別のライブラリ内にある場合でも同様です。Remix はこれらを使用して、クライアント ファイルかサーバー ファイルかを判断します。プロジェクトはリポジトリごとにコンパイルされないため、インポート エラーが発生します。


  2. Postgres などのマルチプラットフォーム パッケージで問題が発生する場合は、ワークスペース レベルでインストールすることをお勧めします。適切なインポートが検出されます。@repo/db リポジトリに直接インストールすると、Remix にインポートするときに問題が発生します。


以上です、皆さん!!!

GitHub リポジトリ

完全な実装については、ここからアクセスできます。

ソーシャルで私をフォローしてください!

私は、本番環境での 1% のエラーを検出するために、公開されている自動テスト エンジニアを構築しています。


私は以下の進捗状況を共有しています:


X/Twitter @javiasilis

LinkedIn @javiasilis