paint-brush
Comment créer un monorepo avec Vite, Cloudflare, Remix, PNPM et Turborepo (aucune étape de construction)par@josejaviasilis
1,087 lectures
1,087 lectures

Comment créer un monorepo avec Vite, Cloudflare, Remix, PNPM et Turborepo (aucune étape de construction)

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

Trop long; Pour lire

Cela crée un monorepo pour les déploiements Cloduflare Vite de Remix sans étape de build. Cela vous permet de l'étendre à plusieurs cibles
featured image - Comment créer un monorepo avec Vite, Cloudflare, Remix, PNPM et Turborepo (aucune étape de construction)
Jose Javi Asilis HackerNoon profile picture
0-item




Introduction

J'avais besoin d'un moyen d'utiliser Remix avec Vite et Cloudflare Workers-Pages avec une configuration minimale.


J'ai vu d'autres dépôts, tels que :


Mais ils avaient certaines limites :

  1. Je ne voulais pas le pré-construire, car je ne voulais pas empoisonner les référentiels avec plus de fichiers de configuration.


  2. Cloudflare Workers/Pages a une cible différente. Il est devenu difficile de la cibler avec tsup, car des packages tels que Postgres risquaient de casser les dépendances des nœuds lors de leur importation dans Remix.


  3. J'avais également besoin d'un moyen de consommer différentes cibles (Remix-Cloudflare, Node/Bun)


Néanmoins, je les remercie, car ils ont ouvert la voie pour rendre cela possible !


Assurez-vous de lire la section des pièges en bas !

Suivez-moi sur les réseaux sociaux !

Je construis une plateforme de tests automatisée en public pour détecter ces 1% d'erreurs en production.


Je partage mes progrès sur :


X/Twitter @javiasilis

LinkedIn @javiasilis

Dépôt GitHub

Vous pouvez accéder à l' implémentation complète ici .

Étape par étape

Exigences

  1. NodeJS
  2. PNPM
  3. Docker (facultatif - pour l'exemple de base de données locale)


Bien que cela vous guide à travers un nouveau mono-dépôt, il est parfaitement valable de transformer un mono-dépôt existant en un seul.


Cela supposera également que vous avez quelques connaissances en matière de mono repo.


Note:

  • « at root » fait référence au chemin de départ de votre monorepository. Pour ce projet, il sera en dehors des répertoires libs et packages .

Installer Turborepo

Turborepo fonctionne au-dessus des espaces de travail de votre gestionnaire de paquets pour gérer les scripts et les sorties de votre projet (il peut même mettre en cache votre sortie). Jusqu'à présent, c'est le seul outil mono-repo en dehors de Rush (que je n'ai pas essayé et que je n'aime pas) qui est capable de fonctionner.


NX ne prend pas en charge Vite de Remix (au moment de la rédaction de cet article - 28 août 2024).


https://turbo.build/

 pnpm dlx create-turbo@latest

1. Configurer les espaces de travail PNPM

Nous utiliserons les fonctionnalités de l'espace de travail de PNPM pour gérer les dépendances.


Dans votre répertoire Monorepo, créez un pnpm-workspace.yaml .


À l'intérieur, ajoutez :

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


Cela indiquera à pnpm que tous les dépôts se trouveront dans apps et libs . Notez que l'utilisation libs ou packages (comme vous l'avez peut-être vu ailleurs) n'a pas d'importance.

2. Créez un package.json vide à la racine du projet :

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


Notez le name:@repo/main Cela nous indique qu'il s'agit de l'entrée principale de l'application. Vous n'avez pas besoin de suivre une convention particulière ou d'utiliser le préfixe @ . Les gens l'utilisent pour le différencier des packages locaux/distants ou pour faciliter son regroupement dans une organisation.

3. Créez le fichier turbo.json à la racine du projet :

 { "$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": {} } }


Le fichier turbo.json indique au référentiel turbo comment interpréter nos commandes. Tout ce qui se trouve à l'intérieur de la clé tasks correspondra à ceux trouvés dans le package all.json.


Notez que nous définissons quatre commandes. Celles-ci correspondent à celles de la section script du package.json de chaque dépôt. Cependant, tous les packages.json ne doivent pas implémenter ces commandes.


