ভূমিকা
কেন মনোরেপো?
আজকাল, সফটওয়্যার ডেভেলপমেন্টের দ্রুত বিবর্তন অস্বীকার করা যায় না। দলগুলি ক্রমবর্ধমান হচ্ছে, প্রকল্পগুলি আরও জটিল হয়ে উঠছে। কোম্পানিগুলি অনেকগুলি টুকরো নিয়ে গঠিত একটি বিতরণকৃত কোডবেস বজায় রাখার জন্য উল্লেখযোগ্য সম্পদ ব্যয় করে। মনোরেপোতে প্রবেশ করুন - একটি একক, একীভূত সংগ্রহস্থল যা আপনার সমস্ত কোড একত্রিত করে। একটি প্রবণতা হওয়া থেকে দূরে, মনোরেপো সম্প্রতি পুরো কোডবেসকে এক জায়গায় রাখার জন্য একটি স্থাপত্য পদ্ধতিতে পরিণত হয়েছে। দলগুলি উন্নত প্রসঙ্গ ভাগাভাগি, মসৃণ সহযোগিতা এবং একটি সরঞ্জাম পায় যা স্বাভাবিকভাবেই কোড পুনঃব্যবহারকে উৎসাহিত করে।
সুতার কর্মক্ষেত্র স্থাপন করা হচ্ছে
দ্রষ্টব্য: এই প্রবন্ধ জুড়ে, যখনই "Yarn" উল্লেখ করা হয়েছে, এটি বিশেষভাবে Yarn v4-কে বোঝায়—যার সর্বশেষ সংস্করণ উন্নত ক্ষমতা এবং উন্নত কর্মক্ষমতা প্রদান করে।
সুতার কর্মক্ষেত্র কী?
ওয়ার্কস্পেস হল মনোরেপোর প্যাকেজ, যাকে প্রায়শই প্যাকেজ বলা হয়। এগুলি আপনাকে একটি একক সংগ্রহস্থলে অনায়াসে একাধিক প্যাকেজ পরিচালনা করতে সাহায্য করে। ওয়ার্কস্পেসের সাহায্যে আপনি যা করতে পারেন:
নির্ভরতা সহজেই ভাগ করুন:
আপনার প্রকল্প জুড়ে সাধারণ নির্ভরতাগুলি নির্বিঘ্নে ভাগ করুন।
নির্ভরতা ব্যবস্থাপনা সহজ করুন:
সুতা স্বয়ংক্রিয়ভাবে স্থানীয় প্যাকেজগুলিকে সংযুক্ত করে, ডুপ্লিকেশন হ্রাস করে এবং বিকাশ সহজ করে।
ইনস্টলেশন ত্বরান্বিত করুন:
Yarn এর কর্মক্ষমতা অপ্টিমাইজেশন এবং ক্যাশিং প্রক্রিয়া (অর্থাৎ, বিল্ট-ইন plug'n'play ) থেকে উপকৃত হন।
মনোরেপোর উপর নিয়ন্ত্রণ উন্নত করুন:
সীমাবদ্ধতা (নিয়ম) সংজ্ঞায়িত করুন এবং ধারাবাহিকতা বজায় রাখার জন্য কয়েক ডজন উপলব্ধ প্লাগইন ব্যবহার করুন।
যদিও Yarn এই প্রবন্ধের জন্য নির্বাচিত ম্যানেজার, তার সরলতা, গতি এবং বিস্তৃত কনফিগারেশন বিকল্পগুলির জন্য ধন্যবাদ - এটি মনে রাখা গুরুত্বপূর্ণ যে সঠিক পছন্দটি আপনার প্রকল্পের নির্দিষ্ট চাহিদা, দলের পছন্দ এবং সামগ্রিক কর্মপ্রবাহের উপর নির্ভর করে। উদাহরণস্বরূপ, PNPM এবং Turborepo হল অন্যান্য আধুনিক সরঞ্জাম যা বিস্তৃত বৈশিষ্ট্য সরবরাহ করে।
প্রাথমিক কনফিগারেশন
সুতা সেটআপ একটি সহজ প্রক্রিয়া। আপনার প্রকল্পে সুতা ইনস্টল এবং কনফিগার করার জন্য অফিসিয়াল নির্দেশিকা অনুসরণ করুন: সুতা ইনস্টলেশন নির্দেশিকা ।
ইনস্টলেশন সম্পন্ন হলে, কনফিগারেশনে যাওয়া যাক। যেহেতু আমরা plug'n'play ব্যবহার করছি, তাই আপনাকে নিশ্চিত করতে হবে যে আপনার IDE সঠিকভাবে নির্ভরতা সনাক্ত করতে পারে। যদি আপনি VSCode ব্যবহার করেন, তাহলে চালান:
# Typescript is required for VSCode SDK to set up correctly yarn add -D typescript@^5 yarn dlx @yarnpkg/sdks vscode
যদি আপনি অন্য কোনও কোড এডিটর ব্যবহার করেন, তাহলে এখানে উপলব্ধ SDK গুলি পরীক্ষা করুন: Yarn Editor SDK গুলি ।
এই মুহুর্তে, আপনি Yarn ব্যবহার শুরু করার জন্য প্রস্তুত।
মনোরেপো কাঠামো সংগঠিত করা
এখন প্যাকেজ ম্যানেজার কনফিগার করা হয়েছে, এখন একটি স্কেলেবল প্রজেক্ট অর্গানাইজেশন ডিজাইন করার সময়। একটি স্পষ্ট, সুনির্দিষ্ট কাঠামো কেবল রিপোজিটরি নেভিগেট করা সহজ করে না বরং কোড পুনঃব্যবহারের উন্নতিও করে। এই উদাহরণে, আমরা কোডবেসকে তিনটি প্রধান বিভাগে ভাগ করব:
অ্যাপস :
- ক্লায়েন্ট: চূড়ান্ত, স্থাপনযোগ্য ক্লায়েন্ট পণ্য ধারণ করে।
- সার্ভার: চূড়ান্ত, স্থাপনযোগ্য সার্ভার পণ্য ধারণ করে।
বৈশিষ্ট্য :
- ক্লায়েন্ট: স্বতন্ত্র UI উইজেটের জন্য।
- সার্ভার: স্বতন্ত্র ব্যাকএন্ড ব্যবসায়িক লজিক অংশগুলির জন্য।
লিবস :
ডিজাইন সিস্টেমের উপাদান, ধ্রুবক, সম্পদ এবং ইউটিলিটিগুলির মতো ভাগ করা কোডগুলি অন্তর্ভুক্ত করে। এটি পুনর্ব্যবহারযোগ্য যুক্তি সংরক্ষণের জন্য প্রসঙ্গ-মুক্ত অঞ্চল।
এই ফোল্ডার কাঠামোর শক্তি প্রদর্শনের জন্য, আসুন Yarn এর ওয়ার্কস্পেস তালিকায় এই প্রধান ফোল্ডারগুলি যুক্ত করে শুরু করি। আপনার root package.json এ, নিম্নলিখিতগুলি যুক্ত করুন:
"workspaces": [ "apps/**", "features/**", "libs/**" ]
এই কনফিগারেশনটি Yarn-কে এই ফোল্ডারগুলিতে থাকা প্যাকেজগুলিকে স্থানীয় প্যাকেজ হিসাবে বিবেচনা করতে বলে। পরবর্তী ইনস্টলেশনগুলি নিশ্চিত করবে যে প্রতিটি প্যাকেজের জন্য নির্ভরতা সঠিকভাবে সেট আপ এবং লিঙ্ক করা হয়েছে।
বুটস্ট্র্যাপিং কোডবেস
এই বিভাগে, আমরা একটি ন্যূনতম কোডবেস উদাহরণের মধ্য দিয়ে যাব যা মনোরেপো বুটস্ট্র্যাপ করার পদ্ধতি ব্যাখ্যা করবে। সম্পূর্ণ কোড স্নিপেট অন্তর্ভুক্ত করার পরিবর্তে, আমি এই নিবন্ধের জন্য বিশেষভাবে তৈরি করা সংগ্রহস্থলের সম্পূর্ণ ফাইলগুলির লিঙ্ক সহ ছোট উদাহরণ প্রদান করব।
বুটস্ট্র্যাপিং সার্ভার অ্যাপ্লিকেশন
আমরা ব্যবহারকারী প্রমাণীকরণের জন্য একটি সহজ এক্সপ্রেস API দিয়ে শুরু করি। এই সার্ভার অ্যাপ্লিকেশনটি একটি একক এন্ডপয়েন্ট ( /auth/signIn
) প্রকাশ করে যা অন্য প্যাকেজ থেকে একটি হ্যান্ডলার ব্যবহার করে।
import express from "express"; import cors from "cors"; import { signInHandler } from "@robust-monorepo-yarn-nx-changesets/sign-in-handler"; const app = express(); const port = process.env.PORT || 1234; app.use(express.json()); app.use( cors({ origin: process.env.CORS_ORIGIN || "http://localhost:3000", }) ); app.post("/auth/signIn", signInHandler); app.listen(port, () => { console.log(`Server is running at http://localhost:${port}`); });
আপনি দেখতে পাচ্ছেন, /auth/signIn
এন্ডপয়েন্ট অন্য প্যাকেজ থেকে আমদানি করা একটি হ্যান্ডলার ব্যবহার করে। এটি আমাদের পরবর্তী উপাদানে নিয়ে আসে: সার্ভার বৈশিষ্ট্য।
বুটস্ট্র্যাপিং সার্ভার বৈশিষ্ট্য
সার্ভার বৈশিষ্ট্যটি প্রমাণীকরণ যুক্তিকে ধারণ করে। এই প্যাকেজে, আমরা সাইন-ইন হ্যান্ডলার সংজ্ঞায়িত করি, যা libs থেকে একটি ভাগ করা বৈধতা ইউটিলিটি ব্যবহার করে।
import type { RequestHandler } from "express"; import { passwordValidator, usernameValidator, } from "@robust-monorepo-yarn-nx-changesets/validator"; const signInHandler: RequestHandler = (req, res) => { if (!req.body) { res.status(422).send("Request body is missing"); return; } if (typeof req.body !== "object") { res.status(422).send("Request body expected to be an object"); return; } const { username, password } = req.body; const usernameValidationResult = usernameValidator(username); if (typeof usernameValidationResult === "string") { res .status(422) .send("Invalid username format: " + usernameValidationResult); return; } const passwordValidationResult = passwordValidator(password); if (typeof passwordValidationResult === "string") { res .status(422) .send("Invalid password format: " + passwordValidationResult); return; } // Emulate a successful sign-in if (username === "test" && password === "test1234") { res.status(200).send("Sign in successful"); return; } return res.status(422).send("Username or password is incorrect"); }; export default signInHandler;
এই পদ্ধতিটি তার নিজস্ব প্যাকেজের মধ্যে প্রমাণীকরণ লজিককে সারসংক্ষেপ করে, যা এটিকে স্বাধীনভাবে বিকাশ এবং রক্ষণাবেক্ষণের অনুমতি দেয়। লক্ষ্য করুন কিভাবে ভ্যালিডেটর ইউটিলিটিগুলি শেয়ার্ড lib থেকে আমদানি করা হয়।
বুটস্ট্র্যাপিং ক্লায়েন্ট অ্যাপ্লিকেশন
এরপর, ক্লায়েন্টের দিকটি দেখা যাক। আমাদের ক্লায়েন্ট অ্যাপ্লিকেশনে, আমরা একটি সহজ ওয়েবসাইট তৈরি করি যা সার্ভার API ব্যবহার করে ব্যবহারকারীর প্রমাণীকরণ সক্ষম করে।
"use client"; import { SignInForm } from "@robust-monorepo-yarn-nx-changesets/sign-in-form"; const API_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:1234"; export default function Home() { const handleSubmit = async (username: string, password: string) => { const response = await fetch(`${API_URL}/auth/signIn`, { method: "POST", body: JSON.stringify({ username, password }), headers: { "Content-Type": "application/json", }, }); if (response.status === 200) { alert("Sign in successful"); return; } if (response.status === 422) { alert("Sign in failed: " + (await response.text())); return; } alert("Sign in failed"); }; return ( <div className="w-full h-screen overflow-hidden flex items-center justify-center"> <SignInForm onSubmit={handleSubmit} /> </div> ); }
এই উদাহরণে, SignInForm
কম্পোনেন্টটি একটি ক্লায়েন্ট ফিচার প্যাকেজ থেকে আমদানি করা হয়েছে, যা আমাদের চূড়ান্ত কম্পোনেন্টে নিয়ে যায়।
বুটস্ট্র্যাপিং ক্লায়েন্ট বৈশিষ্ট্য
ক্লায়েন্ট ফিচার প্যাকেজটি শেয়ার্ড ভ্যালিডেশন লজিকের সাথে প্রমাণীকরণ ফর্ম প্রদান করে। এটি কোডের নকল এড়ায় এবং ধারাবাহিকতা নিশ্চিত করে।
import { passwordValidator, usernameValidator, } from "@robust-monorepo-yarn-nx-changesets/validator"; interface SignInFormProps { onSubmit: (username: string, password: string) => void; } const SignInForm = ({ onSubmit }: SignInFormProps) => { const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); const username = (event.currentTarget[0] as HTMLInputElement).value; const usernameValidationResult = usernameValidator(username); if (typeof usernameValidationResult === "string") { alert(usernameValidationResult); return; } const password = (event.currentTarget[1] as HTMLInputElement).value; const passwordValidationResult = passwordValidator(password); if (typeof passwordValidationResult === "string") { alert(passwordValidationResult); return; } onSubmit(username!, password!); }; return ( <form onSubmit={handleSubmit}> <input type="text" placeholder="Username" /> <input type="password" placeholder="Password" /> <button type="submit">Submit</button> </form> ); }; export default SignInForm;
এখানে, আমরা আবার আমাদের শেয়ার্ড লিব থেকে ভ্যালিডেটরের ব্যবহার দেখতে পাচ্ছি, যা নিশ্চিত করে যে ভ্যালিডেশন লজিক কেন্দ্রীভূত এবং সহজেই রক্ষণাবেক্ষণ করা হচ্ছে।
আমাদের ন্যূনতম কোডবেস উদাহরণের জন্য এটিই যথেষ্ট। মনে রাখবেন যে এই কোডটি একটি সরলীকৃত চিত্রণ যা একটি মনোরেপোতে অ্যাপস, বৈশিষ্ট্য এবং লিবসের মধ্যে মৌলিক কাঠামো এবং আন্তঃসংযোগ প্রদর্শনের জন্য তৈরি। আপনার প্রকল্পের নির্দিষ্ট প্রয়োজনীয়তার সাথে মানানসই করার জন্য আপনি প্রয়োজন অনুসারে এই উদাহরণগুলি প্রসারিত করতে পারেন।
NX দিয়ে স্ক্রিপ্ট চালানো
মনোরেপোতে স্ক্রিপ্ট পরিচালনা করা চ্যালেঞ্জিং হতে পারে। যদিও Yarn আপনাকে বিভিন্ন শর্ত ব্যবহার করে একাধিক প্যাকেজ জুড়ে স্ক্রিপ্ট চালানোর অনুমতি দেয়, তবে আরও সূক্ষ্ম নিয়ন্ত্রণের জন্য কাস্টম স্ক্রিপ্টিং প্রয়োজন হতে পারে। এখানেই NX আসে: এটি দক্ষ, লক্ষ্যযুক্ত স্ক্রিপ্ট সম্পাদনের জন্য একটি আউট-অফ-দ্য-বক্স সমাধান প্রদান করে।
NX এর ভূমিকা
NX হল উন্নত CI ক্ষমতা সহ মনোরেপোর জন্য অপ্টিমাইজ করা একটি বিল্ড সিস্টেম। NX এর সাহায্যে আপনি যা করতে পারেন:
- সমান্তরালভাবে দক্ষতার সাথে কাজগুলি সম্পাদন করুন : আপনার বিল্ডগুলিকে দ্রুততর করার জন্য কনকারেন্সি ব্যবহার করুন।
- নির্ভরতা সম্পর্ক চিহ্নিত করুন : প্যাকেজ এবং স্ক্রিপ্টের মধ্যে সংযোগগুলি বুঝুন।
- ক্যাশে স্ক্রিপ্ট কার্যকর করার ফলাফল : আউটপুট ক্যাশে করে অপ্রয়োজনীয় কাজ এড়িয়ে চলুন।
- প্লাগইনগুলির সাথে আচরণ কাস্টমাইজ করুন: প্লাগইনগুলির একটি সমৃদ্ধ ইকোসিস্টেমের মাধ্যমে কার্যকারিতা প্রসারিত করুন।
লক্ষ্যযুক্ত স্ক্রিপ্ট সম্পাদন
NX এর ক্ষমতা কাজে লাগানোর জন্য, আমাদের প্রথমে আমাদের স্ক্রিপ্টগুলির জন্য নিয়মের একটি সেট সংজ্ঞায়িত করার জন্য একটি nx.json
ফাইল তৈরি করতে হবে। নীচে একটি উদাহরণ কনফিগারেশন দেওয়া হল:
{ "targetDefaults": { "build": { "dependsOn": [ "^build" ], "outputs": [ "{projectRoot}/dist" ], "cache": true }, "typecheck": { "dependsOn": [ "^build", "^typecheck" ] }, "lint": { "dependsOn": [ "^build", "^lint" ] } }, "defaultBase": "main" }
সরল ইংরেজিতে, এই কনফিগারেশনের অর্থ হল:
নির্মাণ করুন
একটি প্যাকেজের
build
স্ক্রিপ্ট তার নির্ভরতাগুলির সফল বিল্ডের উপর নির্ভর করে এবং এর আউটপুট ক্যাশে করা হয়।টাইপচেক
একটি প্যাকেজের
typecheck
স্ক্রিপ্ট তার নির্ভরতার বিল্ড এবং টাইপচেক স্ক্রিপ্ট উভয়ের উপর নির্ভর করে।লিন্ট
একটি প্যাকেজের জন্য
lint
স্ক্রিপ্ট তার নির্ভরতার বিল্ড এবং লিন্ট স্ক্রিপ্ট উভয়ের উপর নির্ভর করে।
এখন, package.json
এ স্ক্রিপ্ট যোগ করা যাক:
"scripts": { "build:all": "yarn nx run-many -t build", "build:affected": "yarn nx affected -t build --base=${BASE:-origin/main} --head=${HEAD:-HEAD}", "typecheck:all": "yarn nx run-many -t typecheck", "typecheck:affected": "yarn nx affected -t typecheck --base=${BASE:-origin/main} --head=${HEAD:-HEAD}", "lint:all": "yarn nx run-many -t lint", "lint:affected": "yarn nx affected -t lint --base=${BASE:-origin/main} --head=${HEAD:-HEAD}", "quality:all": "yarn nx run-many --targets=typecheck,lint", "quality:affected": "yarn nx affected --targets=typecheck,lint --base=${BASE:-origin/main} --head=${HEAD:-HEAD}" }
এখানে, আমরা চার ধরণের এক্সিকিউশন স্ক্রিপ্ট সংজ্ঞায়িত করি:
বিল্ড: একটি প্যাকেজ তৈরি করে।
টাইপচেক: প্যাকেজের ধরণ পরীক্ষা করে।
লিন্ট: একটি প্যাকেজ লিন্ট করে।
গুণমান: টাইপচেক এবং লিন্ট উভয়ই চালায়।
প্রতিটি স্ক্রিপ্টের দুটি ভিন্নতা রয়েছে:
- all: সকল প্যাকেজে স্ক্রিপ্ট চালায়।
- প্রভাবিত: শুধুমাত্র সাম্প্রতিক পরিবর্তন দ্বারা প্রভাবিত প্যাকেজগুলিতে স্ক্রিপ্টটি চালায়।
BASE
এবংHEAD
পরিবেশ ভেরিয়েবলগুলি আপনাকে একটি পরিসর নির্দিষ্ট করতে দেয় (ডিফল্টভাবেorigin/main
এবং বর্তমানHEAD
তে), যা পুল অনুরোধগুলিতে গ্রানুলার এক্সিকিউশন সক্ষম করে। এটি সময় এবং সম্পদ উল্লেখযোগ্যভাবে সাশ্রয় করতে পারে।
সার্কুলার নির্ভরতা ব্যবস্থাপনা
NX একটি নির্ভরতা গ্রাফ তৈরি করার জন্য একটি অন্তর্নির্মিত কমান্ডও প্রদান করে, যা নির্ভরতা চক্র সনাক্তকরণে সাহায্য করতে পারে। নিম্নলিখিত স্ক্রিপ্টটি বৃত্তাকার নির্ভরতা পরীক্ষা করার জন্য NX গ্রাফ আউটপুট ব্যবহার করে এবং যদি কোনও পাওয়া যায় তবে তা ব্যর্থ হয়।
scripts/check-circulardeps.mjs
এ নিম্নলিখিত বিষয়বস্তু সহ একটি ফাইল তৈরি করুন:
import { execSync } from "child_process"; import path from "path"; import fs from "fs"; const hasCycle = (node, graph, visited, stack, path) => { if (!visited.has(node)) { visited.add(node); stack.add(node); path.push(node); const dependencies = graph.dependencies[node] || []; for (const dep of dependencies) { const depNode = dep.target; if ( !visited.has(depNode) && hasCycle(depNode, graph, visited, stack, path) ) { return true; } if (stack.has(depNode)) { path.push(depNode); return true; } } } stack.delete(node); path.pop(); return false; }; const getGraph = () => { const cwd = process.cwd(); const tempOutputFilePath = path.join(cwd, "nx-graph.json"); execSync(`nx graph --file=${tempOutputFilePath}`, { encoding: "utf-8", }); const output = fs.readFileSync(tempOutputFilePath, "utf-8"); fs.rmSync(tempOutputFilePath); return JSON.parse(output).graph; }; const checkCircularDeps = () => { const graph = getGraph(); const visited = new Set(); const stack = new Set(); for (const node of Object.keys(graph.dependencies)) { const path = []; if (hasCycle(node, graph, visited, stack, path)) { console.error("🔴 Circular dependency detected:", path.join(" → ")); process.exit(1); } } console.log("✅ No circular dependencies detected."); }; checkCircularDeps();
এই স্ক্রিপ্ট:
- একটি নির্ভরতা গ্রাফ তৈরি করতে NX কমান্ড কার্যকর করে।
- একটি অস্থায়ী JSON ফাইল থেকে গ্রাফটি পড়ে।
- চক্রের জন্য পুনরাবৃত্তিমূলকভাবে পরীক্ষা করে।
- একটি ত্রুটি লগ করে এবং যদি একটি বৃত্তাকার নির্ভরতা সনাক্ত করা হয় তবে প্রস্থান করে।
সুতার সীমাবদ্ধতা ব্যবহার করে নির্ভরতা যাচাই করা
প্রকল্পগুলি বৃদ্ধির সাথে সাথে, নির্ভরতা জুড়ে ধারাবাহিকতা বজায় রাখা চ্যালেঞ্জিং হয়ে ওঠে। অপ্রয়োজনীয় প্রযুক্তিগত ঋণ এড়াতে নির্ভরতা, নোড সংস্করণ এবং অন্যান্য কনফিগারেশনের উপর কঠোর নিয়ম প্রয়োগ করা অপরিহার্য। Yarn Constraints এই বৈধতাগুলিকে স্বয়ংক্রিয় করার একটি উপায় প্রদান করে।
সুতার সীমাবদ্ধতা বোঝা
Yarn Constraints হল আপনার monorepo-তে প্যাকেজগুলির জন্য নিয়মের সেট। এগুলি ব্যবহারের উল্লেখযোগ্য সুবিধা হল আপনি এই নিয়মগুলির পরিচালক। উদাহরণস্বরূপ, আপনি একটি নিয়ম তৈরি করতে পারেন যাতে সমস্ত প্যাকেজকে একই React সংস্করণ ব্যবহার করতে বাধ্য করা হয়। একবার এটি সেট হয়ে গেলে, যখন কোনও হোস্ট অ্যাপ্লিকেশন উচ্চতর React সংস্করণ সহ কোনও feature/lib ব্যবহার করতে না পারে তখন আপনি কখনই কোনও সমস্যার সম্মুখীন হবেন না।
একটি বৃহৎ মনোরেপোকে নির্ভরতার একটি নতুন প্রধান সংস্করণে স্থানান্তর করা জটিল হতে পারে, তবে সীমাবদ্ধতা ব্যবহার করলে শেষ পর্যন্ত পুরো প্রকল্পে ধারাবাহিকতা এবং স্থিতিশীলতা আসে।
ধারাবাহিকতা প্রয়োগ করা
আমাদের উদাহরণ রিপোজিটরিতে, আমরা নিম্নলিখিতগুলির জন্য ধারাবাহিকতা জোরদার করার জন্য একটিyarn.config.cjs ফাইল ব্যবহার করি:
নোড সংস্করণ
সুতা সংস্করণ
নির্ভরতা সংস্করণ
ট্রানজিশনের সময় নমনীয়তা নিশ্চিত করার জন্য, আপনি কিছু নির্দিষ্ট চেককে সাময়িকভাবে বাইপাস করার জন্য এক্সক্লুশন নির্ধারণ করতে পারেন। উদাহরণস্বরূপ:
const workspaceCheckExclusions = []; const dependencyCheckExclusions = [];
এই ধ্রুবকগুলি আপনাকে বৈধতা প্রক্রিয়া থেকে নির্দিষ্ট কর্মক্ষেত্র বা নির্ভরতা বাদ দিতে দেয়, প্রয়োজনে মসৃণ স্থানান্তর নিশ্চিত করে।
চেঞ্জসেট দিয়ে সংস্করণ পরিচালনা করা
রিপোজিটরির বৃদ্ধির ক্ষেত্রে আপনার আরেকটি সমস্যা হতে পারে তা হল সংস্করণ ব্যবস্থাপনা এবং প্রকাশ। চেঞ্জসেটগুলি এই প্রক্রিয়াটি স্বয়ংক্রিয় করার জন্য একটি মার্জিত সমাধান প্রদান করে, যাতে প্রতিটি পরিবর্তন ট্র্যাক, সংস্করণ এবং প্রকাশ করা হয়।
চেঞ্জসেটের ভূমিকা
চেঞ্জসেটস হল একটি ওপেন-সোর্স টুল যা মনোরেপো রিপোজিটরিতে ভার্সনিং পরিচালনা করার জন্য ডিজাইন করা হয়েছে। এটি পরিবর্তনের উদ্দেশ্য ধারণ করে ছোট, মানুষের পঠনযোগ্য নথিতে ভাগ করে পরিবর্তনগুলির ট্র্যাক রাখার প্রক্রিয়াটিকে সহজ করে তোলে। এই নথিগুলিকে চেঞ্জসেট বলা হয়। মূল সুবিধাগুলির মধ্যে রয়েছে:
ডকুমেন্টেশন সাফ করুন
প্রতিটি পরিবর্তন সেটে করা পরিবর্তনগুলির রূপরেখা দেওয়া হয়, যা ডেভেলপার এবং গ্রাহক উভয়কেই বুঝতে সাহায্য করে যে নতুন রিলিজে কী আশা করা যায়।
দানাদার সংস্করণ নিয়ন্ত্রণ
প্রতিটি প্যাকেজ স্বাধীনভাবে সংস্করণ করা হয়, নিশ্চিত করে যে শুধুমাত্র প্রভাবিত প্যাকেজগুলি আপডেট করা হয়েছে। এটি খালি সংস্করণ বাম্প এবং নির্ভরতা বিরতির ঝুঁকি কমায়।
সহযোগিতা-বান্ধব
যেহেতু প্রতিটি পরিবর্তন একটি পরিবর্তন সেটের মাধ্যমে রেকর্ড করা হয়, তাই দলগুলি প্রকৃত প্রকাশের আগে আপডেটগুলি পর্যালোচনা এবং অনুমোদন করতে পারে।
স্বয়ংক্রিয় রিলিজ
Changesets এর সবচেয়ে শক্তিশালী বৈশিষ্ট্যগুলির মধ্যে একটি হল প্রক্রিয়াটি স্বয়ংক্রিয় করার ক্ষমতা। আপনি Changesets কে আপনার CI/CD পাইপলাইনে একীভূত করতে পারেন এবং ম্যানুয়াল সংস্করণ পরিবর্তন এবং NPM প্রকাশনার কথা ভুলে যেতে পারেন।
উদাহরণ রিপোজিটরিতে release.yaml ওয়ার্কফ্লোটি একবার দেখুন। এতে create-release-pull-request-or-publish
ধাপ রয়েছে। changesets/action GitHub অ্যাকশন দ্বারা সমর্থিত ধাপটি সমস্ত জাদু তৈরি করে। আপনার প্যাকেজ প্রকাশের জন্য আপনাকে কেবল NPM_TOKEN
সেট আপ করতে হবে। তারপর, main
শাখায় প্রতিটি পুশ:
কোন Changeset ডকুমেন্ট আছে কিনা তা পরীক্ষা করুন ।
যদি চেঞ্জসেট ডকুমেন্ট উপস্থিত থাকে, তাহলে অ্যাকশনটি প্রয়োজনীয় ভার্সন বাম্প এবং চেঞ্জলগ আপডেট সহ একটি পুল রিকোয়েস্ট তৈরি করে। যদি কোনও পরিবর্তন সনাক্ত না হয়, তবে কিছুই ঘটে না।
প্রকাশের জন্য কোন প্যাকেজ প্রস্তুত আছে কিনা তা পরীক্ষা করুন ।
যদি প্যাকেজগুলি প্রকাশের জন্য প্রস্তুত থাকে, তাহলে অ্যাকশনটি প্রদত্ত
NPM_TOKEN
ব্যবহার করে নতুন সংস্করণগুলি NPM-এ প্রকাশ করে। যদি প্রকাশের জন্য কোনও প্যাকেজ প্রস্তুত না থাকে, তাহলে অ্যাকশনটি পরিবর্তন না করেই প্রস্থান করে।
এই কাজগুলি স্বয়ংক্রিয় করে, চেঞ্জসেটগুলি নিশ্চিত করে যে আপনার রিলিজগুলি সামঞ্জস্যপূর্ণ এবং নির্ভরযোগ্য, মানুষের ত্রুটির সম্ভাবনা হ্রাস করে এবং আপনার উন্নয়ন কর্মপ্রবাহকে সুগম করে।
GitHub অ্যাকশনের সাথে ওয়ার্কফ্লো ইন্টিগ্রেশন
এই বিভাগটি আমাদের তৈরি করা আর্কিটেকচারের শক্তি কীভাবে কাজে লাগানো যায় তা নিয়ে আলোচনা করবে। GitHub Actions ব্যবহার করে, আমরা PR মানের পরীক্ষা, লাইব্রেরি এবং বৈশিষ্ট্যগুলির জন্য সংস্করণ প্রকাশ এবং অ্যাপ্লিকেশন স্থাপনা স্বয়ংক্রিয় করব। কোডের মান এবং কাজের গ্র্যানুলারিটি বজায় রেখে অটোমেশন সর্বাধিক করার উপর জোর দেওয়া হচ্ছে।
জনসংযোগ মান যাচাই করুন
পুল রিকোয়েস্ট কোড যাতে ধারাবাহিক এবং স্থিতিশীল থাকে তা নিশ্চিত করার জন্য, আমরা একটি ডেডিকেটেড quality.yaml ওয়ার্কফ্লো তৈরি করি। এই ওয়ার্কফ্লোটি বেশ কয়েকটি কাজ সম্পাদন করে, যেমন ম্যানুয়াল সংস্করণ পরিবর্তনগুলি চালু না করা নিশ্চিত করা (যেহেতু সংস্করণটি Changesets দ্বারা পরিচালিত হয়):
- id: check_version name: Check version changes run: | BASE_BRANCH=${{ github.event.pull_request.base.ref }} git fetch origin $BASE_BRANCH CHANGED_FILES=$(git diff --name-only origin/$BASE_BRANCH HEAD) VERSION_CHANGED=false for FILE in $CHANGED_FILES; do if [[ $FILE == */package.json ]]; then if [ -f "$FILE" ]; then HEAD_VERSION=$(grep '"version":' "$FILE" | awk -F '"' '{print $4}') else continue fi HEAD_VERSION=$(cat $FILE | grep '"version":' | awk -F '"' '{print $4}') if git cat-file -e origin/$BASE_BRANCH:$FILE 2>/dev/null; then BASE_VERSION=$(git show origin/$BASE_BRANCH:$FILE | grep '"version":' | awk -F '"' '{print $4}') else BASE_VERSION=$HEAD_VERSION fi if [ "$BASE_VERSION" != "$HEAD_VERSION" ]; then VERSION_CHANGED=true echo "Version change detected in $FILE" fi fi done if [ "$VERSION_CHANGED" = true ]; then echo "Manual version changes are prohibited. Use changesets instead." exit 1 fi env: GITHUB_REF: ${{ github.ref }}
এই চেকের পাশাপাশি, check-quality
জব নির্ভরতা ইনস্টল করে, সীমাবদ্ধতা যাচাই করে, বৃত্তাকার নির্ভরতা পরীক্ষা করে এবং NX দিয়ে আমরা আগে যে স্ক্রিপ্টটি সংজ্ঞায়িত করেছি তা ব্যবহার করে সামগ্রিক কোডের মান যাচাই করে:
- id: install-dependencies name: Install dependencies run: yarn --immutable - id: check-constraints name: Check constraints run: yarn constraints - id: check-circulardeps name: Check circular dependencies run: yarn check-circulardeps:all - id: check-quality name: Check quality run: BASE=origin/${{ github.event.pull_request.base.ref }} yarn quality:affected
মান পরীক্ষাটি শুধুমাত্র বর্তমান পুল অনুরোধ দ্বারা প্রভাবিত প্যাকেজগুলিতে চালানোর জন্য ডিজাইন করা হয়েছে। এই কাজগুলির সফল সমাপ্তি ইঙ্গিত দেয় যে পুল অনুরোধটি একত্রিত হওয়ার জন্য প্রস্তুত (কোড পর্যালোচনা গ্রহণের পাশাপাশি)।
আপনার প্রকল্পের জন্য যদি অতিরিক্ত পরীক্ষা-নিরীক্ষার প্রয়োজন হয়, তাহলে আপনি কর্মপ্রবাহ অপরিবর্তিত রেখে আপনার nx.json
এবং মানসম্পন্ন স্ক্রিপ্ট আপডেট করতে পারেন।
লাইব্রেরি এবং বৈশিষ্ট্য প্রকাশ করুন
একটি PR মার্জ করার পর, রিলিজ ওয়ার্কফ্লো (যেমন Changesets অধ্যায়ে বর্ণিত হয়েছে) ট্রিগার হয়। এই ওয়ার্কফ্লো প্রভাবিত প্যাকেজগুলি তৈরি করে এবং সংস্করণ বাম্পগুলির সাথে একটি PR তৈরি করে। একবার এই PR অনুমোদিত এবং মার্জ হয়ে গেলে, release.yaml আবার চলে - এবার, PR তৈরি করার পরিবর্তে, এটি সংস্করণের পরিবর্তনগুলি সনাক্ত করে এবং আপডেট হওয়া প্যাকেজগুলিকে NPM-এ প্রকাশ করে:
- id: build-packages name: Build packages run: yarn build:affected - id: create-release-pull-request-or-publish name: Create Release Pull Request or Publish to NPM uses: changesets/action@v1 with: version: yarn changeset version publish: yarn release commit: "chore: publish new release" title: "chore: publish new release" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} release-apps: needs: release-libs-features uses: ./.github/workflows/release-apps.yaml with: publishedPackages: ${{ needs.release-libs-features.outputs.publishedPackages }}
এর পরে, release-apps
নামক একটি কাজ সম্পাদিত হয়, যা অ্যাপ্লিকেশন স্থাপনের জন্য দায়ী। এটি পূর্ববর্তী ধাপ থেকে প্রকাশিত প্যাকেজগুলির একটি তালিকা গ্রহণ করে এবং আমাদের পরবর্তী অধ্যায়ে নিয়ে যায়।
অ্যাপ প্রকাশ করুন
রিলিজ প্রক্রিয়ার শেষ অংশে আপনার অ্যাপ্লিকেশনগুলি স্থাপন করা জড়িত (অ্যাপ্লিকেশনগুলি NPM-এ প্রকাশিত হয় না, কারণ সেগুলি package.json
এ private
সেট করা থাকে)। release-apps.yaml ওয়ার্কফ্লো স্বয়ংক্রিয়ভাবে release.yaml দ্বারা ট্রিগার হয়, অথবা GitHub-এর Actions ট্যাব থেকে সরাসরি কার্যকর করা যেতে পারে:
name: Release Apps on: workflow_call: inputs: publishedPackages: description: "List of published packages" required: false type: string default: "[]" workflow_dispatch: inputs: publishedPackages: description: "List of published packages (optional)" required: false type: string default: "[]"
এই ওয়ার্কফ্লোটি কোন প্যাকেজগুলি প্রকাশিত হয়েছে তা নির্ধারণের জন্য publishedPackages
ইনপুট গ্রহণ করে। একটি ম্যাট্রিক্স কৌশল ব্যবহার করে, এটি প্রকাশিত নির্ভরতার উপস্থিতির জন্য ম্যাট্রিক্সের প্রতিটি অ্যাপ্লিকেশন পরীক্ষা করে:
- id: check-dependency-published name: Check if any app dependency is published run: | PUBLISHED_PACKAGES="${{ inputs.publishedPackages }}" PACKAGE_NAME="${{ matrix.package }}" APP="${{ matrix.app }}" DEPENDENCIES=$(jq -r '.dependencies // {} | keys[]' "apps/$APP/package.json") for DEP in $DEPENDENCIES; do if echo "$PUBLISHED_PACKAGES" | grep -w "$DEP"; then echo "published=true" >> $GITHUB_OUTPUT exit 0 fi done echo "published=false" >> $GITHUB_OUTPUT
এই চেকটি একটি অ্যাপ স্থাপন শুরু করার জন্য একটি শর্ত। অন্য শর্তটি নিশ্চিত করে যে অ্যাপের সংস্করণটি পরিবর্তন করা হয়েছে (নির্দেশ করে যে কোনও নির্ভরতা আপডেট না করা হলেও পুনরায় স্থাপন করা প্রয়োজন):
- id: check-version-change name: Check if app version has changed run: | APP="${{ matrix.app }}" PACKAGE_JSON_PATH="apps/$APP/package.json" CURRENT_VERSION=$(jq -r '.version' "$PACKAGE_JSON_PATH") PREVIOUS_VERSION=$(git show HEAD~1:"$PACKAGE_JSON_PATH" | jq -r '.version' || echo "") if [[ "$CURRENT_VERSION" == "$PREVIOUS_VERSION" ]]; then echo "changed=false" >> $GITHUB_OUTPUT else echo "changed=true" >> $GITHUB_OUTPUT fi
অবশেষে, অ্যাপটির নির্ভরতা আপডেট হয়েছে অথবা এর সংস্করণ পরিবর্তিত হয়েছে তা নিশ্চিত করার পর, ওয়ার্কফ্লো নতুন সংস্করণটি পুনরুদ্ধার করে এবং অ্যাপ্লিকেশনটি তৈরি এবং স্থাপনের জন্য এগিয়ে যায়:
- id: set-up-docker name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - id: get-app-version name: Get the app version from package.json run: echo "app-version=$(cat ./apps/${{ matrix.app }}/package.json | jq -r '.version')" >> $GITHUB_OUTPUT - id: build-image name: Build image if: steps.check-dependency-published.outputs.published == 'true' || steps.check-version-change.outputs.changed == 'true' uses: docker/build-push-action@v4 with: build-contexts: | workspace=./ context: "./apps/${{ matrix.app }}" load: true push: false tags: | ${{ matrix.app }}:v${{ steps.get-app-version.outputs.app-version }}
এই উদাহরণে, আমরা ডকার ইমেজটি রেজিস্ট্রিতে না ঠেলে তৈরি করি। আপনার প্রোডাকশন ওয়ার্কফ্লোতে, এই ধাপটি প্রকৃত স্থাপনার প্রক্রিয়া দিয়ে প্রতিস্থাপন করুন।
উপসংহার
সেরা অনুশীলনের সংক্ষিপ্তসার
এই প্রবন্ধ জুড়ে, আমরা একটি শক্তিশালী মনোরেপোর সেটআপ এবং এটিকে দক্ষতার সাথে পরিচালনা করতে সহায়তা করে এমন সরঞ্জামগুলি অন্বেষণ করেছি। আপনার কোডবেসকে কেন্দ্রীভূত করে, আপনি কেবল নির্ভরতা ব্যবস্থাপনাকে সহজ করেন না বরং দলগুলির মধ্যে সহযোগিতাকেও সুগম করেন। আমরা দেখিয়েছি কিভাবে নির্ভরতা ভাগ করে নেওয়ার জন্য Yarn ব্যবহার করা যেতে পারে, PnP এর সাথে ইনস্টলেশন ত্বরান্বিত করতে এবং সামগ্রিক প্রকল্পের ধারাবাহিকতা উন্নত করতে। অতিরিক্তভাবে, লক্ষ্যযুক্ত স্ক্রিপ্ট সম্পাদনের জন্য NX সংহত করা নিশ্চিত করে যে CI দ্রুত এবং দক্ষ। Changesets সংস্করণ স্বয়ংক্রিয় করতে, ম্যানুয়াল ত্রুটি হ্রাস করতে এবং রিলিজগুলিকে সুগম করতে সহায়তা করেছে। অবশেষে, আমরা GitHub অ্যাকশন সহ একটি উৎপাদন-প্রস্তুত CI/CD পাইপলাইন তৈরি করেছি যা শুধুমাত্র প্রয়োজনীয় কাজগুলি সম্পাদন করে।
পরবর্তী পদক্ষেপ
- পরীক্ষা এবং অভিযোজন : এই সেরা অনুশীলনগুলি পরীক্ষা করার জন্য একটি ছোট আকারের মনোরেপো স্থাপন করে শুরু করুন। বিভিন্ন ফোল্ডার কাঠামো নিয়ে পরীক্ষা করুন এবং ধীরে ধীরে আপনার আত্মবিশ্বাস বাড়ার সাথে সাথে আরও প্যাকেজ অন্তর্ভুক্ত করার জন্য প্রসারিত করুন।
- অতিরিক্ত সরঞ্জাম একীভূত করুন : আপনার প্রকল্পের অনন্য প্রয়োজনীয়তা এবং দলের পছন্দের উপর ভিত্তি করে PNPM বা Turborepo এর মতো পরিপূরক সরঞ্জামগুলিকে একীভূত করার কথা বিবেচনা করুন।
- CI/CD পাইপলাইন উন্নত করুন : আপনার প্রকল্পের জন্য তৈরি অতিরিক্ত গুণমান পরীক্ষা, কোড কভারেজ এবং নিরাপত্তা স্ক্যান অন্তর্ভুক্ত করার জন্য আপনার GitHub Actions কর্মপ্রবাহকে সূক্ষ্ম করুন।
- কমিউনিটি এবং আপডেট : Yarn, NX এবং Changesets-এর সর্বশেষ রিলিজ সম্পর্কে আপডেট থাকুন। মনোরেপো ব্যবস্থাপনায় উদীয়মান প্রবণতা সম্পর্কে অন্তর্দৃষ্টি ভাগ করে নিতে এবং জানতে কমিউনিটির সাথে যুক্ত থাকুন।
রিসোর্স
এই নির্দেশিকার জন্য তৈরি সম্পূর্ণ উদাহরণ সংগ্রহস্থলটি অ্যাক্সেস করুন। প্রকল্পের কাঠামো, কোড নমুনা এবং স্ক্রিপ্টগুলি অন্বেষণ করুন যা মনোরেপো সেটআপকে কার্যকরভাবে প্রদর্শন করে।
এই প্রকল্পের অংশ হিসেবে প্রকাশিত প্রকৃত NPM প্যাকেজটি দেখুন। এই প্যাকেজগুলি প্রবন্ধে আলোচিত ধারণাগুলির বাস্তব-বিশ্ব ব্যবহার এবং বাস্তবায়ন প্রদর্শন করে।