paint-brush
Как создать монорепозиторий с помощью Vite, Cloudflare, Remix, PNPM и Turborepo (без этапа сборки)к@josejaviasilis
1,374 чтения
1,374 чтения

Как создать монорепозиторий с помощью Vite, Cloudflare, Remix, PNPM и Turborepo (без этапа сборки)

к Jose Javi Asilis19m2024/08/28
Read on Terminal Reader

Слишком долго; Читать

Это создает монорепозиторий для Remix's Vite Cloduflare Deployments без шага сборки. Это позволяет расширить его на несколько целей
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 имеет другую цель. Стало сложно нацеливаться на нее с помощью tsup, поскольку такие пакеты, как Postgres, вытягивали зависимости узлов, ломающиеся при импорте в Remix.


  3. Мне также нужен был способ использования различных целей (Remix-Cloudflare, Node/Bun)


Тем не менее, я благодарен им, поскольку они проложили путь к тому, чтобы это стало возможным!


Обязательно прочитайте раздел «Подводные камни» внизу!

Подписывайтесь на меня в социальных сетях!

Я создаю автоматизированную платформу тестирования для публичного использования, чтобы выявлять эти 1% ошибок в производстве.


Я делюсь своим прогрессом по следующим темам:


X/Twitter @javiasilis

LinkedIn @javiasilis

Репозиторий GitHub

Полную версию реализации можно посмотреть здесь .

Шаг за шагом

Требования

  1. NodeJS
  2. ПНПМ
  3. Docker (необязательно — для примера локальной базы данных)


Хотя это проведет вас через новый монорепозиторий, вполне допустимо преобразовать в него уже существующий.


Также предполагается, что у вас есть некоторые знания о Mono Repo.


Примечание:

  • «at root» относится к начальному пути вашего монорепозитория. Для этого проекта он будет за пределами каталогов libs и packages .

Установить ТурбоРепо

Turborepo работает поверх рабочих пространств вашего менеджера пакетов для управления скриптами и выходами вашего проекта (он даже может кэшировать ваш выход). Пока что это единственный инструмент для монорепозитория, помимо Rush (который я не пробовал и который мне не нравится), который способен работать.


NX не поддерживает Vite от Remix (на момент написания статьи — 28 августа 2024 г.).


https://turbo.build/

 pnpm dlx create-turbo@latest

1. Настройте рабочие пространства PNPM

Мы будем использовать возможности рабочего пространства PNPM для управления зависимостями.


В каталоге Monorepo создайте файл pnpm-workspace.yaml .


Внутри него добавьте:

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


Это сообщит pnpm, что все репозитории будут находиться внутри apps и libs . Обратите внимание, что использование libs или packages (как вы могли видеть в другом месте) не имеет значения.

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 будет соответствовать тому, что находится в файле all package.json.


Обратите внимание, что мы определяем четыре команды. Они соответствуют командам в разделе скриптов package.json каждого репозитория. Однако не все package.json должны реализовывать эти команды.


Например: команда dev будет вызвана turbo dev , и она выполнит все пакеты, которые dev найдены в package.json. Если вы не включите его в turbo, он не выполнится.

4. Создайте папку apps в корне проекта.

 mkdir apps

5. Создайте приложение Remix в папке apps (или переместите существующее)

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


Когда вас попросят Install any dependencies with npm ответьте «нет».


  • Вот как это должно выглядеть

6. Переименуйте name package.json в @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. Скопируйте зависимости и 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's devDependencies. Если его нет в списке, выполните следующую команду:

 pnpm add turbo -D -w


Флаг -w сообщает pnpm о необходимости установки в корне рабочей области.

9. Добавьте следующие записи в корневой файл package.json

  • Добавьте команду dev в scripts

  • Добавьте 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». Это сообщает другим репозиториям, откуда импортировать пакет.
  • Указываем поле «имя». Оно используется для установки пакета и ссылки на другие репозитории.

16. (DB) - Добавить Drizzle и Postgres