Par exemple : la commande dev sera déclenchée par turbo dev et exécutera tous les packages dont dev se trouve dans package.json. Si vous ne l'incluez pas dans turbo, elle ne s'exécutera pas.

4. Créez un dossier apps à la racine du projet

 mkdir apps

5. Créez une application de remix dans le dossier apps (ou déplacez-en une existante)

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


Lorsqu'il vous demande d' Install any dependencies with npm dites non.


  • Voilà à quoi cela devrait ressembler

6. Renommez le name du package.json en @repo/my-remix-cloudflare-app (ou votre nom)

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

7. Copiez les dépendances et les devDependencies de apps/<app>/package.json vers le package.json de la racine

Par exemple :

<racine>/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. Ajoutez Turbo en tant que devDependency au niveau racine (cela installera tous les packages du Remix).

Vérifiez que turbo se trouve dans les devDependencies de package.json. S'il n'est pas répertorié, exécutez la commande suivante :

 pnpm add turbo -D -w


L'indicateur -w indique à pnpm de l'installer à la racine de l'espace de travail.

9. Ajoutez les entrées suivantes au package racine.json

  • Ajoutez la commande dev aux scripts

  • Ajoutez le packageManager à l'option


 { "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. Vérifiez que tout fonctionne en exécutant pnpm dev

 pnpm dev

11. Créez un dossier Libs à la racine du projet. Ajoutez config, db et utils :

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

12. Ajoutez un src/index.ts pour chacun des packages.

 touch libs/config/src/index.ts libs/db/src/index.ts libs/utils/src/index.ts
  • Le fichier index.ts sera utilisé pour exporter tous les packages.
  • Nous utiliserons le dossier comme point d’entrée pour rendre tout compact.
  • Il s’agit d’une convention et vous pouvez choisir de ne pas la suivre.

13. Créez un package.json vide et ajoutez ce qui suit au fichier libs/config/package.json :

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

14. Faites la même chose pour libs/db/package.json :

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

15. Et libs/utils/package.json :

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


  • Nous spécifions le champ « exportations ». Cela indique aux autres dépôts d'où importer le paquet.
  • Nous spécifions le champ « nom ». Il est utilisé pour installer le paquet et le référencer à d’autres dépôts.

16. (DB) - Ajouter Drizzle et Postgres

Remarques :

  • Je commence à mépriser les ORM. J'ai passé plus de 10 ans à en apprendre 6 différents, et ce sont des connaissances qu'on ne peut pas transférer.

  • Vous rencontrez des problèmes lorsque de nouvelles technologies apparaissent. Prisma ne prend pas en charge les workers Cloudflare par défaut.

  • Avec les LLM, il est plus facile que jamais d’écrire des requêtes SQL complexes.

  • Apprendre SQL est un langage universel et ne changera probablement pas.


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


Installez Postgres au niveau de l'espace de travail. Voir la section Piège .

 pnma add postgres -w


Remarques :

  • L'indicateur --filter=@repo/db indique à pnpm d'ajouter le package au référentiel db.

17. Ajoutez le dotenv au référentiel de l'espace de travail

 pnpm add dotenv -w

Remarques

  • L'indicateur -w indique à pnpm de l'installer dans le package.json de la racine

18. Ajoutez le projet de configuration à tous les projets.

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

Remarques :

  • L'indicateur -r indique à pnpm d'ajouter le package à tous les référentiels.
  • L'indicateur --filter=! indique à pnpm d'exclure le référentiel de configuration.
  • Notez le ! avant le nom du package

19. (Facultatif) Les commandes ci-dessus ne fonctionnent pas ? Utilisez .npmrc

Si pnpm extrait les packages du référentiel, nous pouvons créer un fichier .npmrc à la racine du projet.


.npmrc

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


  • Cela indiquera à pnpm d’utiliser d’abord les packages de l’espace de travail.
  • Merci à ZoWnx de Reddit, qui m'a aidé à créer un fichier .nprmc

20. Configurer le tsconfig.json partagé dans Libs/Config

En utilisant la puissance des espaces de travail pnpm, vous pouvez créer des fichiers de configuration qui peuvent être partagés entre les projets.


Nous allons créer un tsconfig.lib.json de base que nous utiliserons pour nos bibliothèques.


Dans libs/config instanciez un tsconfig.lib.json :

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


Ensuite, ajoutez ce qui suit :

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. Ajoutez la connexion db au référentiel 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, });


