नीचे दिए गए नुकसान वाले अनुभाग को अवश्य पढ़ें!
टिप्पणी:
libs
और packages
निर्देशिकाओं के बाहर होगा।
pnpm dlx create-turbo@latest
अपनी मोनोरेपो निर्देशिका पर, pnpm-workspace.yaml
बनाएं।
इसके अंदर जोड़ें:
packages: - "apps/*" - "libs/*"
यह pnpm को बताएगा कि सभी रिपॉजिटरी apps
और libs
अंदर होंगी। ध्यान दें कि libs
या packages
(जैसा कि आपने कहीं और देखा होगा) का उपयोग करना कोई मायने नहीं रखता।
pnpm init
{ "name": "@repo/main", "version": "1.0.0", "scripts": {}, "keywords": [], "author": "", "license": "ISC" }
name:@repo/main
यह हमें बताता है कि यह एप्लिकेशन की मुख्य प्रविष्टि है। आपको किसी विशेष परंपरा का पालन करने या @
उपसर्ग का उपयोग करने की आवश्यकता नहीं है। लोग इसे स्थानीय/दूरस्थ पैकेजों से अलग करने या इसे किसी संगठन में समूहीकृत करना आसान बनाने के लिए इसका उपयोग करते हैं।
turbo.json
फ़ाइल बनाएँ: { "$schema": "//turbo.build/schema.json", "tasks": { "build": {}, "dev": { "cache": false, "persistent": true }, "start": { "dependsOn": ["^build"], "persistent": true }, "preview": { "cache": false, "persistent": true }, "db:migrate": {} } }
टर्बो.json फ़ाइल टर्बो रेपो को बताती है कि हमारे आदेशों की व्याख्या कैसे की जाए। tasks
कुंजी के अंदर जो कुछ भी है वह सभी package.json में पाए जाने वाले से मेल खाएगा।
उदाहरण: dev
कमांड को turbo dev
द्वारा ट्रिगर किया जाएगा, और यह उन सभी पैकेजों को निष्पादित करेगा जो dev
package.json में पाए जाते हैं। यदि आप इसे turbo में शामिल नहीं करते हैं, तो यह निष्पादित नहीं होगा।
apps
फ़ोल्डर बनाएँ mkdir apps
apps
फ़ोल्डर में रीमिक्स ऐप बनाएं (या मौजूदा ऐप को स्थानांतरित करें) npx create-remix --template edmundhung/remix-worker-template
जब यह आपसे Install any dependencies with npm
के लिए कहता है तो 'नहीं' कहें।
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" }
apps/<app>/package.json
से Dependencies और devDependencies को रूट के 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" } }
pnpm add turbo -D -w
-w
ध्वज pnpm को इसे कार्यक्षेत्र रूट पर स्थापित करने के लिए कहता है।
scripts
में dev
कमांड जोड़ें
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 } }
pnpm dev
चलाकर सत्यापित करें कि सब कुछ काम कर रहा है pnpm dev
mkdir -p libs/config libs/db libs/utils
src/index.ts
जोड़ें। touch libs/config/src/index.ts libs/db/src/index.ts libs/utils/src/index.ts
libs/config/package.json
फ़ाइल में निम्नलिखित जोड़ें: { "name": "@repo/config", "version": "1.0.0", "type": "module", "exports": { ".": { "import": "./src/index.ts", "default": "./src/index.ts" } } }
libs/db/package.json
के लिए भी यही करें: { "name": "@repo/db", "version": "1.0.0", "exports": { ".": { "import": "./src/index.ts", "default": "./src/index.ts" } } }
libs/utils/package.json
: { "name": "@repo/utils", "version": "1.0.0", "exports": { ".": { "import": "./src/index.ts", "default": "./src/index.ts" } } }
टिप्पणियाँ:
pnpm add drizzle-orm drizle-kit --filter=@repo/db
वर्कस्पेस स्तर पर Postgres स्थापित करें। नुकसान अनुभाग देखें ।
pnma add postgres -w
टिप्पणियाँ:
--filter=@repo/db
फ्लैग pnpm को पैकेज को db रिपोजिटरी में जोड़ने के लिए कहता है। pnpm add dotenv -w
नोट्स-w
फ्लैग pnpm को रूट के package.json पर इसे स्थापित करने के लिए कहता है pnpm add @repo/config -r --filter=!@repo/config
टिप्पणियाँ :
-r
फ्लैग pnpm को पैकेज को सभी रिपॉजिटरी में जोड़ने के लिए कहता है।--filter=!
ध्वज pnpm को कॉन्फ़िगरेशन रिपोजिटरी को बाहर करने के लिए कहता है।!
पर ध्यान दें यदि pnpm रिपोजिटरी से पैकेज खींच रहा है, तो हम प्रोजेक्ट के रूट पर एक .npmrc
फ़ाइल बना सकते हैं।
link-workspace-packages= true prefer-workspace-packages=true
tsconfig.json
कॉन्फ़िगर करें
libs/config
के अंदर tsconfig.lib.json
को तत्काल बनाएं:
touch "libs/config/tsconfig.base.lib.json"
{ "$schema": "//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, } }
// 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" } }
libs/db
और libs/utils
के लिए साझा tsconfig.json
उपयोग करें libs/db
और libs/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 को संदर्भित करने के लिए पथ के रूप में किया जाता है। pnpm add tsx -D --filter=@repo/db
libs/db
डायरेक्टरी में एक खाली .env जोड़ें touch "libs/db/.env"
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres" NODE_ENV="development" MODE="node"
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
चलाएँ।
इस कोड को libs/utils/src/index.ts
फ़ाइल में जोड़ें:
// libs/utils/src/index.ts export function hellowWorld() { return "Hello World!"; }
pnpm add @repo/db --filter=@repo/my-remix-cloudflare-app
प्रोजेक्ट के मूल में 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 //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 को अलग से चलने के लिए कहता है ताकि आप फिर से अपने टर्मिनल तक पहुंच सकें।
अब, libs/db रिपोजिटरी पर जाएँ और db:generate
चलाएँ।
cd `./libs/db` && pnpm db:generate
db:generate
एक उपनाम है: drizzle-kit generate
libs/db रिपोजिटरी पर जाएं (यदि आप वहां नहीं हैं) और db:generate
चलाएं।
cd `./libs/db` && pnpm db:migrate
db:migrate
एक उपनाम है: dotenv tsx ./drizzle/migrate
// 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} />; }
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres"
docker-compose up -d
pnpm turbo dev
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 गुना कैसे बढ़ाया जाए ।
यदि आप लोड-संदर्भ के भीतर किसी पैकेज से टाइपस्क्रिप्ट फ़ाइल आयात करते हैं, मान लीजिए @repo/db
Vite एक त्रुटि लौटाएगा कि एक्सटेंशन .ts
वाली फ़ाइल अज्ञात है, और यह नहीं जानता कि इसे कैसे संसाधित किया जाए।
तरकीब यह है कि tsx
उपयोग करें और Vite को कॉल करने से पहले इसे लोड करें, जो काम करेगा। यह महत्वपूर्ण है क्योंकि यह निम्नलिखित सीमाओं को पार करता है:
क्लाउडफ्लेयर पैकेज निर्भरताएँ और प्री-बिल्डिंग
सबसे पहले, यह वह चरण था जिसे मैं टालने की कोशिश कर रहा था, क्योंकि इसका मतलब था कि मुझे प्रत्येक पैकेज के लिए एक निर्माण चरण शुरू करना होगा, जिसका मतलब था अधिक कॉन्फ़िगरेशन।
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
फ़ाइल बना सकते हैं।
link-workspace-packages= true prefer-workspace-packages=true
यह pnpm को पहले वर्कस्पेस पैकेजों का उपयोग करने के लिए कहेगा।
अपनी फ़ाइलों में .client
और .server
नाम देते समय सावधान रहें। भले ही यह किसी अलग लाइब्रेरी में हो। रीमिक्स इनका उपयोग यह निर्धारित करने के लिए करता है कि यह क्लाइंट या सर्वर फ़ाइल है। प्रोजेक्ट को रिपॉजिटरी के अनुसार संकलित नहीं किया गया है, इसलिए यह एक आयात त्रुटि फेंक देगा!
बस इतना ही, मित्रों!!!