Примечания:

  • Я начинаю презирать ORM. Я потратил более 10 лет на изучение 6 разных, и эти знания невозможно передать.

  • У вас проблемы, когда выходят новые технологии. Prisma не поддерживает Cloudflare worker'ов из коробки.

  • Благодаря 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. Добавьте проект конфигурации во все проекты.

 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 о необходимости сначала использовать пакеты рабочего пространства.
  • Спасибо ZoWnx из Reddit, который помог мне создать файл .nprmc

20. Настройте общий tsconfig.json внутри Libs/Config

Используя возможности рабочих пространств 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. Добавьте подключение к базе данных в репозиторий баз данных.

 // 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. Используйте общий tsconfig.json для libs/db и libs/utils

Создайте tsconfig.json для libs/db и libs/utils

 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. Добавьте пустой .env в каталог libs/db

 touch "libs/db/.env"


Добавьте следующее содержимое:

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


Это должно выглядеть примерно так


25. Добавьте репозиторий libs/db в наш проект ремикса

Из корня проекта запустите:

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


Если это не сработает, перейдите в package.json apps/my-remix-cloudflare-app и добавьте зависимость вручную.

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

Обратите внимание workspace:* в поле версии. Это говорит pnpm использовать любую версию пакета в workspace.


Если вы установили его через CLI с помощью 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. (Необязательно) Запуск Postgres из контейнера Docker

Если у вас нет запущенного экземпляра 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. Сгенерируйте схему БД

Теперь перейдите в репозиторий 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.

 // 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} />; }


  • Обратите внимание, что здесь мы не следуем передовым практикам.
  • Я бы посоветовал вам не делать никаких вызовов БД напрямую внутри загрузчика, а создать абстракцию, которая будет их вызывать.
  • Cloudflare сложен в настройке переменных окружения. Они передаются по запросу

32. Добавьте в ваш .dev.vars следующее:

apps/my-remix-cloudflare-app/.dev.vars

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

33. Реализуйте проект ремикса!

Запустить экземпляр postgres (если не готов)

 docker-compose up -d


Запустить проект

 pnpm turbo dev 


Расширенный вариант использования — CQRS в GetLoadContext в Cloudflare Workers.

В своих проектах я, как правило, реализую шаблон CQRS , 2. Это выходит за рамки данного руководства.


Тем не менее, в контексте загрузки я стараюсь внедрять посредника (и флэш-сообщение cookie), который отделит все мое приложение Remix от моей бизнес-логики.


Это выглядит примерно так:

 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, }; };

Обратите внимание, что код отправки опущен. Вы можете узнать больше об этом в моей статье о том, как в 10 раз улучшить свой опыт разработки TypeScript здесь .


Я могу удалить Remix или использовать другой потребитель, не изменяя свой код.


Но….


При работе в структуре монорепозитория с использованием турборепозитория возникают дополнительные трудности.


Если вы импортируете файл TypeScript из пакета в контексте загрузки, скажем @repo/db Vite вернет ошибку, что файл с расширением .ts неизвестен, и не будет знать, как его обработать.


Это происходит из-за того, что load-context + workspaces находятся за пределами основного графика импорта сайта, в результате чего файлы 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 о необходимости сначала использовать пакеты рабочего пространства.


Спасибо ZoWnx из Reddit, который помог мне создать файл .nprmc

Подводные камни -

  1. Будьте осторожны с именами .client и .server в ваших файлах. Даже если это отдельная библиотека. Remix использует их, чтобы определить, является ли это файлом клиента или сервера. Проект не компилируется для каждого репозитория, поэтому он выдаст ошибку импорта!


  2. Если у вас возникли проблемы с многоплатформенными пакетами, такими как Postgres, лучше установить его на уровне рабочей области. Он обнаружит правильный импорт. Установка его напрямую в репозиторий @repo/db сломает его при импорте в Remix.


Вот и всё, ребята!!!

Репозиторий GitHub

Полную версию реализации можно посмотреть здесь .

Подписывайтесь на меня в социальных сетях!

Я создаю автоматизированного инженера по тестированию для общественности, чтобы выявлять эти 1% ошибок в производстве.


Я делюсь своим прогрессом по следующим темам:


X/Twitter @javiasilis

LinkedIn @javiasilis