typescript - Hur installerar man npm-beroenden effektivt för flera dockeriserade node.js-projekt i en monorepo?
Jag har ett monorepo-projekt som innehåller 10 paket, låt oss säga. Var och en av dessa paket har en Dockerfile, med ett separat npm install-kommando. Varje npm install-kommando tar cirka 10 minuter på egen hand. Att bygga alla bilder tar 10 x 10 minuter, vilket är oacceptabelt.
Vad jag har kommit fram till hittills: Skapa en Dockerfile där jag kopierar hela monorepot på en gång, gör ett npm install där, vilket bara tar ~15 minuter, eftersom det finns många gemensamma beroenden. Därifrån kan jag bara använda detta som basbild för alla andra bilder. Det enda problemet är att denna basbild är 5 gigabyte, vilket är enormt, eftersom den innehåller node_modules-mappen, som nu innehåller ALLA beroenden från varje projekt.
Kopiera endast nödvändiga mappar från node_modules? Finns det ett kommando i npm som listar alla beroenden för en package.json-fil (med alla peer-beroenden etc.) så att jag kan filtrera vad jag kopierar från basbildens node_modules-mapp till den slutliga bilden (och på så sätt minska storleken utan att ladda ner vanliga beroenden flera gånger)? Kanske ett redan etablerat verktyg som kan göra just det?
Bundla node_modules?: En annan idé jag hade är att bundla appen, vilket bara skulle inkludera i den slutliga bundlen den kod paketet faktiskt använder, så genom att använda multi-stage builds skulle den slutliga imagen kunna bli mycket liten. Det här är vad jag redan använder för frontend-delen av applikationen (med Vite eller CRA tidigare) men jag har inte lyckats få det att fungera för Node.js. Troligtvis för att pg-native kan ha några binärer som inte kan bundlas. Ändå skulle det vara den BÄSTA lösningen att bundla allt till en 5 MB stor JS-fil och installera bara problematiska beroenden efteråt som pg-native. Jag har inte hittat någon handledning eller beskrivning om detta överhuvudtaget, så jag är inte särskilt säker på att detta ens kan uppnås, och jag har ingen aning ... varför?
Löjligt ineffektiva svar jag har hittat hittills inkluderar:
- minska beroenden - det är inte möjligt, kontrollerade 3 gånger med
depcheck - installerar endast produktionsberoenden - sparar bara några få MB, inget betydande
- använda flerstegsbyggen - det är en bra lösning att starta en färsk bild, om du har byggartefakter i "builder"-bilden, men i mitt fall minskar det inte node_modules storleken, bara i frontend-bilden, eftersom där node_modules är bundlade till en js-fil, och inte nödvändiga under körning.
- använder node:x-alpine-bild - använder den redan, den sparar 500 MB, men det är också obetydligt jämfört med de 3-4 gigabyte node_modules som jag måste kopiera överallt.
Slutligen, en liten förklaring till varför detta är viktigt för mig: Jag använder Builx med en docker-container driver, vilket är nödvändigt för att dra nytta av caching via gha eller lokala caching-typer som sätts via --cache-to-alternativet. Docker-container-drivern har en mycket långsam fas, kallad sending tarball, och den är direkt relaterad till bildstorleken. Nedladdning och uppladdning av cache från GHA:s cachelagring påverkas också mycket av cachestorleken. Så på papperet, om vi tar ~600mb-bilder istället för ~4000mb-bilder, skulle hela processen kunna snabbas upp med 6-7 gånger. Det är en stor förbättring, utan att ens nämna hur kostnadseffektivt det skulle vara, eftersom allt i molnet debiteras per sekund av beräkningskraft/lagring som används.
Skål