Giới thiệu Tôi cần tìm cách sử dụng Remix với Vite và Cloudflare Workers-Pages với cấu hình tối thiểu. Tôi đã thấy các kho lưu trữ khác, chẳng hạn như: , Đống phúc âm , Girish21 . Himorishige Nhưng chúng có một số hạn chế: Tôi không muốn xây dựng trước vì không muốn làm hỏng kho lưu trữ bằng nhiều tệp cấu hình hơn. Cloudflare Workers/Pages có mục tiêu khác. Sẽ rất khó để nhắm mục tiêu vào tsup vì các gói như Postgres sẽ kéo các phụ thuộc của nút bị hỏng khi nhập vào Remix. Tôi cũng cần một cách để sử dụng các mục tiêu khác nhau (Remix-Cloudflare, Node/Bun) Tuy nhiên, tôi vẫn cảm ơn họ vì họ đã mở đường để biến điều này thành hiện thực! Hãy nhớ đọc phần lưu ý ở cuối nhé! Theo dõi tôi trên mạng xã hội! Tôi đang xây dựng một nền tảng thử nghiệm tự động công khai để phát hiện 1% lỗi trong quá trình sản xuất. Tôi chia sẻ tiến trình của mình về: X/Twitter @javiasilis Linkedin @javiasilis Kho lưu trữ GitHub Bạn có thể truy cập vào . bản triển khai đầy đủ tại đây từng bước một Yêu cầu NodeJS PNPPM-VN Docker (Tùy chọn - Đối với ví dụ cơ sở dữ liệu cục bộ) Mặc dù cách này hướng dẫn bạn đến một kho lưu trữ đơn mới, nhưng việc chuyển đổi kho lưu trữ đơn hiện có thành kho lưu trữ đơn là hoàn toàn hợp lệ. Điều này cũng giả định rằng bạn có một số kiến thức về mono repo. Ghi chú: “at root” đề cập đến đường dẫn bắt đầu của monorepository của bạn. Đối với dự án này, nó sẽ nằm ngoài thư mục và . libs packages Cài đặt Turborepo Turborepo hoạt động trên không gian làm việc của trình quản lý gói để quản lý các tập lệnh và đầu ra của dự án (nó thậm chí có thể lưu trữ đệm đầu ra của bạn). Cho đến nay, đây là công cụ mono-repo duy nhất ngoài Rush (mà tôi chưa thử và không thích) có khả năng hoạt động. NX không hỗ trợ Vite của Remix (tính đến thời điểm viết bài này - 28 tháng 8 năm 2024). https://turbo.build/ pnpm dlx create-turbo@latest 1. Cấu hình không gian làm việc PNPM Chúng tôi sẽ sử dụng khả năng không gian làm việc của PNPM để quản lý các mối phụ thuộc. Trên thư mục Monorepo của bạn, hãy tạo . pnpm-workspace.yaml Bên trong, thêm: packages: - "apps/*" - "libs/*" Điều này sẽ cho pnpm biết rằng tất cả các kho lưu trữ sẽ nằm bên trong và . Lưu ý rằng việc sử dụng hoặc (như bạn có thể đã thấy ở nơi khác) không quan trọng. apps libs libs packages 2. Tạo một package.json trống tại Root của Project: pnpm init { "name": "@repo/main", "version": "1.0.0", "scripts": {}, "keywords": [], "author": "", "license": "ISC" } Lưu ý Điều này cho chúng ta biết rằng đây là mục nhập chính của ứng dụng. Bạn không cần phải tuân theo một quy ước cụ thể hoặc sử dụng tiền tố . Mọi người sử dụng nó để phân biệt với các gói cục bộ/từ xa hoặc để dễ dàng nhóm nó vào một tổ chức. name:@repo/main @ 3. Tạo File trong Thư mục gốc của Dự án: 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": {} } } Tệp turbo.json cho biết kho turbo cách diễn giải các lệnh của chúng ta. Mọi thứ nằm trong khóa sẽ khớp với những thứ được tìm thấy trong all package.json. tasks Lưu ý rằng chúng tôi định nghĩa bốn lệnh. Chúng khớp với các lệnh trong phần tập lệnh của package.json của mỗi kho lưu trữ. Tuy nhiên, không phải tất cả package.json đều phải triển khai các lệnh này. Ví dụ: Lệnh sẽ được kích hoạt bởi và nó sẽ thực thi tất cả các gói mà được tìm thấy trong package.json. Nếu bạn không đưa nó vào turbo, nó sẽ không thực thi. dev turbo dev dev 4. Tạo một thư mục trong thư mục gốc của dự án apps mkdir apps 5. Tạo ứng dụng Remix trong thư mục (hoặc di chuyển ứng dụng hiện có) apps npx create-remix --template edmundhung/remix-worker-template Khi được yêu cầu hãy trả lời không. Install any dependencies with npm 6. Đổi package.json thành (Hoặc Tên của bạn) 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. Sao chép Dependencies và devDependencies từ đến của Root apps/<app>/package.json package.json Ví dụ: <gốc>/gói.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. Thêm Turbo làm devDependency ở cấp độ gốc (Điều này sẽ cài đặt tất cả các gói của Remix). Xác minh rằng turbo nằm trong devDependencies của package.json. Nếu không được liệt kê, hãy thực hiện lệnh sau: pnpm add turbo -D -w Cờ yêu cầu pnpm cài đặt nó tại gốc không gian làm việc. -w 9. Thêm các mục sau vào Root package.json Thêm lệnh vào dev scripts Thêm vào tùy chọn packageManager { "name": "@repo/main", "version": "1.0.0", "scripts": { "dev": "turbo dev" }, "keywords": [], "author": "", "license": "ISC", "packageManager": "pnpm@9.1.0", "dependencies": { // omitted for brevity }, "devDependencies": { // omitted for brevity } } 10. Kiểm tra mọi thứ đang hoạt động bằng cách chạy pnpm dev pnpm dev 11. Tạo một thư mục Libs tại gốc của dự án. Thêm config, db và utils: mkdir -p libs/config libs/db libs/utils 12. Thêm cho mỗi gói. src/index.ts touch libs/config/src/index.ts libs/db/src/index.ts libs/utils/src/index.ts Tệp index.ts sẽ được sử dụng để xuất tất cả các gói. Chúng ta sẽ sử dụng thư mục làm điểm vào để làm cho mọi thứ gọn gàng hơn. Đây là một quy ước và bạn có thể chọn không tuân theo. 13. Tạo một package.json trống và thêm nội dung sau vào tệp : libs/config/package.json { "name": "@repo/config", "version": "1.0.0", "type": "module", "exports": { ".": { "import": "./src/index.ts", "default": "./src/index.ts" } } } 14. Thực hiện tương tự cho : libs/db/package.json { "name": "@repo/db", "version": "1.0.0", "exports": { ".": { "import": "./src/index.ts", "default": "./src/index.ts" } } } 15. Và : libs/utils/package.json { "name": "@repo/utils", "version": "1.0.0", "exports": { ".": { "import": "./src/index.ts", "default": "./src/index.ts" } } } Chúng tôi chỉ định trường “exports”. Trường này cho các kho lưu trữ khác biết nơi nhập gói từ đâu. Chúng tôi chỉ định trường “name”. Trường này được sử dụng để cài đặt gói và tham chiếu đến các kho lưu trữ khác. 16. (DB) - Thêm Drizzle và Postgres Ghi chú: Tôi bắt đầu ghét ORM. Tôi đã dành hơn 10 năm để học 6 loại ORM khác nhau và đó là kiến thức mà bạn không thể chuyển giao. Bạn gặp vấn đề khi công nghệ mới ra đời. Prisma không hỗ trợ Cloudflare worker ngay từ đầu. Với LLM, việc viết các truy vấn SQL phức tạp trở nên dễ dàng hơn bao giờ hết. Học SQL là ngôn ngữ phổ biến và có khả năng sẽ không thay đổi. pnpm add drizzle-orm drizle-kit --filter=@repo/db Cài đặt Postgres ở cấp độ không gian làm việc. . Xem phần Pitfall pnma add postgres -w Ghi chú: Cờ yêu cầu pnpm thêm gói vào kho lưu trữ db. --filter=@repo/db 17. Thêm dotenv vào Kho lưu trữ không gian làm việc pnpm add dotenv -w Ghi chú Cờ yêu cầu pnpm cài đặt nó tại package.json của root -w 18. Thêm Dự án Cấu hình vào Tất cả các Dự án. pnpm add @repo/config -r --filter=!@repo/config : Ghi chú Cờ yêu cầu pnpm thêm gói vào tất cả các kho lưu trữ. -r Cờ yêu cầu pnpm loại trừ kho lưu trữ cấu hình. --filter=! Lưu ý dấu trước tên gói ! 19. (Tùy chọn) Các lệnh trên không hoạt động? Sử dụng .npmrc Nếu pnpm đang kéo các gói từ kho lưu trữ, chúng ta có thể tạo tệp ở thư mục gốc của dự án. .npmrc .npmrc link-workspace-packages= true prefer-workspace-packages=true Điều này sẽ yêu cầu pnpm sử dụng các gói không gian làm việc trước. Cảm ơn từ Reddit đã giúp tôi tạo tệp .nprmc ZoWnx 20. Cấu hình được chia sẻ bên trong Libs/Config tsconfig.json Sử dụng sức mạnh của không gian làm việc pnpm, bạn có thể tạo các tệp cấu hình có thể chia sẻ giữa các dự án. Chúng ta sẽ tạo một file tsconfig.lib.json cơ sở để sử dụng cho các thư viện của mình. Bên trong khởi tạo : libs/config tsconfig.lib.json touch "libs/config/tsconfig.base.lib.json" Sau đó, thêm nội dung sau: 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. Thêm kết nối db vào kho lưu trữ 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, }); Tệp lược đồ: // 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(), }); Tệp khách hàng: // 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!; } } Tệp di chuyển: // 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(); Điều này nên được thực hiện sau khi di chuyển Và xuất client và schema trong file . Những cái khác được chạy vào những thời điểm cụ thể. src/index.ts // libs/db/src/index.ts export * from "./drizzle/drizzle-client"; export * from "./drizzle/schema " Trong của bạn, hãy thêm và mã để chạy lệnh di chuyển: 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. Sử dụng dùng chung cho và tsconfig.json libs/db libs/utils Tạo tsconfig.json cho và libs/db libs/utils touch "libs/db/tsconfig.json" "libs/utils/tsconfig.json" Sau đó thêm vào mỗi mục: { "extends": "@repo/configs/tsconfig.base.lib.json", "include": ["./src"], } Xem được sử dụng làm đường dẫn để tham chiếu đến tsconfig.base.lib.json của chúng tôi. @repo/configs Nó làm cho con đường của chúng ta sạch sẽ. 23. Cài đặt TSX TypeScript Execute (TSX) là một thư viện thay thế cho ts-node. Chúng ta sẽ sử dụng nó để thực hiện di chuyển drizzle. pnpm add tsx -D --filter=@repo/db 24. Thêm một .env trống vào thư mục libs/db touch "libs/db/.env" Thêm các nội dung sau: DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres" NODE_ENV="development" MODE="node" 25. Thêm kho lưu trữ vào dự án Remix của chúng tôi libs/db Từ gốc của dự án, hãy chạy: pnpm add @repo/db --filter=@repo/my-remix-cloudflare-app Nếu cách này không hiệu quả, hãy vào package.json của và thêm phần phụ thuộc theo cách thủ công. apps/my-remix-cloudflare-app { "name": "@repo/my-remix-cloudflare-app", "version": "1.0.0", "dependencies": { "@repo/db": "workspace:*" } } Lưu ý trong trường phiên bản. Điều này cho pnpm biết sử dụng bất kỳ phiên bản nào của gói trong không gian làm việc. workspace:* Nếu bạn cài đặt nó thông qua CLI bằng cách sử dụng bạn có thể sẽ thấy một cái gì đó giống như . Điều đó không quan trọng miễn là bạn không tăng phiên bản gói cục bộ. pnpm add, workspace:^ Nếu bạn đã thêm thủ công, hãy chạy từ thư mục gốc của dự án. pnpm install Chúng ta có thể sử dụng @repo/db trong dự án của mình. 26. Thêm một số mã được chia sẻ vào tiện ích của chúng tôi: Thêm mã này vào tệp : libs/utils/src/index.ts // libs/utils/src/index.ts export function hellowWorld() { return "Hello World!"; } 27. Cài đặt Libs/Utils vào ứng dụng Remix của chúng tôi: pnpm add @repo/db --filter=@repo/my-remix-cloudflare-app 28. (Tùy chọn) Khởi chạy Postgres từ Docker Container Nếu bạn không có phiên bản Postgres đang chạy, chúng ta có thể khởi chạy một phiên bản bằng docker-compose. Lưu ý, tôi cho rằng bạn biết Docker. Tạo tệp ở thư mục gốc của dự án. 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: admin@a.com PGADMIN_DEFAULT_PASSWORD: admin Sau đó bạn có thể chạy: docker-compose up -d Cờ yêu cầu docker-compose chạy riêng biệt để bạn có thể truy cập lại vào thiết bị đầu cuối của mình. -d 29. Tạo lược đồ DB Bây giờ, hãy điều hướng đến kho lưu trữ libs/db và chạy . db:generate cd `./libs/db` && pnpm db:generate Lưu ý rằng là một bí danh cho: db:generate drizzle-kit generate Xác minh rằng bạn có .env phù hợp. Ngoài ra, điều này giả định rằng bạn có một phiên bản Postgres đang chạy. 30. Chạy di chuyển. Chúng ta cần chạy di chuyển để tạo khung cho tất cả các bảng trong cơ sở dữ liệu của mình. Điều hướng đến kho lưu trữ libs/db (nếu bạn không có ở đó) và chạy . db:generate cd `./libs/db` && pnpm db:migrate Lưu ý rằng là một bí danh cho: db:migrate dotenv tsx ./drizzle/migrate Xác minh rằng bạn có .env phù hợp. Ngoài ra, điều này giả định rằng bạn có một phiên bản Postgres đang chạy. 31. Chèn lệnh gọi DB vào ứng dụng Remix của bạn. // 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} />; } Xin lưu ý rằng chúng tôi không tuân theo các biện pháp tốt nhất ở đây. Tôi khuyên bạn không nên thực hiện bất kỳ lệnh gọi DB nào trực tiếp trong trình tải của mình mà hãy tạo một lớp trừu tượng để gọi chúng. Cloudflare gặp khó khăn khi thiết lập các biến môi trường. Chúng được truyền theo yêu cầu 32. Thêm vào .dev.vars của bạn những thông tin sau: ứng dụng/my-remix-cloudflare-app/.dev.vars DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres" 33. Thực hiện Dự án Phối lại! Khởi chạy phiên bản postgres (nếu chưa sẵn sàng) docker-compose up -d Khởi động dự án pnpm turbo dev Trường hợp sử dụng nâng cao - CQRS trong GetLoadContext trong Cloudflare Workers. Trong các dự án của mình, tôi có xu hướng triển khai , Điều này nằm ngoài phạm vi của hướng dẫn này. mẫu CQRS 2. Tuy nhiên, trong bối cảnh tải, tôi có xu hướng chèn một trình trung gian (và một thông báo cookie flash) để tách toàn bộ Ứng dụng Remix khỏi logic kinh doanh của tôi. Nó trông giống như thế này: 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, }; }; Lưu ý rằng mã dispatch bị bỏ qua. Bạn có thể tìm hiểu thêm về nó trong bài viết của tôi về cách tăng gấp 10 lần trải nghiệm phát triển TypeScript của bạn . tại đây Tôi có thể loại bỏ Remix hoặc sử dụng một trình tiêu dùng khác mà không cần thay đổi mã của mình. Nhưng…. Có một thách thức nữa khi bạn làm việc trong cấu trúc monorepo bằng cách sử dụng turborepo. Nếu bạn nhập tệp TypeScript từ một gói trong ngữ cảnh tải, giả sử Vite sẽ trả về lỗi cho biết tệp có phần mở rộng không xác định và không biết cách xử lý tệp đó. @repo/db .ts Điều này xảy ra vì load-context + workspaces nằm ngoài biểu đồ nhập chính của trang web, khiến các tệp TypeScript không được sử dụng. Mẹo là sử dụng và tải nó gọi Vite, điều này sẽ hiệu quả. Điều này quan trọng vì nó khắc phục được những hạn chế sau: tsx trước khi Các gói phụ thuộc của Cloudflare. Các gói phụ thuộc của Cloudflare và việc xây dựng trước Trước hết, đó là bước mà tôi muốn tránh vì nó có nghĩa là tôi phải giới thiệu một bước xây dựng cho từng gói, nghĩa là phải cấu hình nhiều hơn. May mắn thay, điều này không hiệu quả với Cloudflare Pages. Các thư viện cụ thể, chẳng hạn như Postgres, sẽ phát hiện thời gian chạy và kéo gói cần thiết. Có một giải pháp thay thế: Chúng ta có thể sử dụng tsx để tải tất cả các tệp TypeScript và biên dịch chúng trước khi thực thi. Bạn có thể cho rằng đây là bước dựng trước, nhưng vì nó vẫn ở cấp độ kho lưu trữ của bản phối lại nên tôi không thấy có vấn đề gì đáng kể với cách tiếp cận này. Để giải quyết vấn đề này, chúng ta thêm tsx làm phụ thuộc: pnpm add tsx -D --filter=@repo/my-remix-cloudflare-app Và sau đó, chúng ta cần sửa đổi và thêm quy trình tsx vào từng tập lệnh phối lại của mình: package.json { "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" } } Thêm vào Tạo một tập tin .npmrc Trong trường hợp bạn gặp sự cố khi thêm các gói cục bộ bằng dòng lệnh, bạn có thể tạo tệp trong thư mục gốc của dự án. .npmrc .npmrc link-workspace-packages= true prefer-workspace-packages=true Điều này sẽ yêu cầu pnpm sử dụng các gói không gian làm việc trước. Cảm ơn từ Reddit đã giúp tôi tạo tệp .nprmc ZoWnx Những cạm bẫy - Cẩn thận khi đặt tên và trong các tệp của bạn. Ngay cả khi nó nằm trong một thư viện riêng. Remix sử dụng những tên này để xác định xem đó là tệp máy khách hay máy chủ. Dự án không được biên dịch theo từng kho lưu trữ nên sẽ gây ra lỗi nhập! .client .server Nếu bạn gặp sự cố với các gói đa nền tảng như Postgres, cài đặt ở cấp độ không gian làm việc sẽ tốt hơn. Nó sẽ phát hiện ra lệnh nhập thích hợp. Cài đặt trực tiếp trong kho lưu trữ @repo/db sẽ bị hỏng khi nhập vào Remix. Vậy là xong rồi các bạn ơi!!! Kho lưu trữ GitHub Bạn có thể truy cập vào . bản triển khai đầy đủ tại đây Theo dõi tôi trên mạng xã hội! Tôi đang xây dựng một kỹ sư thử nghiệm tự động để phát hiện 1% lỗi trong quá trình sản xuất. Tôi chia sẻ tiến trình của mình về: X/Twitter @javiasilis Linkedin @javiasilis