513 показания
513 показания

Изграждане на стабилно JS/TS Monorepo: Най-добри практики с Yarn, NX и Changesets

от Teimur Gasanov22m2025/03/24
Read on Terminal Reader

Твърде дълго; Чета

Тази статия обяснява как да изградите стабилно JS/TS monorepo, като използвате Yarn v4 за работни пространства, NX за ефективно изпълнение на скриптове и управление на зависимостите и Changesets за автоматизирано създаване на версии и издания. Той също така обхваща структурирането на вашия код в приложения, функции и библиотеки, плюс интегриране на GitHub Actions за CI/CD, за да се гарантира качество на кода и да се рационализира внедряването.
featured image - Изграждане на стабилно JS/TS Monorepo: Най-добри практики с Yarn, NX и Changesets
Teimur Gasanov HackerNoon profile picture
0-item
1-item

Въведение

Защо Monorepo?

В наши дни не може да се отрече бързата еволюция на разработката на софтуер. Екипите растат, проектите са по-сложни. Компаниите харчат значителни ресурси, за да поддържат разпределена кодова база, състояща се от много фрагменти. Влезте в monorepo - единно, унифицирано хранилище, което обединява целия ви код. Далеч от това да са тенденция, monorepos наскоро се превърнаха в архитектурен подход за съхраняване на цялата кодова база на едно място. Екипите получават подобрено споделяне на контекст, гладко сътрудничество и инструмент, който естествено насърчава повторното използване на кода.

Настройване на работни пространства на Yarn

Забележка: В цялата тази статия, когато се споменава „Yarn“, това се отнася конкретно за Yarn v4 – най-новата версия, предлагаща подобрени възможности и подобрена производителност.

Какво представляват работните пространства на Yarn?

Работните пространства са пакетите на monorepo, често наричани пакети. Те ви помагат да управлявате множество пакети в едно хранилище без усилие. С работни пространства. можете да:

  • Лесно споделяне на зависимости:

    Споделяйте безпроблемно общите зависимости във вашия проект.

  • Опростете управлението на зависимостите:

    Yarn автоматично свързва локални пакети, намалявайки дублирането и улеснявайки разработката.

  • Ускоряване на инсталациите:

    Възползвайте се от оптимизациите на производителността и механизмите за кеширане на Yarn (т.е. вграден plug'n'play ).

  • Подобрете контрола върху Monorepo:

    Дефинирайте ограничения (правила) и използвайте десетки налични добавки, за да поддържате последователност.


Въпреки че Yarn е избраният мениджър за тази статия благодарение на своята простота, скорост и обширни опции за конфигуриране – важно е да се отбележи, че правилният избор зависи от специфичните нужди на вашия проект, предпочитанията на екипа и цялостния работен процес. Например PNPM и Turborepo са други модерни инструменти, които предлагат широк набор от функции.

Първоначална конфигурация

Настройката на преждата е лесен процес. Следвайте официалното ръководство за инсталиране и конфигуриране на Yarn във вашия проект: Ръководство за инсталиране на Yarn .

След като завършите инсталацията, нека да преминем към конфигурацията. Тъй като използваме 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.

Организиране на структурата на Monorepo

Сега, когато мениджърът на пакети е конфигуриран, е време да проектираме мащабируема организация на проекта. Ясната, добре дефинирана структура не само прави хранилището по-лесно за навигация, но също така насърчава по-доброто повторно използване на кода. В този пример ще разделим кодовата база на три основни категории:

  • Приложения :

    • Клиент: Съдържа крайните клиентски продукти, които могат да се внедряват.
    • Сървър: Съдържа окончателните сървърни продукти, които могат да се внедряват.
  • характеристики :

    • Клиент: За самостоятелни UI уиджети.
    • Сървър: За самостоятелни елементи на бизнес логиката в бекенда.
  • Libs :

    Съдържа споделен код като компоненти на системата за проектиране, константи, активи и помощни програми. Това е зона без контекст за съхранение на многократно използваема логика.


За да демонстрираме силата на тази структура на папките, нека започнем с добавянето на тези основни папки към списъка с работни пространства на Yarn. Във вашия root package.json добавете следното:

 "workspaces": [ "apps/**", "features/**", "libs/**" ]

Тази конфигурация казва на Yarn да третира пакетите в тези папки като локални пакети. Последващите инсталации ще гарантират, че зависимостите за всеки пакет са правилно настроени и свързани.

Кодова база за стартиране

