Concepts, conseils et astuces de monorepo orientés autour de NextJS
Howtos pour monorepo. Nouveau sur Monorepos? Vérifiez cette FAQ. Cet exemple est géré par TurborePo et Yarn 4 avec l'approche A / TypeScript Path Aliases. Pas la seule façon de faire.
Utile à
Si vous appréciez une partie de mon travail OSS dans votre entreprise, j'apprécierais vraiment un parrainage, un café ou une étoile abandonnée. Cela me donne plus de temps pour l'améliorer au niveau supérieur.
| Brains de jet | 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)
Les applications ne doivent pas dépendre des applications, elles peuvent dépendre des packages
Les applications peuvent dépendre des packages, les packages peuvent dépendre les uns des autres ...
.
├── 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/*" ] ,
//...
} Le gestionnaire de packages analysera ces répertoires et recherchera des enfants package.json . Leur contenu est utilisé pour définir la topologie de l'espace de travail (applications, libs, dépendances ...).
Créez un dossier dans ./packages/ répertoire avec le nom de votre package.
mkdir packages/magnificent-poney
mkdir packages/magnificent-poney/src
cd packages/magnificent-poneyInitialisez un package.json avec le nom de votre package.
Plutôt que de taper
yarn init, préfèrez prendre le ./packages/ui-lib/package.json comme exemple de travail et modifier ses valeurs.
{
"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:^" ,
} ,
}Ajoutez d'abord le package à l'application package.json. Le moyen recommandé est d'utiliser le protocole d'espace de travail pris en charge par le fil et la PNPM.
cd apps/my-app
yarn add @your-org/magnificent-poney@ ' workspace:^ 'L'inspiration peut être trouvée dans Apps / NextJS-App / Package.json.
{
"name" : "my-app" ,
"dependencies" : {
"@your-org/magnificient-poney" : "workspace:^" ,
} ,
} Ajoutez ensuite un alias de chemin de type dactylographié dans l'application tsconfig.json. Cela vous permettra de l'importer directement (aucune construction nécessaire)
L'inspiration peut être trouvée dans 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:
- N'essayez pas de définir des alias dans le Global tSonfig.base.json pour rester strict avec les dépendances des graphiques.
- L' étoile dans
@your-org/magnificent-poney/*vous permet d'importer des sous-dossiers. Si vous utilisez un fichier de baril (index.ts), l'alias avec l'étoile peut être supprimé.
Modifiez votre next.config.mjs et activez l'option expérimentale.externaldir. Vos commentaires ici.
const nextConfig = {
experimental : {
externalDir : true ,
} ,
} ;Si vous utilisez une ancienne version NextJS et que vous n'avez pas l'indicateur expérimental, vous pouvez simplement remplacer votre configuration WebPack.
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: Si votre package partagé utilise SCSS Bundler ... Une configuration Webpack personnalisée sera nécessaire ou utilise des modules de transpulation suivants, voir FAQ ci-dessous.
Les packages sont désormais liés à votre application, il suffit de les importer comme des packages réguliers: import { poney } from '@your-org/magnificent-poney' .
Facultatif
Si vous avez besoin de partager certains packages en dehors du monorepo, vous pouvez les publier sur NPM ou des référentiels privés. Un exemple basé sur la microbundle est présent dans chaque package. Le versioning et la publication peuvent être faits avec Atlassian / changeset, et c'est simple comme tapant:
$ yarn g:changesetSuivez les instructions ... et commettez le fichier ModigeSet. Un "packages de version" P / R apparaîtra après les vérifications CI. Lors de la fusion, une action GitHub publiera les packages avec la version SEMVER résultante et générera des changelogs pour vous.
PS:
- Même si vous n'avez pas besoin de publier, ChangeSet peut maintenir un changelog automatisé pour vos applications. Bon !
- Pour désactiver la publication automatique de certains packages, définissez simplement
"private": "true"dans leur package.json.- Vous voulez régler le comportement, voir .changeset / config.json.
Certains scripts de commodité peuvent être exécutés dans n'importe quel dossier de ce dépôt et appellent leurs homologues définis dans des packages et des applications.
| Nom | Description |
|---|---|
yarn g:changeset | Ajouter un ensemble de modifications pour déclarer une nouvelle version |
yarn g:codegen | Exécutez CodeGen dans tous les espaces de travail |
yarn g:typecheck | Exécutez des typèques dans tous les espaces de travail |
yarn g:lint | Afficher les problèmes de linter dans tous les espaces de travail |
yarn g:lint --fix | Tenter d'exécuter Linter Auto-Fix dans tous les espaces de travail |
yarn g:lint-styles | Afficher les problèmes CSS Stylelint dans tous les espaces de travail |
yarn g:lint-styles --fix | Tenter d'exécuter des problèmes de fixe automatique de stylelint dans tous les espaces de travail |
yarn g:test | Exécuter l'unité et les tests E2E dans tous les espaces de travail |
yarn g:test-unit | Exécutez des tests unitaires dans tous les espaces de travail |
yarn g:test-e2e | Exécutez les tests E2E dans tous les espaces de travail |
yarn g:build | Exécutez la construction dans tous les espaces de travail |
yarn g:clean | Clean Builds dans tous les espaces de travail |
yarn g:check-dist | Assurez-vous que Build Dist Files passe ES2017 (exécutez g:build en premier). |
yarn g:check-size | Assurez-vous que les fichiers DIST du navigateur sont dans la limite de taille (Exécutez g:build en premier). |
yarn clean:global-cache | Caches d'outillage propres (Eslint, plaisantant ...) |
yarn deps:check --dep dev | Imprimera ce que les packages peuvent être mis à niveau à l'échelle mondiale (voir aussi .ncurc.yml) |
yarn deps:update --dep dev | Appliquer les mises à jour possibles (exécutez yarn install && yarn dedupe après) |
yarn install:playwright | Installer le dramaturge pour E2E |
yarn dedupe | Déduplication de fil intégrée du fichier de verrouillage |
Pourquoi utiliser
:pour préfixer les noms de scripts? C'est pratique dans YARN 3+, nous pouvons appeler ces scripts de n'importe quel dossier du monorepo.g:est un raccourci pourglobal:. Voir la liste complète dans root package.json.
Les commandes globales yarn deps:check et yarn deps:update aidera à maintenir les mêmes versions dans l'ensemble du monorepo. Ils sont basés sur les excellentes dates NPM-Check (voir les options, c'est-à-dire: yarn check:deps -t minor ).
Après avoir exécuté
yarn deps:update, uneyarn installest requise. Pour éviter d'avoir des doublons dans le bloc de Yarn, vous pouvez exécuteryarn dedupe --checketyarn dedupepour appliquer la déduplication. La vérification en double est appliquée dans l'exemple des actions GitHub.
Voir un exemple dans ./apps/nextjs-app/.eslintrc.js et nos Eslint-Config-Bases.
Vérifiez le contenu du dossier .husky pour voir quels crochets sont activés. La peluche est utilisée pour garantir que les peluches et les plus jolies sont appliqués automatiquement sur la validation et / ou les poussées.
Les tests s'appuient sur TS-Jest ou le plus vitre en fonction de l'application. Toutes les configurations prennent en charge les alias de chemin de TypeScript. React-Testing-Library est activé chaque fois que React est impliqué.
La configuration vit dans le dossier racine de chaque application / packages. Comme exemple voir
Vous trouverez quelques exemples de workflows pour l'action GitHub dans .github / workflows. Par défaut, ils veilleront à ce que
Chacune de ces étapes peut être désactivée.
Pour garantir des performances décentes, ces fonctionnalités sont présentes dans l'exemple d'actions:
Cache de packages (Node_modules ...) - Installez environ 25s
Mise en cache de NextJS Build précédente - Construit environ la vingtaine
Déclenché lorsqu'il est modifié à l'aide de chemins d'actions, c'est-à-dire:
paths: - "apps/nextjs-app/**" - "packages/**" - "package.json" - "tsconfig.base.json" - "yarn.lock" - ".yarnrc.yml" - ".github/workflows/**" - ".eslintrc.base.json" - ".eslintignore"
Le plugin Eslint nécessite que le paramètre eslint.workingDirectories soit défini:
"eslint.workingDirectories": [
{
"pattern": "./apps/*/"
},
{
"pattern": "./packages/*/"
}
],
Plus d'informations ici
Vercel Support Native Monorepos, voir le document Vercel-Monorepo-Deploit.
Il y a un exemple de base pour construire une image Docker, lire le doc docker.
Les recettes Netlify, AWS-AMPLIFY, K8S-Docker, Serverless-NextJS pourraient être ajoutées à l'avenir. Les relations publiques sont également bien accueillies.
Les dépendances des applications et les dépenses sont épinglées sur les versions exactes. Les Packages Deps utiliseront des SEMVER compatibles. Pour plus d'informations sur ce changement, voir le raisonnement ici et notre fichier de configuration Renovabot.json5.
Pour aider à maintenir les DEP à jour, consultez les yarn deps:check && yarn deps:update les scripts et / ou utilisez le RenovateBot.
Lors de l'ajout d'un CLI DE DEP via le fil (c'est-à-dire: le fil Ajouter quelque chose), il est possible de définir automatiquement le comportement de sauvegarde-exact en définissant
defaultSemverRangePrefix: ""dans yarnrc.yml. Mais cela ferait également la valeur par défaut des packages / *. Mieux vaut géreryarn add something --exactau cas.