Hogyan szervezzünk frontend csomagokat monorepóban, nyomon követjük a változásokat az összes projektben, használjuk újra a megosztott könyvtárakat, és készítsünk csomagokat egy modern összeállítási rendszerrel

A komponensek felépítése és különböző csomagokban történő újrafelhasználása arra a következtetésre jutott, hogy szükséges a projektek tartalmának megfelelő megközelítését egyetlen struktúrában megszervezni. Az építési eszközöknek azonosaknak kell lenniük, beleértve a tesztelési környezetet, a lintszabályokat és az összetevőkönyvtárak hatékony erőforrás-elosztását.

Olyan eszközöket kerestem, amelyekkel hatékony és eredményes módszereket hozhatok robusztus, erőteljes kombinációk létrehozására. És ennek eredményeként egy félelmetes trió alakult ki. Ebben a cikkben több csomagot fogunk létrehozni ezekkel az eszközökkel.

Eszközök

Mielőtt elkezdenénk, vizsgáljuk meg, hogy ezek az eszközök mit tesznek.

Lerna: JavaScript projektek kezelése több csomaggal. Optimalizálja a munkafolyamatot a többcsomagos adattárak git és npm segítségével történő kezelése körül.

Vite: építőeszköz, amely gyors hot modul cserét, azonnali ES-modul támogatást, kiterjedt szolgáltatást és bővítménytámogatást biztosít a React számára

Storybook: nyílt forráskódú eszköz a felhasználói felület összetevőinek elkülönített fejlesztésére és rendezésére, amely egyben platformként is szolgál vizuális teszteléshez és interaktív dokumentációk készítéséhez.

Lerna kezdeti beállítás

Az első lépés a Lerna projekt létrehozása lesz. Hozzon létre egy mappát a lerna_vite_monorepo elemmel, és azon belül futtassa át a npx lerna init terminálon – ez alapvető fontosságú a Lerna projekt számára. Két fájlt hoz létre – lerna.json, package.json – és egy üres mappát (packages).

lerna.json – ez a fájl lehetővé teszi a Lerna számára, hogy egyszerűsítse a monorepo konfigurációját, és utasításokat adjon a függőségek összekapcsolására, a csomagok megkeresésére, a verziószámítási stratégiák megvalósítására és a további feladatok végrehajtására.

Vite Initial Setup

A telepítés befejeztével elérhető lesz egy packages mappa. Következő lépésünkben több további mappát hozunk létre packages a mappán belül:

  • vite-common
  • footer-components
  • body-components
  • footer-components

A projektek létrehozásához a npm init vite-t kell futtatnunk a projekt nevével. Válassza a React keretrendszert és a Typescript változatot. Ezek a projektek ugyanazokat a szöszszabályokat, az összeállítási folyamatot és a React verziót fogják használni.

Ez a folyamat minden csomagban egy csomó fájlt és mappát hoz létre:

├── .eslintrc.cjs
├── .gitignore
├── index.html
├── package.json
├── public
│   └── vite.svg
├── src
│   ├── App.css
│   ├── App.tsx
│   ├── assets
│   │   └── react.svg
│   ├── index.css
│   ├── main.tsx
│   └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts

Mesekönyv kezdeti beállítása

Ideje minden csomagunkhoz beállítani egy mesekönyvet. Lépjen az egyik csomagmappába, és futtassa ott a npx storybook@latest init programot a Storybook telepítéséhez. A eslint-plugin-storybook-vel kapcsolatos kérdéshez a Y bemenetet a telepítéshez. Ezt követően elindul a függőségek telepítésének folyamata.

Ez létrehoz egy .storybook mappát konfigurációkkal és stories mappát a src mappában. Távolítsuk el a stories mappát, mert saját összetevőket készítünk.

Most futtassa a telepítést npx sb init --builder @storybook/builder-vite – ez segít a történetek felépítésében a Vite segítségével a gyors induláshoz és a HMR-hez.

Tételezzük fel, hogy minden mappához ugyanazok a konfigurációk. Ha a telepítés megtörtént, akkor futtathatja a yarn storybook fájlt a csomag mappájában, és futtathatja a Storybookot.

Kezdeti konfigurációk

Az ötlet az, hogy minden csomagunknál újra felhasználjuk a közös beállításokat. Távolítsunk el néhány fájlt, amelyekre nincs szükségünk az egyes tárolókban. Végül minden egyes mappának a következő mappákat és fájlokat kell tartalmaznia:

├── package.json
├── src
│   └── vite-env.d.ts
├── tsconfig.json
└── vite.config.ts

Most vegyük az összes devDependencies-et, és vágjuk ki őket a package.json-ból az egyik csomagmappánkból, és helyezzük el mindet a devDependenices-be a gyökérben package.json.

Futtassa a gyökérben npx storybook@latest init, és javítsa ki a main.js tulajdonságban:

stories: [
  "../packages/*/src/**/*..mdx",
  "../packages/*/src/**/*.stories.@(js|jsx|ts|tsx)"
],

És távolítsa el a gyökérből package.json két szkriptben:

"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"

Adjon hozzá components mappát index.tsx fájllal minden csomagmappához:

├── package.json
├── src
│   ├── components
│   │   └── index.tsx
│   ├── index.tsx
│   └── vite-env.d.ts
├── tsconfig.json
└── vite.config.ts

Létrehozhatunk közös konfigurációkat, amelyek minden csomagra vonatkoznak. Ez magában foglalja a Vite, Storybook, Jest, Babel és Prettier beállításait, amelyek univerzálisan konfigurálhatók.

A gyökérmappának a következő fájlokat kell tartalmaznia:

├── .eslintrc.cjs
├── .gitignore
├── .nvmrc
├── .prettierignore
├── .prettierrc.json
├── .storybook
│   ├── main.ts
│   ├── preview-head.html
│   └── preview.ts
├── README.md
├── babel.config.json
├── jest.config.ts
├── lerna.json
├── package.json
├── packages
│   ├── vite-body
│   ├── vite-common
│   ├── vite-footer
│   └── vite-header
├── test.setup.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts

Ebben az esetben nem vesszük figyelembe a Babel, a Jest és a Prettier beállításait.

Lerna konfiguráció

Először is vizsgáljuk meg a Lerna konfigurációs fájlt, amely segít a monorepo projektünk több csomaggal történő kezelésében.

Először is, a "$schema" struktúrát és érvényesítést biztosít a Lerna konfigurációhoz.

Ha a "useWorkspaces" értéke true, a Lerna fonal munkaterületeket használ a csomagok közötti jobb összekapcsolás és függőségek kezelése érdekében. Ha false, a Lerna kezeli a csomagközi függőségeket monorepo-ban.

A "packages" meghatározza, hogy a Lerna hol találja meg a csomagokat a projektben.

"version" ha "independent"-re van állítva, a Lerna lehetővé teszi, hogy a monorepon belül minden egyes csomag saját verziószámmal rendelkezzen, rugalmasságot biztosítva az egyes csomagokhoz tartozó frissítések kiadásában.

Közös Vite konfiguráció

Most vizsgáljuk meg a szükséges elemeket a vite.config.ts fájlban.

Ez a fájl exportálja a Vite általános konfigurációit további bővítményekkel és könyvtárakkal, amelyeket minden csomagban újra felhasználunk. A defineConfig segédfunkcióként szolgál a Vite konfigurációs fájljában. Bár közvetlenül nem hajt végre semmilyen logikát, és nem módosítja az átadott konfigurációs objektumot, elsődleges szerepe a típuskövetkeztetés javítása és az automatikus kiegészítés megkönnyítése bizonyos kódszerkesztőkben.

A rollupOptions lehetővé teszi az egyéni összesítési beállítások megadását. A „Rollup” az a modulcsomagoló, amelyet a Vite a motorháztető alatt használ felépítési folyamatához. Azáltal, hogy közvetlenül a Rollup számára biztosít opciókat, a fejlesztők pontosabban irányíthatják az összeállítási folyamatot. A rollupOptions external opciója annak meghatározására szolgál, hogy mely modulokat kell külső függőségként kezelni.

Általánosságban elmondható, hogy a external opció használata csökkentheti a köteg méretét azáltal, hogy kizárja a kódot futtató környezetben már meglévő függőségeket.

A output opció globals: { react: "React" } értékkel az összesítő konfigurációjában azt jelenti, hogy a generált kötegben a react importálási utasításai a React globális változóra cserélődnek. Lényegében azt feltételezzük, hogy az React már jelen van a felhasználó környezetében, és globális változóként kell elérni, nem pedig a csomagban.

Az tsconfig.node.json fájl kifejezetten a TypeScript vite.config.ts fájllal való átültetésének szabályozására szolgál, biztosítva, hogy kompatibilis legyen a Node.js-szel. A Vite, amely a frontend eszközöket szolgálja ki és építi fel, Node.js környezetben fut. Erre a szétválasztásra azért van szükség, mert a Vite konfigurációs fájl eltérő TypeScript-beállításokat igényelhet, mint a böngészőben való futtatásra szánt előtér-kód.

Az "types": ["vite/client"] beillesztése az tsconfig.json-be azért szükséges, mert a Vite olyan további tulajdonságokat biztosít az import.meta objektumon, amelyek nem részei a szabványos JavaScript- vagy TypeScript-könyvtárak, például az import.meta.env és import.meta.glob.

Közös mesekönyv konfiguráció

A .storybook könyvtár határozza meg a Storybook konfigurációját, a kiegészítőket és a dekorátorokat. Ez elengedhetetlen a Storybook viselkedésének testreszabásához és konfigurálásához.

├── main.ts
└── preview.ts

Az általános konfigurációkhoz itt van két fájl. Nézzük meg mindegyiket.

A main.ts a Storybook fő konfigurációs fájlja, és lehetővé teszi a Storybook viselkedésének szabályozását. Amint látja, csak a szokásos konfigurációkat exportáljuk, amelyeket minden csomagban újra felhasználunk.

A preview.ts lehetővé teszi, hogy a történeteket dekorátorokkal vonjuk be, amelyek segítségével kontextust biztosíthatunk, vagy stílusokat állíthatunk be történeteinkhez globálisan. Ezt a fájlt globális paraméterek konfigurálására is használhatjuk. Ezenkívül exportálja az általános konfigurációt a csomaghasználathoz.

Root package.json

Egy Lerna monorepo projektben a package.json hasonló szerepet tölt be, mint bármely más JavaScript vagy TypeScript projektben. Néhány szempont azonban a monoreposra jellemző.

A szkriptek kezelik a monorepót. Tesztek futtatása az összes csomagon vagy az összes csomag összeállítása. Ez a package.json magában foglalja azokat a fejlesztési függőségeket is, amelyek a monorepo több csomagja között vannak megosztva, például tesztelési könyvtárak vagy összeállítási eszközök. A private mező általában true-re van állítva ebben a package.json-ban, hogy elkerülje a véletlen közzétételt.

A szkriptek természetesen kibővíthetők más csomagokkal tesztelés, építés és így tovább, például:

"start:vite-footer": "lerna run --scope vite-footer storybook --stream",

Csomagszintű konfiguráció

Ami az összes konfigurációt a gyökérből exportáltuk a konfigurációk újrafelhasználásához, alkalmazzuk őket a csomagunk szintjén.

A Vite konfiguráció a root vite konfigurációt fogja használni, ahol csak a getBaseConfig függvényt importáljuk, és ott megadjuk a lib függvényt. Ezt a konfigurációt arra használjuk, hogy az összetevőcsomagunkat önálló könyvtárként építsük fel. Megadja a csomagunk belépési pontját, a könyvtár nevét és a kimeneti fájl nevét. Ezzel a konfigurációval a Vite egy lefordított fájlt generál, amely a megadott könyvtárnév alatt teszi közzé a komponenscsomagunkat, lehetővé téve annak használatát más projektekben vagy külön terjesztését.

A .storybook esetében ugyanezt a megközelítést alkalmazzuk. Csak importáljuk a commonConfigs-et.

És nézd meg az előnézetet is.

A .storybook mappából az utolsóhoz hozzá kell adnunk a preview-head.html-t.

És a legjobb az egészben az, hogy van egy elég tiszta package.json függőségek nélkül, mindannyian ezeket használjuk minden csomaghoz a gyökértől kezdve.

Az egyetlen különbség a vite-common, ami az a függőség, amelyet a Footer komponensben használunk.

Alkatrészek

Ha komponenscsomagjainkat ilyen módon szervezzük, könnyedén kezelhetjük és közzétehetjük az egyes csomagokat egymástól függetlenül, miközben megosztjuk a monorepo által biztosított közös függőségeket és infrastruktúrát.

Nézzük meg a Footer komponens src mappáját. A többi összetevő azonos lesz, de a konfiguráció csak a különbséget jelenti.

├── assets
│   └── flow.svg
├── components
│   ├── Footer
│   │   ├── Footer.stories.tsx
│   │   └── index.tsx
│   └── index.ts
├── index.ts
└── vite-env.d.ts

A src mappában található vite-env.d.ts fájl segít a TypeScript számára, hogy megértse és pontos típusellenőrzést biztosítson a Vite-hoz kapcsolódó kódhoz a projektünkben. Biztosítja, hogy a TypeScript felismerje és ellenőrizhesse a Vite-specifikus tulajdonságokat, funkciókat és szolgáltatásokat.

A src mappában a index.ts tartalmazza:

export * from "./components";

A vite-common komponenst fogyasztó komponens pedig így néz ki:

Így néz ki a stories az összetevőhöz:

Ebben a példában négy csomagot használunk, de a megközelítés ugyanaz. Miután létrehozta az összes csomagot, képesnek kell lennie önállóan összeállítani, futtatni és tesztelni őket. Mielőtt mindegyik a gyökérszintre kerülne, futtassa a yarn install, majd a yarn build parancsot az összes csomag összeállításához, vagy építse fel a yarn build:vite-common-ot, és már használhatja a csomagot a többi csomagban.

Közzététel

Az összes csomag közzétételéhez a monorepo-ban használhatjuk a npx lerna publish parancsot. Ez a parancs végigvezet minket az egyes csomagok verziószámításán és közzétételén a végrehajtott változtatások alapján.

lerna notice cli v6.6.2
lerna info versioning independent
lerna info Looking for changed packages since [email protected]
? Select a new version for vite-body (currently 1.0.0) Major (2.0.0)
? Select a new version for vite-common (currently 2.0.0) Patch (2.0.1)
? Select a new version for vite-footer (currently 1.0.0) Minor (1.1.0)
? Select a new version for vite-header (currently 1.0.0) 
  Patch (1.0.1) 
❯ Minor (1.1.0) 
  Major (2.0.0) 
  Prepatch (1.0.1-alpha.0) 
  Preminor (1.1.0-alpha.0) 
  Premajor (2.0.0-alpha.0) 
  Custom Prerelease 
  Custom Version 

A Lerna minden egyes csomagverziót megkér tőlünk, majd közzéteheti.

lerna info execute Skipping releases
lerna info git Pushing tags...
lerna info publish Publishing packages to npm...
lerna success All packages have already been published. 

Következtetés

Szilárd architektúra megoldást kerestem a frontend komponensek szervezetéhez abban a cégben, ahol dolgozom. Minden projekthez van egy hatékony, hatékony fejlesztői környezetünk általános szabályokkal, amelyek segítenek függetlenné válni. Ez a kombináció egyszerűsített függőségkezelést, elkülönített komponenstesztelést és egyszerűsített közzétételt tesz lehetővé.

Hivatkozások

Adattár: https://github.com/antonkalik/lerna-monorepo-boilerplate
Vite with Storybook: https://storybook.js.org/blog/storybook-for-vite