В този раздел ще разгледаме минимален пример за кодова база, който илюстрира как да стартирате monorepo. Вместо да включвам пълни кодови фрагменти, ще предоставя кратки примери с връзки към пълните файлове в хранилището, създадено специално за тази статия .

Сървърно приложение за стартиране

Започваме с прост Express 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 използва манипулатор, импортиран от друг пакет. Това ни отвежда до нашия следващ компонент: сървърната функция.

Функция за стартиращ сървър

Сървърната функция капсулира логиката за удостоверяване. В този пакет ние дефинираме манипулатора за влизане, който използва споделена помощна програма за валидиране от библиотеките.

 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;

Линк към пакета


Този подход обобщава логиката за удостоверяване в рамките на собствен пакет, позволявайки да бъде разработен и поддържан независимо. Забележете как помощните програми за проверка се импортират от споделената библиотека .

Клиентско приложение за стартиране

След това нека да разгледаме клиентската страна. В нашето клиентско приложение изграждаме прост уебсайт, който позволява удостоверяване на потребителя чрез извикване на 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 е система за изграждане, оптимизирана за monorepos с разширени 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 за пакет зависи както от компилацията, така и от скриптовете 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}" }

Тук дефинираме четири типа скриптове за изпълнение:

  • build: Създава пакет.

  • typecheck: Проверява типовете на пакета.

  • lint: Линтира пакет.

  • качество: Изпълнява както проверка на типа, така и линт.'


Всеки скрипт има два варианта:

  • всички: Изпълнява скрипта на всички пакети.
  • засегнат: Изпълнява скрипта само върху пакети, засегнати от последните промени. Променливите на средата 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 файл.
  • Рекурсивно проверява за цикли.
  • Регистрира грешка и излиза, ако бъде открита кръгова зависимост.

Валидиране на зависимости с ограничения на прежди

С нарастването на проектите поддържането на последователност между зависимостите става предизвикателство. Налагането на стриктни правила относно зависимостите, версиите на Node и други конфигурации е от съществено значение за избягване на ненужно техническо задължение. Ограниченията на Yarn предлагат начин за автоматизиране на тези валидации.

Разбиране на ограниченията на преждата

Ограниченията на Yarn са набор от правила за пакети във вашето монорепо. Съществено предимство от използването им е, че вие сте мениджърът на тези правила. Например, можете да създадете правило, което да принуди всички пакети да използват една и съща версия на React. След като бъде зададено, никога няма да се натъкнете на проблем, когато хост приложение не може да използва функция/библиотека с по-висока версия на React.

Въпреки че мигрирането на голямо монорепо към нова основна версия на зависимост може да бъде сложно, използването на ограничения в крайна сметка носи последователност и стабилност на целия проект.

Налагане на последователност

В нашето примерно хранилище използваме файлyarn.config.cjs , за да наложим последователност за:

  • Версия на възела

  • Версия с прежда

  • Версии на зависимостите


За да позволите гъвкавост по време на преходите, можете да дефинирате изключения за временно заобикаляне на определени проверки. Например:

 const workspaceCheckExclusions = []; const dependencyCheckExclusions = [];

Тези константи ви позволяват да изключите конкретни работни пространства или зависимости от процеса на валидиране, като гарантирате плавни миграции, когато е необходимо.

Управление на версии с набори от промени

Друг проблем, с който може да се сблъскате с разрастването на хранилището, е управлението и освобождаването на версиите. Наборите от промени предоставят елегантно решение за автоматизиране на този процес, като гарантират, че всяка промяна се проследява, поддържа версия и се освобождава.

Въведение в наборите от промени

Changesets е инструмент с отворен код, предназначен да управлява версиите в monorepo хранилища. Той опростява процеса на следене на промените, като ги разпределя в малки, четими от човека документи, които улавят намерението на промяната. Тези документи се наричат набори от промени. Основните предимства включват:

  • Ясна документация

    Всеки набор от промени очертава направените промени, което помага както на разработчиците, така и на потребителите да разберат какво да очакват в нова версия.

  • Подробен контрол на версиите

    Всеки пакет се управлява независимо, като се гарантира, че само засегнатите пакети се актуализират. Това минимизира риска от сблъсъци с празни версии и прекъсвания на зависимостите.

  • Удобен за сътрудничество

    Тъй като всяка промяна се записва чрез набор от промени, екипите могат да преглеждат и одобряват актуализациите преди действителното пускане.

Автоматизиране на изданията

Една от най-мощните функции на Changesets е способността за автоматизиране на процеса. Можете да интегрирате Changesets във вашия CI/CD тръбопровод и да забравите за ръчните промени на версията и публикуването на NPM.

