Utangulizi
Kwa nini Monorepo?
Siku hizi, mageuzi ya haraka ya maendeleo ya programu hayawezi kukataliwa. Timu zinakua, miradi huwa ngumu zaidi. Makampuni hutumia rasilimali nyingi kudumisha codebase iliyosambazwa inayojumuisha vipande vingi. Ingiza monorepo - hazina moja, iliyounganishwa ambayo huleta pamoja msimbo wako wote. Mbali na kuwa mtindo, monorepos hivi karibuni imekuwa mbinu ya usanifu wa kuweka msingi wote wa kanuni katika sehemu moja. Timu hupata ushirikishwaji ulioboreshwa wa muktadha, ushirikiano mzuri na zana ambayo inahimiza utumiaji wa msimbo tena.
Kuweka Nafasi za Kazi za Uzi
Kumbuka: Katika makala haya yote, wakati wowote "Uzi" inapotajwa, inarejelea Uzi v4—toleo la hivi punde linalotoa uwezo ulioimarishwa na utendakazi ulioboreshwa.
Nafasi za kazi za Uzi ni nini?
Nafasi za kazi ni vifurushi vya monorepo, mara nyingi huitwa vifurushi. Wanakusaidia kudhibiti vifurushi vingi kwenye hazina moja bila bidii. Pamoja na maeneo ya kazi. unaweza:
Shiriki Vitegemezi kwa Urahisi:
Shiriki vitegemezi vya kawaida kwenye mradi wako bila mshono.
Rahisisha Usimamizi wa Utegemezi:
Uzi huunganisha kiotomatiki vifurushi vya ndani, kupunguza marudio na kurahisisha maendeleo.
Ongeza kasi ya Usakinishaji:
Faidika na uboreshaji wa utendakazi wa Yarn na mifumo ya kuweka akiba (yaani, iliyojengewa ndani plug'n'play ).
Boresha Udhibiti wa Monorepo:
Bainisha vikwazo (sheria) na utumie programu-jalizi kadhaa zinazopatikana ili kudumisha uthabiti.
Ingawa Uzi ndiye msimamizi aliyechaguliwa wa makala haya kutokana na usahili wake, kasi, na chaguo pana za usanidi - ni muhimu kutambua kwamba chaguo sahihi inategemea mahitaji mahususi ya mradi wako, mapendeleo ya timu na mtiririko wa kazi kwa ujumla. Kwa mfano, PNPM na Turborepo ni zana zingine za kisasa ambazo hutoa anuwai ya vipengele.
Usanidi wa Awali
Kuweka uzi ni mchakato wa moja kwa moja. Fuata mwongozo rasmi ili kusakinisha na kusanidi Uzi katika mradi wako: Mwongozo wa Ufungaji wa Uzi .
Mara tu unapokamilisha usakinishaji, wacha tuendelee kwenye usanidi. Kwa kuwa tunatumia plug'n'play, unahitaji kuhakikisha kuwa IDE yako inatambua vitegemezi kwa usahihi. Ikiwa unatumia VSCode, endesha:
# Typescript is required for VSCode SDK to set up correctly yarn add -D typescript@^5 yarn dlx @yarnpkg/sdks vscode
Ikiwa unatumia kihariri kingine cha msimbo, angalia SDK zinazopatikana hapa: SDK za Uhariri wa Vitambaa .
Kwa hatua hii, mko tayari kuanza kutumia Uzi.
Kuandaa Muundo wa Monorepo
Sasa kwa kuwa kidhibiti kifurushi kimesanidiwa, ni wakati wa kubuni shirika la mradi ambalo linaweza kupunguzwa. Muundo ulio wazi na uliobainishwa vyema sio tu kwamba hurahisisha uelekezaji wa hazina bali pia unakuza matumizi bora ya msimbo. Katika mfano huu, tutagawanya msingi wa kanuni katika kategoria tatu kuu:
Programu :
- Mteja: Ina bidhaa za mwisho za mteja zinazoweza kutumika.
- Seva: Ina bidhaa za seva za mwisho, zinazoweza kutumiwa.
Vipengele :
- Mteja: Kwa wijeti za UI zinazojitegemea.
- Seva: Kwa vipande vya mantiki ya biashara inayojitegemea.
Libs :
Msimbo wa nyumba unaoshirikiwa kama vile vipengee vya mfumo wa kubuni, vipengee, mali na huduma. Hili ndilo eneo lisilo na muktadha la kuhifadhi mantiki inayoweza kutumika tena.
Ili kuonyesha uwezo wa muundo wa folda hii, hebu tuanze kwa kuongeza folda hizi kuu kwenye orodha ya nafasi za kazi za Uzi. Katika root package.json yako, ongeza yafuatayo:
"workspaces": [ "apps/**", "features/**", "libs/**" ]
Usanidi huu unaambia Uzi kutibu vifurushi kwenye folda hizi kama vifurushi vya ndani. Usakinishaji unaofuata utahakikisha kuwa vitegemezi vya kila kifurushi vimewekwa na kuunganishwa ipasavyo.
Bootstrapping Codebase
Katika sehemu hii, tutapitia mfano mdogo wa codebase ambao unaonyesha jinsi ya bootstrap monorepo. Badala ya kujumuisha vijisehemu kamili vya msimbo, nitatoa mifano mifupi iliyo na viungo vya faili kamili kwenye hazina iliyoundwa mahususi kwa makala haya .
Maombi ya Seva ya Bootstrapping
Tunaanza na API rahisi ya Express kwa uthibitishaji wa mtumiaji. Programu hii ya seva inafichua ncha moja ( /auth/signIn
) ambayo hutumia kidhibiti kutoka kwa kifurushi kingine.
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}`); });
Kama unavyoona, mwisho wa /auth/signIn
hutumia kidhibiti kilichoingizwa kutoka kwa kifurushi kingine. Hiyo inatuleta kwenye sehemu yetu inayofuata: kipengele cha seva.
Kipengele cha Seva ya Bootstrapping
Kipengele cha seva kinajumuisha mantiki ya uthibitishaji. Katika kifurushi hiki, tunafafanua kidhibiti cha kuingia, ambacho hutumia matumizi ya uthibitishaji yaliyoshirikiwa kutoka kwa 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;
Mbinu hii ni muhtasari wa mantiki ya uthibitishaji ndani ya kifurushi chake, ikiruhusu kuendelezwa na kudumishwa kwa kujitegemea. Tazama jinsi huduma za uthibitishaji huletwa kutoka kwa lib iliyoshirikiwa .
Programu ya Mteja wa Kufunga Mtambo
Ifuatayo, wacha tuangalie upande wa mteja. Katika programu yetu ya mteja, tunaunda tovuti rahisi ambayo huwezesha uthibitishaji wa mtumiaji kwa kutumia API ya seva.
"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> ); }
Katika mfano huu, kipengele cha SignInForm
kinaletwa kutoka kwa kifurushi cha kipengele cha mteja, ambacho hutupeleka kwenye kipengee chetu cha mwisho.
Kipengele cha Mteja cha Kufunga Mtambo
Kifurushi cha kipengele cha mteja hutoa fomu ya uthibitishaji pamoja na mantiki ya uthibitishaji iliyoshirikiwa. Hii inaepuka kunakili msimbo na inahakikisha uthabiti.
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;
Hapa, tunaona tena matumizi ya kiidhinishi kutoka kwa libs zetu zilizoshirikiwa, kuhakikisha kuwa mantiki ya uthibitishaji iko katikati na kudumishwa kwa urahisi.
Hiyo ni kwa mfano wetu mdogo wa codebase. Kumbuka kwamba msimbo huu ni kielelezo kilichorahisishwa kinachokusudiwa kuonyesha muundo msingi na muunganisho kati ya Programu, Vipengee na Libs katika monorepo. Unaweza kupanua mifano hii inapohitajika ili kuendana na mahitaji mahususi ya mradi wako.
Inaendesha Hati na NX
Kusimamia hati katika monorepo kunaweza kuwa changamoto. Ingawa Uzi hukuruhusu kuendesha hati kwenye vifurushi vingi kwa kutumia hali mbalimbali, inaweza kuhitaji uandishi maalum kwa udhibiti wa punjepunje. Hapa ndipo NX inapoingia: hutoa suluhu ya nje ya kisanduku kwa utekelezaji mzuri wa hati unaolengwa.
Utangulizi wa NX
NX ni mfumo wa kujenga ulioboreshwa kwa monorepos na uwezo wa juu wa CI. Ukiwa na NX, unaweza:
- Endesha kazi kwa ufanisi sambamba : Tumia upatanishi ili kuharakisha ujenzi wako.
- Tambua uhusiano wa utegemezi : Elewa miunganisho kati ya vifurushi na hati.
- Matokeo ya utekelezaji wa hati ya akiba : Epuka kazi isiyo ya lazima kwa kuakibisha matokeo.
- Geuza tabia ukitumia programu-jalizi kukufaa: Panua utendakazi kupitia mfumo tajiri wa ikolojia wa programu-jalizi .
Utekelezaji wa Hati Uliolengwa
Ili kutumia uwezo wa NX, tunahitaji kwanza kuunda faili ya nx.json
ili kufafanua seti ya sheria za hati zetu. Chini ni mfano wa usanidi:
{ "targetDefaults": { "build": { "dependsOn": [ "^build" ], "outputs": [ "{projectRoot}/dist" ], "cache": true }, "typecheck": { "dependsOn": [ "^build", "^typecheck" ] }, "lint": { "dependsOn": [ "^build", "^lint" ] } }, "defaultBase": "main" }
Kwa Kiingereza wazi, usanidi huu unamaanisha:
Jenga
Nakala ya
build
wa kifurushi inategemea ujenzi uliofanikiwa wa utegemezi wake, na matokeo yake yamehifadhiwa.Aina ya ukaguzi
Nakala ya
typecheck
kifurushi inategemea maandishi ya muundo na chapa ya utegemezi wake.Lint
Hati
lint
ya kifurushi inategemea maandishi ya ujenzi na laini ya utegemezi wake.
Sasa, wacha tuongeze maandishi kwenye 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}" }
Hapa, tunafafanua aina nne za hati za utekelezaji:
kujenga: Hujenga kifurushi.
typecheck: Huangalia aina za kifurushi.
lint: Huweka kifurushi.
ubora: Huendesha kikagua chapa na pamba.'
Kila hati ina tofauti mbili:
- zote: Huendesha hati kwenye vifurushi vyote.
- iliyoathiriwa: Huendesha hati kwenye vifurushi vilivyoathiriwa na mabadiliko ya hivi majuzi pekee. Vigezo vya mazingira ya
BASE
naHEAD
hukuruhusu kubainisha masafa (chaguo-msingi hadiorigin/main
naHEAD
ya sasa ), kuwezesha utekelezaji wa punjepunje kwenye maombi ya kuvuta. Hii inaweza kuokoa muda na rasilimali kwa kiasi kikubwa.
Kusimamia Utegemezi wa Mviringo
NX pia hutoa amri iliyojumuishwa ili kutoa grafu ya utegemezi, ambayo inaweza kusaidia katika kugundua mizunguko ya utegemezi. Hati ifuatayo hutumia pato la grafu ya NX kuangalia utegemezi wa duara na itashindwa ikiwa inapatikana.
Unda faili katika scripts/check-circulardeps.mjs
na maudhui yafuatayo:
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();
Hati hii:
- Hutekeleza amri ya NX ili kutoa grafu ya utegemezi.
- Husoma grafu kutoka kwa faili ya muda ya JSON.
- Hukagua mizunguko kwa kujirudia.
- Huweka hitilafu na kuondoka ikiwa utegemezi wa mviringo umegunduliwa.
Kuthibitisha Vitegemezi kwa Vizuizi vya Uzi
Miradi inapokua, kudumisha uthabiti katika utegemezi inakuwa changamoto. Utekelezaji wa sheria kali kuhusu utegemezi, matoleo ya Node, na usanidi mwingine ni muhimu ili kuepuka madeni ya kiufundi yasiyo ya lazima. Vizuizi vya Uzi hutoa njia ya kubinafsisha uthibitishaji huu.
Kuelewa Vizuizi vya Uzi
Vizuizi vya Uzi ni seti ya sheria za vifurushi katika monorepo yako. Faida kubwa ya kuzitumia ni kwamba wewe ndiye msimamizi wa sheria hizi. Kwa mfano, unaweza kuunda sheria ya kulazimisha vifurushi vyote kutumia toleo sawa la React. Mara tu ikiwa imewekwa, hutawahi kukumbana na tatizo wakati programu mwenyeji haiwezi kutumia kipengele/lib na toleo la juu la React.
Ingawa kuhamisha monorepo kubwa hadi toleo kuu jipya la utegemezi kunaweza kuwa ngumu, kutumia vizuizi hatimaye huleta uthabiti na uthabiti kwa mradi mzima.
Utekelezaji Uthabiti
Katika hazina yetu ya mfano, tunatumia faili yayarn.config.cjs kutekeleza uthabiti kwa:
Toleo la Nodi
Toleo la Uzi
Matoleo ya Dependencies
Ili kuruhusu kunyumbulika wakati wa mabadiliko, unaweza kufafanua vizuizi ili kupitisha ukaguzi fulani kwa muda. Kwa mfano:
const workspaceCheckExclusions = []; const dependencyCheckExclusions = [];
Vidhibiti hivi hukuruhusu kutenga nafasi mahususi za kazi au vitegemezi kutoka kwa mchakato wa uthibitishaji, kuhakikisha uhamiaji laini inapohitajika.
Kusimamia Utoaji kwa kutumia Mipangilio ya Mabadiliko
Shida nyingine ambayo unaweza kukabiliana nayo na ukuaji wa hazina ni usimamizi wa toleo na kutolewa. Mipangilio ya mabadiliko hutoa suluhisho la kifahari la kugeuza mchakato huu kiotomatiki, kuhakikisha kwamba kila mabadiliko yanafuatiliwa, yanatolewa na kutolewa.
Utangulizi wa Mabadiliko
Changesets ni zana huria iliyoundwa kudhibiti uchapishaji katika hazina za monorepo. Hurahisisha mchakato wa kufuatilia mabadiliko kwa kuyagawa katika hati ndogo zinazoweza kusomeka na binadamu ambazo zinanasa dhamira ya mabadiliko. Hati hizi zinaitwa mabadiliko. Faida kuu ni pamoja na:
Futa Nyaraka
Kila kibadilishaji kinaonyesha mabadiliko yaliyofanywa, ambayo husaidia wasanidi programu na watumiaji kuelewa nini cha kutarajia katika toleo jipya.
Udhibiti wa Toleo la Punjepunje
Kila kifurushi kinatolewa kivyake, na kuhakikisha kuwa vifurushi vilivyoathiriwa pekee ndivyo vinavyosasishwa. Hii inapunguza hatari ya matuta tupu ya toleo na mapumziko ya utegemezi.
Ushirikiano-Rafiki
Kila mabadiliko yanaporekodiwa kupitia kibadilishaji, timu zinaweza kukagua na kuidhinisha masasisho kabla ya toleo halisi.
Matoleo ya Kiotomatiki
Moja ya vipengele vya nguvu zaidi vya Changesets ni uwezo wa kufanya mchakato otomatiki. Unaweza kujumuisha Changesets kwenye bomba la CI/CD na usahau kuhusu mabadiliko ya matoleo ya kibinafsi na uchapishaji wa NPM.
Angalia mtiririko wa kazi wa release.yaml katika hazina ya mfano. Ina hatua create-release-pull-request-or-publish
. Hatua inayoungwa mkono na mabadiliko/kitendo cha GitHub huunda uchawi wote. Unahitaji tu kusanidi NPM_TOKEN
kwa kuchapisha vifurushi vyako. Kisha, kila kushinikiza kwa tawi main
itakuwa:
Angalia kama kuna hati za Changeset .
Iwapo hati za kibadilishaji zipo, kitendo hutengeneza ombi la kuvuta kwa kutumia matuta muhimu ya toleo na masasisho ya mabadiliko. Ikiwa hakuna mabadiliko yanayotambuliwa, hakuna kinachotokea.
Angalia kama kuna vifurushi vilivyo tayari kuchapishwa .
Ikiwa vifurushi viko tayari kutolewa, hatua itachapisha matoleo mapya kwa NPM kwa kutumia
NPM_TOKEN
iliyotolewa. Ikiwa hakuna vifurushi vilivyo tayari kuchapishwa, kitendo kitaondoka bila kufanya mabadiliko.
Kwa kufanyia kazi hizi kiotomatiki, Seti za Mabadiliko huhakikisha kuwa matoleo yako ni thabiti na yanategemewa, hivyo basi kupunguza uwezekano wa makosa ya kibinadamu na kurahisisha utendakazi wako wa ukuzaji.
Ujumuishaji wa mtiririko wa kazi na Vitendo vya GitHub
Sehemu hii inaangazia jinsi ya kufungua uwezo wa usanifu ambao tumeunda hivi punde. Kwa kutumia Vitendo vya GitHub, tutafanya ukaguzi wa ubora wa PR kiotomatiki, matoleo ya matoleo ya maktaba na vipengele, na utumaji programu. Lengo ni kuongeza uwekaji kiotomatiki huku ukidumisha ubora wa msimbo na uzito wa kazi.
Thibitisha Ubora wa PR
Ili kuhakikisha kwamba msimbo wa ombi la kuvuta unasalia kuwa thabiti na thabiti, tunaunda mtiririko maalum wa ubora.yaml . Mtiririko huu wa kazi hufanya kazi kadhaa, kama vile kuhakikisha kuwa mabadiliko ya toleo la mikono hayatambuliwi (kwa kuwa uchapishaji unadhibitiwa na 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 }}
Kando ya hundi hii, utegemezi check-quality
usakinishaji, kuthibitisha vikwazo, hukagua utegemezi wa mduara na kuthibitisha ubora wa jumla wa msimbo kwa kutumia hati tuliyofafanua awali na 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
Ukaguzi wa ubora umeundwa kufanya kazi kwenye vifurushi vilivyoathiriwa na ombi la sasa la kuvuta. Kukamilika kwa kazi hizi kwa mafanikio kunaashiria kwamba ombi la kuvuta liko tayari kuunganishwa (pamoja na kupokea ukaguzi wa misimbo).
Ikiwa ukaguzi wa ziada unahitajika kwa mradi wako, unaweza kusasisha hati yako ya nx.json
na ubora ili kuweka mtiririko wa kazi bila kubadilika.
Chapisha Maktaba na Vipengele
Baada ya PR kuunganishwa, mtiririko wa kazi wa kutolewa (kama ilivyofafanuliwa katika sura ya Changesets) huanzishwa. Mtiririko huu wa kazi huunda vifurushi vilivyoathiriwa na kuunda PR na matuta ya toleo. Mara baada ya PR hii kuidhinishwa na kuunganishwa, release.yaml hutumika tena - wakati huu, badala ya kuunda PR, hutambua mabadiliko ya toleo na kutoa vifurushi vilivyosasishwa kwa 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 }}
Kufuatia hili, kazi inayoitwa release-apps
inatekelezwa, ambayo inawajibika kwa uwekaji wa programu. Inapokea orodha ya vifurushi vilivyochapishwa kutoka kwa hatua ya awali na hutuleta kwenye sura inayofuata.
Chapisha Programu
Sehemu ya mwisho ya mchakato wa kutoa inahusisha kupeleka maombi yako (programu hazichapishwi kwa NPM, kwa sababu zimewekwa private
katika package.json
). Mtiririko wa kazi wa release-apps.yaml huanzishwa kiotomatiki na release.yaml , au unaweza kutekelezwa moja kwa moja kutoka kwa kichupo cha Vitendo kwenye GitHub:
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: "[]"
Mtiririko huu wa kazi unakubali uingizaji wa Vifurushi publishedPackages
ili kubaini ni vifurushi vipi vimechapishwa. Kwa kutumia mkakati wa matrix, hukagua kila matumizi ya matrix kwa uwepo wa vitegemezi vilivyochapishwa:
- 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
Ukaguzi huu ni sharti moja la kuanzisha uwekaji wa programu. Masharti mengine yanahakikisha kuwa toleo la programu limebadilishwa (kuashiria kuwa uwekaji upya ni muhimu hata kama hakuna vitegemezi vilivyosasishwa):
- 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
Hatimaye, baada ya kuthibitisha kuwa programu ina vitegemezi vilivyosasishwa au toleo lake limebadilika, mtiririko wa kazi hurejesha toleo jipya na kuendelea kuunda na kusambaza programu:
- 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 }}
Katika mfano huu, tunaunda picha ya Docker bila kuisukuma kwenye Usajili. Katika utendakazi wako wa uzalishaji, badilisha hatua hii na mchakato halisi wa kusambaza.
Hitimisho
Muhtasari wa Mbinu Bora
Katika makala haya yote, tuligundua usanidi wa monorepo thabiti na zana zinazosaidia kuidhibiti kwa ufanisi. Kwa kuweka msingi wako wa msimbo katikati, hutahisisha tu usimamizi wa utegemezi bali pia huboresha ushirikiano kati ya timu zote. Tulionyesha jinsi Uzi unavyoweza kutumiwa ili kushiriki utegemezi, kuharakisha usakinishaji na PnP na kuboresha uthabiti wa jumla wa mradi. Zaidi ya hayo, kuunganisha NX kwa utekelezaji wa hati inayolengwa huhakikisha kuwa CI ni ya haraka na bora. Mipangilio ya mabadiliko ilisaidia kuweka matoleo kiotomatiki, kupunguza hitilafu za mikono na kurahisisha matoleo. Hatimaye, tumetengeneza bomba la CI/CD lililo tayari kwa uzalishaji kwa vitendo vya GitHub ambavyo hufanya kazi zinazohitajika pekee.
Hatua Zinazofuata
- Jaribio na Ubadilishe : Anza kwa kusanidi monorepo ya kiwango kidogo ili kujaribu mbinu hizi bora. Jaribu kwa miundo tofauti ya folda, na upanue hatua kwa hatua ili kujumuisha vifurushi zaidi imani yako inapoongezeka.
- Unganisha Zana za Ziada : Zingatia kujumuisha zana za ziada kama PNPM au Turborepo kulingana na mahitaji ya kipekee ya mradi wako na mapendeleo ya timu.
- Boresha Mabomba ya CI/CD : Rekebisha utiririshaji kazi wako wa GitHub Actions ili kujumuisha ukaguzi wa ziada wa ubora, ufunikaji wa misimbo, na ukaguzi wa usalama unaolenga mradi wako.
- Jumuiya na Masasisho : Endelea kupata taarifa kuhusu matoleo mapya zaidi ya Uzi, NX na Changesets. Shirikiana na jumuiya ili kushiriki maarifa na kujifunza kuhusu mienendo inayoibuka katika usimamizi wa monorepo.
Rasilimali
Fikia mfano kamili wa hazina iliyoundwa kwa mwongozo huu. Chunguza muundo wa mradi, sampuli za msimbo, na hati zinazoonyesha usanidi wa monorepo ukifanya kazi.
Vifurushi vya NPM vilivyochapishwa :
Angalia kifurushi halisi cha NPM kilichochapishwa kama sehemu ya mradi huu. Vifurushi hivi vinaonyesha matumizi ya ulimwengu halisi na utekelezaji wa dhana zilizojadiliwa katika makala.