Le fichier de schéma :

 // 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(), });


Le dossier client :

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


Le fichier de migration :

 // 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();

Ceci devrait être exécuté après les migrations


Et exportez le client et le schéma dans le fichier src/index.ts . D'autres sont exécutés à des moments précis.

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


Dans votre package.json , ajoutez le drizzle-kit generate et le code pour exécuter la commande de migration :

 { "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. Utilisez le tsconfig.json partagé pour libs/db et libs/utils

Créez un tsconfig.json pour libs/db et libs/utils

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


Ajoutez ensuite à chacun :

 { "extends": "@repo/configs/tsconfig.base.lib.json", "include": ["./src"], }
  • Vérifiez que @repo/configs est utilisé comme chemin pour faire référence à notre tsconfig.base.lib.json.
  • Cela rend notre chemin propre.

23. Installer TSX

TypeScript Execute (TSX) est une bibliothèque alternative à ts-node. Nous l'utiliserons pour exécuter les migrations de Drizzle.

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

24. Ajoutez un .env vide dans le répertoire libs/db

 touch "libs/db/.env"


Ajoutez le contenu suivant :

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


Cela devrait ressembler à ceci


25. Ajoutez le référentiel libs/db à notre projet de remix

Depuis la racine du projet, exécutez :

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


Si cela ne fonctionne pas, accédez au package.json de apps/my-remix-cloudflare-app et ajoutez la dépendance manuellement.

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

Notez l' workspace:* dans le champ version. Cela indique à pnpm d'utiliser n'importe quelle version du package dans l'espace de travail.


Si vous l'avez installé via la CLI en utilisant pnpm add, vous verrez probablement quelque chose comme workspace:^ . Cela ne devrait pas avoir d'importance tant que vous n'augmentez pas les versions des packages locaux.


Si vous l'avez ajouté manuellement, exécutez pnpm install depuis la racine du projet.


Nous devrions pouvoir utiliser le @repo/db dans notre projet.

26. Ajoutez du code partagé à nos utilitaires :

Ajoutez ce code au fichier libs/utils/src/index.ts :

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


27. Installez les bibliothèques/utilitaires sur notre application Remix :

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

28. (Facultatif) Lancer un Postgres à partir d'un conteneur Docker

Si vous n'avez pas d'instance Postgres en cours d'exécution, nous pouvons en lancer une à l'aide de docker-compose. Remarque : je suppose que vous connaissez Docker.


Créez un fichier docker-compose.yml à la racine du projet.

 # 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


Ensuite, vous pouvez exécuter :

 docker-compose up -d

L'indicateur -d indique à docker-compose de s'exécuter séparément afin que vous puissiez à nouveau accéder à votre terminal.

29. Générer le schéma de base de données

Accédez maintenant au référentiel libs/db et exécutez db:generate .

 cd `./libs/db` && pnpm db:generate
  • Notez que db:generate est un alias pour : drizzle-kit generate
  • Vérifiez que vous disposez du bon .env.
  • De plus, cela suppose que vous disposez d’une instance Postgres en cours d’exécution.

30. Exécutez les migrations.

Nous devons exécuter les migrations pour structurer toutes les tables de notre base de données.


Accédez au référentiel libs/db (si vous n'y êtes pas) et exécutez db:generate .

 cd `./libs/db` && pnpm db:migrate
  • Notez que db:migrate est un alias pour : dotenv tsx ./drizzle/migrate
  • Vérifiez que vous disposez du bon .env.
  • De plus, cela suppose que vous disposez d’une instance Postgres en cours d’exécution.

31. Insérez un appel DB dans votre application 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} />; }


  • Notez que nous ne suivons pas les meilleures pratiques ici.
  • Je vous conseille de ne faire aucun appel de base de données directement dans votre chargeur, mais de créer une abstraction qui les appelle.
  • Cloudflare est un défi lorsqu'il s'agit de définir les variables d'environnement. Elles sont transmises par requête