Разгледайте работния процес release.yaml в примерното хранилище. Има стъпка create-release-pull-request-or-publish . Стъпката, подкрепена от набори от промени/действие GitHub действие създава цялата магия. Трябва само да настроите NPM_TOKEN за публикуване на вашите пакети. След това всяко натискане към main клон ще:

  • Проверете дали има документи за Changeset .

    Ако присъстват документи за набор от промени, действието създава заявка за изтегляне с необходимите промени на версията и актуализации на регистъра на промените. Ако не бъдат открити промени, нищо не се случва.

  • Проверете дали има готови за публикуване пакети .

    Ако пакетите са готови за пускане, действието публикува новите версии в NPM, като използва предоставения NPM_TOKEN . Ако няма пакети, готови за публикуване, действието излиза без да се правят промени.


Чрез автоматизирането на тези задачи, Changesets гарантира, че вашите версии са последователни и надеждни, намалявайки потенциала за човешка грешка и рационализирайки вашия работен процес на разработка.

Интеграция на работния процес с GitHub Actions

Този раздел разглежда как да отприщим силата на архитектурата, която току-що изградихме. Използвайки GitHub Actions, ние ще автоматизираме проверките на качеството на PR, изданията на версии за библиотеки и функции и внедряването на приложения. Фокусът е върху максимизирането на автоматизацията, като същевременно се поддържа качеството на кода и детайлността на работата.

Проверете качеството на PR

За да гарантираме, че кодът на заявка за изтегляне остава последователен и стабилен, ние създаваме специален работен поток за качество.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 се задейства работният поток за освобождаване (както е описано в главата за Набори промени). Този работен процес изгражда засегнатите пакети и създава 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, защото са зададени private в package.json ). Работният процес release-apps.yaml се задейства автоматично от release.yaml или може да се изпълни директно от раздела Действия в 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: "[]"

Този работен поток приема 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 }}

В този пример изграждаме изображението на Docker, без да го изпращаме в регистър. Във вашия производствен работен процес заменете тази стъпка с действителния процес на внедряване.

Заключение

Резюме на най-добрите практики

В цялата тази статия проучихме настройката на стабилно monorepo и инструментите, които помагат за ефективното му управление. Чрез централизирането на вашата кодова база вие не само опростявате управлението на зависимостите, но и рационализирате сътрудничеството между екипите. Ние демонстрирахме как Yarn може да се използва за споделяне на зависимости, ускоряване на инсталирането с PnP и подобряване на цялостната последователност на проекта. Освен това, интегрирането на NX за целево изпълнение на скриптове гарантира, че CI е бърз и ефективен. Наборите от промени помогнаха за автоматизиране на версиите, намаляване на ръчните грешки и рационализиране на изданията. И накрая, създадохме готов за производство CI/CD тръбопровод с GitHub действия, който изпълнява само необходимите задачи.

Следващи стъпки

  1. Експериментирайте и адаптирайте : Започнете, като създадете монорепо в малък мащаб, за да тествате тези най-добри практики. Експериментирайте с различни структури на папки и постепенно разширявайте, за да включите повече пакети, докато увереността ви нараства.
  2. Интегрирайте допълнителни инструменти : Помислете за интегриране на допълнителни инструменти като PNPM или Turborepo въз основа на уникалните изисквания на вашия проект и предпочитанията на екипа.
  3. Подобрете CI/CD тръбопроводите : Настройте фино работните си процеси на GitHub Actions, за да включите допълнителни проверки на качеството, покритие на кода и сканирания за сигурност, съобразени с вашия проект.
  4. Общност и актуализации : Бъдете в течение с най-новите версии на Yarn, NX и Changesets. Ангажирайте се с общността, за да споделите прозрения и да научите за нововъзникващите тенденции в управлението на monorepo.

Ресурси

  • Примерно хранилище :

    Достъп до пълното хранилище за примери, създадено за това ръководство. Разгледайте структурата на проекта, примерните кодове и скриптовете, които демонстрират настройката на monorepo в действие.

  • Публикувани NPM пакети :

    Вижте действителния NPM пакет, публикуван като част от този проект. Тези пакети демонстрират използване в реалния свят и прилагане на концепциите, обсъдени в статията.


L O A D I N G
. . . comments & more!

About Author

Teimur Gasanov HackerNoon profile picture
Teimur Gasanov@teimurjan
I am an engineer with significant experience in web development.

ЗАКАЧВАЙТЕ ЕТИКЕТИ

ТАЗИ СТАТИЯ Е ПРЕДСТАВЕНА В...

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks