Monorepo -Konzepte, Tipps und Tricks, die sich um NextJs orientieren
Howtos für Monorepo. Neu in Monorepos? Überprüfen Sie diese FAQ. Dieses Beispiel wird von Turborepo und Garn 4 mit A / TypeScript -Pfad -Aliases -Ansatz verwaltet. Nicht der einzige Weg zu tun.
Nützlich zu
Wenn Sie einige meiner OSS -Arbeiten in Ihrer Firma genießen, würde ich einen Sponsoring, einen Kaffee oder einen abgesetzten Star sehr schätzen. Das gibt mir etwas mehr Zeit, um es auf die nächste Stufe zu verbessern.
| Jetbrains | Embie.be | Vercel |
corepack enable
yarn install .
├── apps
│ ├── nextjs-app (i18n, ssr, api, vitest)
│ └── vite-app
└── packages
├── common-i18n (locales...)
├── core-lib
├── db-main-prisma
├── eslint-config-bases (to shared eslint configs)
└── ui-lib (emotion, storybook)
Apps sollten nicht von Apps abhängen, sie können von Paketen abhängen
Apps können von Paketen abhängen, Pakete können voneinander abhängen ...
.
├── apps
│ ├── vite-app (Vite app as an example)
│ │ ├── src/
│ │ ├── package.json (define package workspace:package deps)
│ │ └── tsconfig.json (define path to packages)
│ │
│ └── nextjs-app (NextJS app with api-routes)
│ ├── e2e/ (E2E tests with playwright)
│ ├── public/
│ ├── src/
│ │ └── pages/api (api routes)
│ ├── CHANGELOG.md
│ ├── next.config.mjs
│ ├── package.json (define package workspace:package deps)
│ ├── tsconfig.json (define path to packages)
│ └── vitest.config.ts
│
├── packages
│ ├── core-lib (basic ts libs)
│ │ ├── src/
│ │ ├── CHANGELOG.md
│ │ ├── package.json
│ │ └── tsconfig.json
│ │
│ ├── db-main-prisma (basic db layer with prisma)
│ │ ├── e2e/ (E2E tests)
│ │ ├── prisma/
│ │ ├── src/
│ │ ├── CHANGELOG.md
│ │ ├── package.json
│ │ └── tsconfig.json
│ │
│ ├── eslint-config-bases
│ │ ├── src/
│ │ ├── CHANGELOG.md
│ │ ├── package.json
│ │ └── tsconfig.json
│ │
│ └── ui-lib (basic design-system in react)
│ ├── src/
│ ├── CHANGELOG.md
│ ├── package.json
│ └── tsconfig.json
│
├── static (no code: images, json, locales,...)
│ ├── assets
│ └── locales
├── docker (docker...)
│ ├── .dockerignore
│ ├── docker-compose.yml (compose specific for nextjs-app)
│ ├── docker-compose.db.yml (general services like postgresql...)
│ └── Dockerfile (multistage build for nextjs-app)
├── .yarnrc.yml
├── package.json (the workspace config)
└── tsconfig.base.json (base typescript config)
{
"name" : "nextjs-monorepo-example" ,
// Set the directories where your apps, packages will be placed
"workspaces" : [ "apps/*" , "packages/*" ] ,
//...
} Der Paketmanager scannt diese Verzeichnisse und sucht nach Children package.json . Ihr Inhalt wird verwendet, um die Arbeitsbereichstopologie (Apps, Libs, Abhängigkeiten ...) zu definieren.
Erstellen Sie einen Ordner in ./Packages/ Verzeichnis mit dem Namen Ihres Pakets.
mkdir packages/magnificent-poney
mkdir packages/magnificent-poney/src
cd packages/magnificent-poneyInitialisieren Sie ein Paket.json mit dem Namen Ihres Pakets.
Anstatt
yarn initeinzugeben, nehmen Sie es vor, die ./packages/ui-lib/package.json als Arbeitsbeispiel zu nutzen und seine Werte zu bearbeiten.
{
"name" : "@your-org/magnificent-poney" ,
"version" : "0.0.0" ,
"private" : true ,
"scripts" : {
"clean" : "rimraf ./tsconfig.tsbuildinfo" ,
"lint" : "eslint . --ext .ts,.tsx,.js,.jsx" ,
"typecheck" : "tsc --project ./tsconfig.json --noEmit" ,
"test" : "run-s 'test:*'" ,
"test:unit" : "echo "No tests yet"" ,
"fix:staged-files" : "lint-staged --allow-empty" ,
"fix:all-files" : "eslint . --ext .ts,.tsx,.js,.jsx --fix" ,
} ,
"devDependencies" : {
"@your-org/eslint-config-bases" : "workspace:^" ,
} ,
}Fügen Sie zuerst das Paket dem App -Paket hinzu.json. Die empfohlene Möglichkeit besteht darin, das von Garn und PNPM unterstützte Arbeitsbereichsprotokoll zu verwenden.
cd apps/my-app
yarn add @your-org/magnificent-poney@ ' workspace:^ 'Inspiration finden Sie in Apps/Nextjs-App/Package.json.
{
"name" : "my-app" ,
"dependencies" : {
"@your-org/magnificient-poney" : "workspace:^" ,
} ,
} Fügen Sie dann in der App tsconfig.json einen Typscript -Pfad -Alias hinzu. Auf diese Weise können Sie es direkt importieren (kein Build benötigt)
Inspiration finden Sie in Apps/Nextjs-App/tsconfig.json.
{
"compilerOptions" : {
"baseUrl" : "./src" ,
"paths" : {
// regular app aliases
"@/components/*" : [ "./components/*" ] ,
// packages aliases, relative to app_directory/baseUrl
"@your-org/magnificent-poney/*" : [
"../../../packages/magnificent-poney/src/*" ,
] ,
"@your-org/magnificent-poney" : [
"../../../packages/magnificent-poney/src/index" ,
] ,
} ,
} ,
}PS:
- Versuchen Sie nicht, Aliase in der globalen tsonfig.base.json festzulegen, um streng mit Diagrammabhängigkeiten zu halten.
- Mit dem Stern in
@your-org/magnificent-poney/*können Sie Unterordner importieren. Wenn Sie eine Barrel -Datei (index.ts) verwenden, kann der Alias mit Stern entfernt werden.
Bearbeiten Sie Ihren next.config.mjs und aktivieren Sie die Option Experiment.externaldir. Feedbacks hier.
const nextConfig = {
experimental : {
externalDir : true ,
} ,
} ;Wenn Sie eine ältere NextJS -Version verwenden und nicht über das experimentelle Flag verfügen, können Sie einfach Ihre Webpack -Konfiguration überschreiben.
const nextConfig = {
webpack : ( config , { defaultLoaders } ) => {
// Will allow transpilation of shared packages through tsonfig paths
// @link https://github.com/vercel/next.js/pull/13542
const resolvedBaseUrl = path . resolve ( config . context , "../../" ) ;
config . module . rules = [
... config . module . rules ,
{
test : / .(tsx|ts|js|jsx|json)$ / ,
include : [ resolvedBaseUrl ] ,
use : defaultLoaders . babel ,
exclude : ( excludePath ) => {
return / node_modules / . test ( excludePath ) ;
} ,
} ,
] ;
return config ;
} ,
} ;PS: Wenn Ihr freigegebenes Paket SCSS-Bundler verwendet, ist eine benutzerdefinierte Webpack-Konfiguration erforderlich oder nutzen Sie die Nächstenübertragungsmodule, siehe FAQ unten.
Die Pakete sind jetzt mit Ihrer App verknüpft. Importieren Sie sie einfach wie reguläre Pakete: import { poney } from '@your-org/magnificent-poney' .
Optional
Wenn Sie einige Pakete außerhalb des Monorepo teilen müssen, können Sie sie an NPM- oder privaten Repositories veröffentlichen. In jedem Paket ist ein Beispiel basierend auf Mikrobund. Versioning und Veröffentlichung kann mit Atlassian/ChangeSet durchgeführt werden und ist einfach wie das Tippen:
$ yarn g:changesetBefolgen Sie die Anweisungen ... und begehen Sie die Änderungsset -Datei. Ein "Versionspaket" -P/R wird nach CI -Überprüfungen angezeigt. Im Zusammenhang mit einer GitHub -Aktion veröffentlichen die Pakete mit der resultierenden SEMVER -Version und generieren ChangeLogs für Sie.
PS:
- Auch wenn Sie nicht veröffentlichen müssen, kann ChangeSet einen automatisierten ChangeLog für Ihre Apps beibehalten. Hübsch !
- Um die automatische Veröffentlichung einiger Pakete zu deaktivieren, setzen Sie einfach
"private": "true"in ihrem Paket.json.- Ich möchte das Verhalten einstellen, siehe .Changeset/config.json.
Einige Convenience -Skripte können in einem beliebigen Ordner dieses Repo ausgeführt werden und rufen ihre in Paketen und Apps definierten Kollegen auf.
| Name | Beschreibung |
|---|---|
yarn g:changeset | Fügen Sie einen Änderungssatz hinzu, um eine neue Version zu deklarieren |
yarn g:codegen | Führen Sie CodeGen in allen Arbeitsbereichen aus |
yarn g:typecheck | Führen Sie typecks in allen Arbeitsbereichen aus |
yarn g:lint | Zeigen Sie in allen Arbeitsbereichen Linterprobleme an |
yarn g:lint --fix | Versuchen Sie, eine Linter automatisch in allen Arbeitsbereichen auszuführen |
yarn g:lint-styles | Zeigen Sie CSS -Stylelint -Probleme in allen Arbeitsbereichen an |
yarn g:lint-styles --fix | Versuchen Sie, Stylelint Auto-Fix-Probleme in allen Arbeitsbereichen auszuführen |
yarn g:test | Führen Sie Einheits- und E2E -Tests in allen Arbeitsbereichen aus |
yarn g:test-unit | Führen Sie Unit -Tests in allen Arbeitsbereichen aus |
yarn g:test-e2e | Führen Sie E2E -Tests in allen Arbeitsbereichen aus |
yarn g:build | Führen Sie alle Arbeitsbereiche aus |
yarn g:clean | Reinigen Sie Builds in allen Arbeitsbereichen |
yarn g:check-dist | Stellen Sie sicher, dass Build DIST -Dateien ES2017 (Ausführen g:build zuerst). |
yarn g:check-size | Stellen Sie sicher, dass die Browser -DIST -Dateien innerhalb der Größengrenze liegen (zuerst ausführen g:build ). |
yarn clean:global-cache | Clean Tooling Caches (Eslint, Scherz ...) |
yarn deps:check --dep dev | Drucken, welche Pakete weltweit aktualisiert werden können (siehe auch .ncurc.yml) |
yarn deps:update --dep dev | Wenden Sie mögliche Updates an (Führen Sie yarn install && yarn dedupe nach) an) |
yarn install:playwright | Installieren Sie Dramatiker für E2E |
yarn dedupe | Integrierte Garndeduplizierung der Sperrdatei |
Warum verwenden
:Vorverfixieren von Skriptsnamen? In Garn 3+ ist es bequem, wir können diese Skripte von jedem Ordner im Monorepo aufrufen.g:Ist eine Abkürzung fürglobal:. Siehe die vollständige Liste in root package.json.
Die Global Commands yarn deps:check und yarn deps:update hilft dabei, die gleichen Versionen über den gesamten Monorepo zu führen. Sie basieren auf den hervorragenden NPM-Check-Updates (siehe Optionen, dh yarn check:deps -t minor ).
Nach dem Ausführen
yarn deps:updateist eineyarn installerforderlich. Um zu verhindern, dass Duplikate im Garn zu haben.locke, können Sieyarn dedupe --checkundyarn dedupeum eine Deduplizierung anzuwenden. Die doppelte Überprüfung wird in den Beispiel -Github -Aktionen durchgesetzt.
Siehe ein Beispiel in ./apps/nextjs-app/.eslintrc.js und unsere Eslint-config-Basen.
Überprüfen Sie den Inhalt des .husky -Ordners, um zu sehen, welche Hooks aktiviert sind. In Lint-Stage wird sichergestellt, dass Lint und schöner automatisch im Commit und/oder in Pushes angewendet werden.
Die Tests basieren je nach App auf TS-Jest oder Vitest. Alle Setups unterstützen Aliase von TypeScript -Pfad. React-Testing-Bibliothek wird aktiviert, wenn React beteiligt ist.
Die Konfiguration lebt im Stammordner jeder Apps/Pakete. Als Beispiel siehe siehe
Sie finden einige Beispiel -Workflows für die GitHub -Aktion in .github/Workflows. Standardmäßig stellen sie das sicher, dass
Jeder dieser Schritte kann ausgelöst werden.
Um eine anständige Leistung zu gewährleisten, sind diese Funktionen in den Beispielaktionen vorhanden:
Paketspeicher (node_modules ...) - Rund 25s installieren
Ausgespeicher von NextJs früherer Build - rund 20er Jahre gebaut
Ausgelöst, wenn sie mit Aktionenpfaden geändert werden , dh:
paths: - "apps/nextjs-app/**" - "packages/**" - "package.json" - "tsconfig.base.json" - "yarn.lock" - ".yarnrc.yml" - ".github/workflows/**" - ".eslintrc.base.json" - ".eslintignore"
Das Eslint -Plugin erfordert, dass die Einstellung eslint.workingDirectories festgelegt ist:
"eslint.workingDirectories": [
{
"pattern": "./apps/*/"
},
{
"pattern": "./packages/*/"
}
],
Weitere Informationen hier
Vercel unterstützt nativ Monorepos, siehe das Dokument von Vercel-Monorepo-Deploy.
Es gibt ein grundlegendes Beispiel für das Erstellen eines Docker -Images, lesen Sie den Docker -Dokument.
Netlify, AWS-Amplify, K8S-Docker, serverlose-NextJS-Rezepte könnten in Zukunft hinzugefügt werden. PR ist auch willkommen.
Apps -Abhängigkeiten und DevDependenzen sind an genaue Versionen festgehalten. Pakete DEPS verwenden SEMVER -kompatible. Weitere Informationen zu dieser Änderung finden Sie hier und in unserer Konfigurationsdatei renovabot.json5.
Um DEPs auf dem neuesten Stand zu halten, finden Sie in den yarn deps:check && yarn deps:update Skripte und / oder verwenden Sie den Renovatebot.
Beim Hinzufügen einer DEP durch Garn-CLI (dh Garn Hinzufügen etwas) ist es möglich, das Verhalten des Speicherns automatisch durch Einstellen
defaultSemverRangePrefix: ""in arnrc.yml. Dies würde jedoch auch die Standardeinstellung für Pakete/* machen. Besser mityarn add something --exactausschließlich pro Case.