32. Ajoutez dans votre .dev.vars les éléments suivants :

applications/mon-application-cloudflare-remix/.dev.vars

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

33. Exécutez le projet Remix !

Lancer l'instance postgres (si elle n'est pas prête)

 docker-compose up -d


Lancer le projet

 pnpm turbo dev 


Cas d'utilisation avancé - CQRS dans GetLoadContext dans Cloudflare Workers.

Dans mes projets, j'ai tendance à implémenter un modèle CQRS , 2 . Ceci sort du cadre de ce tutoriel.


Néanmoins, dans le contexte de chargement, j’ai tendance à injecter un médiateur (et un message flash de cookie) qui découplera toute mon application Remix de ma logique métier.


Cela ressemble à ceci :

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

Notez que le code de répartition est omis. Vous pouvez en savoir plus à ce sujet dans mon article sur la façon de décupler votre expérience de développement TypeScript ici .


Je peux supprimer Remix ou utiliser un autre consommateur sans modifier mon code.


Mais….


Il y a un défi supplémentaire lorsque vous travaillez dans une structure monorepo utilisant turborepo.


Si vous importez un fichier TypeScript à partir d'un package dans le contexte de chargement, disons que @repo/db Vite renverra une erreur indiquant que le fichier avec l'extension .ts est inconnu et ne saura pas comment le traiter.


Cela se produit parce que le contexte de chargement + les espaces de travail sont en dehors du graphique d'importation principal du site, laissant les fichiers TypeScript hors jeu.


L'astuce consiste à utiliser tsx et à le charger avant d'appeler Vite, ce qui fonctionnera. Ceci est important car cela permet de surmonter les limitations suivantes :


Dépendances du package Cloudflare.


Dépendances et pré-construction des packages Cloudflare

Tout d’abord, c’était l’étape que j’essayais d’éviter, car cela signifiait que je devais introduire une étape de construction pour chacun des packages, ce qui impliquait plus de configuration.


Heureusement, cela n'a pas fonctionné pour les pages Cloudflare. Des bibliothèques spécifiques, telles que Postgres, détecteront l'exécution et extrairont le package requis.


Il existe une solution de contournement : nous pouvons utiliser tsx pour charger tous les fichiers TypeScript et les transpiler avant de les exécuter.


Vous pouvez affirmer qu'il s'agit d'une étape de pré-construction, mais comme elle se trouve toujours au niveau du référentiel du remix, je ne vois pas de problèmes importants avec cette approche.


Pour résoudre ce problème, nous ajoutons tsx comme dépendance :

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


Et puis, nous devons modifier notre package.json et ajouter le processus tsx à chacun de nos scripts de remix :

 { "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" } }

Suppléments

Création d'un fichier .npmrc

Si vous rencontrez des problèmes lors de l'ajout de vos packages locaux avec la ligne de commande, vous pouvez créer un fichier .npmrc à la racine du projet.

.npmrc

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

Cela indiquera à pnpm d’utiliser d’abord les packages de l’espace de travail.


Merci à ZoWnx de Reddit qui m'a aidé à créer un fichier .nprmc

Pièges -

  1. Soyez prudent avec les noms de .client et .server dans vos fichiers. Même s'ils se trouvent dans une bibliothèque distincte. Remix les utilise pour déterminer s'il s'agit d'un fichier client ou serveur. Le projet n'est pas compilé par référentiel, il génère donc une erreur d'importation !


  2. Si vous rencontrez des problèmes avec des packages multi-plateformes tels que Postgres, il est préférable de l'installer au niveau de l'espace de travail. Il détectera l'importation appropriée. L'installer directement dans le référentiel @repo/db ne fonctionnera pas lors de son importation dans Remix.


C'est tout, les amis !!!

Dépôt GitHub

Vous pouvez accéder à l' implémentation complète ici .

Suivez-moi sur les réseaux sociaux !

Je suis en train de créer un ingénieur de tests automatisé en public pour détecter ces 1% d'erreurs en production.


Je partage mes progrès sur :


X/Twitter @javiasilis

LinkedIn @javiasilis