Escena Viva ja té manifest, però el seu bloc de dependències continua buit. Avui el trenquem: instal·larem els primers paquets del projecte i, sobretot, aprendrem a decidir quins mereixen entrar-hi.

Aquesta segona part importa més que la primera. Teclejar npm install alguna-cosa s'aprèn en deu segons; saber si aquesta "alguna cosa" estarà mantinguda d'aquí a dos anys, quantes dependències arrossega amb ella, si la seva llicència és compatible amb la teva empresa i si el nucli de Node ja fa el mateix, això és criteri d'enginyeria. I tu véns d'escriure un mòdul sencer —servidor, enrutador, estàtics, client HTTP— sense cap dependència, així que ja saps per experiència que "instal·lar un paquet" no és l'única resposta possible a un problema.

Contingut

  1. npm install <paquet>: què canvia al disc i al manifest
  2. dependencies davant de devDependencies
  3. Per què la distinció importa de debò en el desplegament
  4. peerDependencies i optionalDependencies
  5. Instal·lar una versió, un rang, una etiqueta o un repositori git
  6. Instal·lació global: quan es justifica (gairebé mai)
  7. Triar una dependència amb criteri
  8. Les primeres dependències reals d'Escena Viva
  9. Com resol Node un paquet instal·lat
  10. Inspeccionar i mantenir: ls, outdated, update, uninstall
  11. L'arbre, l'aplanament i les versions duplicades

  1. npm install <paquet>: què canvia al disc i al manifest

Anem amb l'exemple canònic:

npm install dotenv
added 1 package, and audited 2 packages in 612ms

found 0 vulnerabilities

Darrere d'aquestes dues línies han passat cinc coses concretes:

Què canvia Detall
package.json Apareix un bloc dependencies amb "dotenv": "^17.2.1"
package-lock.json Es crea (o s'actualitza) amb la versió exacta resolta i el seu hash
node_modules/ Es crea la carpeta amb dotenv a dins i el seu propi package.json
node_modules/.bin/ S'enllacen els executables que declari el paquet (dotenv no en porta)
Memòria cau de npm El tarball descarregat queda a ~/.npm/_cacache per a futures instal·lacions

Fixa't en el rang: has demanat dotenv a seques i npm ha escrit ^17.2.1, no 17.2.1. Aquest accent circumflex és el comportament per defecte i significa "aquesta versió o qualsevol posterior compatible". És el tema central de 05-03; avui n'hi ha prou de saber que npm no fixa versions exactes tret que li ho demanis.

I una comprovació que convé fer un cop a la vida: ls node_modules/dotenv revela CHANGELOG.md LICENSE README.md config.js lib package.json. No hi ha res exòtic allà dins: és un projecte Node normal, amb el seu package.json i el seu codi. Tot el que has après en quatre mòduls s'aplica també al que instal·les.

  1. dependencies davant de devDependencies

npm distingeix dos blocs principals, i la diferència és purament contractual: no canvia com s'instal·len a la teva màquina, canvia què s'instal·la en producció.

npm install dotenv               # -> dependencies
npm install --save-dev prettier  # -> devDependencies  (alias: -D)
dependencies devDependencies
Pregunta clau El necessita el codi en execució? El necessito només per desenvolupar?
S'instal·la amb npm install Sí Sí
S'instal·la amb npm install --omit=dev Sí No
Exemples típics express, mongoose, dotenv, zod eslint, prettier, mocha, nodemon
Regla mental Apareix en un require de src/ Només apareix a scripts o a test/

La regla mental de l'última fila resol el 95 % dels casos: si un fitxer de src/ fa require d'aquest paquet, és una dependència de producció. Si només l'invoquen els teus scripts o les teves proves, és de desenvolupament.

Així queda el repartiment a Escena Viva al llarg del curs:

Paquet Bloc Per què
dotenv dependencies src/config/ el requereix en arrencar el servidor
express (M6) dependencies És el servidor en execució
helmet, cors, morgan (M6) dependencies Middleware que corre en producció
mongoose (M7) dependencies Accés a dades en execució
bcrypt, jsonwebtoken (M8) dependencies Autenticació en execució
prettier devDependencies Només formata codi font
eslint devDependencies Només analitza codi font
mocha, chai, sinon, supertest (M9) devDependencies Només s'executen a les proves
nyc / cobertura (M9) devDependencies Només a les proves

Hi ha un cas que enganya: una eina que genera codi que sí que s'executa en producció. Un compilador o un empaquetador són devDependencies encara que el seu resultat es desplegui, perquè el que viatja al servidor és la sortida, no l'eina.

  1. Per què la distinció importa de debò en el desplegament

Molta gent classifica a l'atzar perquè "a la meva màquina funciona igual". I és veritat: en desenvolupament, npm install instal·la tots dos blocs. La factura arriba al servidor.

# Al servidor de produccio, o al Dockerfile del Modul 11
npm ci --omit=dev

Tres conseqüències molt concretes:

Mida. Un projecte amb Express, Mongoose i una bateria de proves completa pot tenir 90 MB de node_modules en desenvolupament i 25 MB amb --omit=dev. En una imatge Docker que es reconstrueix i es descarrega a cada desplegament, aquesta diferència es paga a cada desplegament, cada dia.

Temps d'instal·lació. Menys paquets per descarregar, verificar i extreure. A la CI del Mòdul 11, on això passa a cada confirmació, es nota.

Superfície d'atac. Aquesta és la raó de pes. Cada paquet instal·lat és codi aliè que pot executar-se amb els permisos del teu procés. Les eines de desenvolupament solen ser les més pesades en dependències transitives —un linter complet arrossega desenes de paquets— i cap d'elles no té motiu per ser en un servidor de producció. Treure-les és reduir el risc sense perdre res. Hi tornarem amb dades a 05-06.

Nota històrica: --omit=dev substitueix l'antic --production, que encara funciona però està obsolet. Veuràs --production en tutorials antics i en Dockerfile heretats.

I el corol·lari: si classifiques malament una dependència de producció com a devDependencies, l'aplicació funciona al teu portàtil i peta al servidor amb un Error: Cannot find module. És una de les fallades de desplegament més freqüents i més desconcertants, perquè el codi és idèntic. Si algun dia la pateixes, mira primer el bloc on és el mòdul que falta.

  1. peerDependencies i optionalDependencies

Hi ha dos blocs més que poques vegades escriuràs com a consumidor, però que veuràs constantment als paquets que instal·les.

peerDependencies diu: "necessito que tu, el projecte amfitrió, tinguis instal·lat això; jo no ho porto". El seu cas d'ús és el dels complements. Un plugin d'ESLint declara eslint com a parell: no té sentit que el plugin porti la seva pròpia còpia d'ESLint, perquè aleshores hi hauria dos ESLint diferents i el plugin no veuria la configuració del que de debò s'executa.

"peerDependencies": {
  "eslint": ">=9.0.0"
}

Des de npm 7, les dependències de parell s'instal·len automàticament si falten, i npm falla si la versió que tens no compleix el rang. Abans només avisava, i aquesta és la causa dels famosos ERESOLVE unable to resolve dependency tree en instal·lar plugins antics.

optionalDependencies diu: "intenta instal·lar això; si falla, tira endavant sense error". El cas clàssic són els binaris natius compilats per sistema operatiu: un paquet pot oferir una versió ràpida en C++ i una alternativa en JavaScript pur si la compilació no funciona. El codi del paquet comprova en temps d'execució si el mòdul opcional està disponible.

Bloc Qui l'instal·la Si falla
dependencies npm, sempre Error, s'avorta
devDependencies npm, tret de --omit=dev Error, s'avorta
peerDependencies npm 7+ si falta Error si la versió no encaixa
optionalDependencies npm, si pot S'ignora i continua

  1. Instal·lar una versió, un rang, una etiqueta o un repositori git

npm install accepta un especificador després del nom:

npm install [email protected]          # versio exacta
npm install dotenv@"^17.0.0"       # rang (cometes: ^ es especial al shell)
npm install dotenv@latest          # ultima estable publicada
npm install express@next           # etiqueta de preproduccio
npm install lodash@">=4 <5"        # rang compost

Les etiquetes de distribució (dist-tags) són àlies amb nom que apunten a una versió concreta. Tot paquet en té almenys latest; molts publiquen també next, beta o canary. Mira-les amb:

npm dist-tag ls express
beta: 5.2.0-beta.1
latest: 5.1.0

També pots instal·lar des de git, cosa útil quan necessites un arranjament que encara no està publicat, o quan el paquet és intern i no és a cap registre:

npm install git+https://github.com/usuari/paquet.git#v2.1.0
npm install github:usuari/paquet#branca-amb-l-arranjament

Fixa sempre una etiqueta o un commit (#v2.1.0), mai una branca viva: una branca canvia sota els teus peus i arruïna la reproduïbilitat que el lock intenta donar-te. I tingues present que un paquet instal·lat des de git no passa pel registre, així que npm audit no en sap res.

  1. Instal·lació global: quan es justifica (gairebé mai)

npm install -g <paquet>
npm list -g --depth=0     # que tens instal.lat globalment

La llista honesta de casos en què -g està justificat és curta: eines de sistema que fas servir cada dia i que no pertanyen a cap projecte —un client de desplegament, pm2 en un servidor (Mòdul 11)— i gairebé res més. Per a tota la resta hi ha dues opcions millors: devDependencies + script de npm si l'eina és del projecte (ESLint, Prettier, Mocha), i npx eina@versio si és d'un sol ús, com un generador de plantilles.

El motiu de fons, ja avançat a 05-01, és la deriva de versions: el que és global no està declarat enlloc, no viatja amb el repositori, no apareix a la CI i no s'instal·la a la màquina de ningú més. Un projecte el README del qual digui "primer instal·la X globalment" és un projecte que fallarà la primera vegada que algú el cloni.

  1. Triar una dependència amb criteri

Aquí hi ha el cor de la lliçó. Abans d'escriure npm install, passa-li al candidat aquesta llista:

Criteri Què mirar Senyal d'alarma
Ho fa ja Node? fetch, crypto.randomUUID, node:test, structuredClone, AbortSignal Instal·lar uuid o node-fetch el 2026
Descàrregues setmanals npmjs.com Menys de mil per a una cosa d'ús general
Últim llançament Data a npmjs.com o a GitHub Més de dos anys sense tocar
Incidències obertes Es responen? Hi ha errors crítics antics? Centenars d'obertes, zero respostes
Dependències transitives npm ls després d'instal·lar, o packagephobia.com 200 paquets per formatar una data
Mida instal·lada bundlephobia.com / packagephobia.com Desenes de MB per una utilitat
Llicència Camp license Absent, GPL en producte tancat (05-06)
Mantenidors Una persona o una organització? Un únic mantenidor sense activitat
Alternatives Hi ha una opció estàndard de l'ecosistema? Triar l'exòtica sense motiu
Cost d'escriure-ho Són 20 línies teves? Instal·lar per mandra, no per complexitat

Les dues files més productives són la primera i l'última.

La primera, perquè el nucli de Node ha crescut enormement i una part important de les dependències clàssiques ja sobra:

Dependència clàssica Substitut al nucli
node-fetch, axios (ús simple) fetch global (M4)
uuid crypto.randomUUID()
rimraf fs.promises.rm(ruta, { recursive: true }) (M3)
mkdirp fs.promises.mkdir(ruta, { recursive: true }) (M3)
dotenv (parcialment) node --env-file=.env
nodemon node --watch (05-04)
mocha / jest (casos simples) node:test (M9)
chalk (casos simples) util.styleText

L'última, perquè de vegades la millor dependència és la que no instal·les. El cas més famós de l'ecosistema és left-pad: onze línies de codi, i quan el seu autor el va retirar del registre el 2016 es van trencar les compilacions de mig internet, incloses les de Babel i React. Tornarem a aquesta història a 05-05, des del punt de vista de qui publica.

I tens un cas propi, molt més proper: el Mòdul 4 sencer es va fer sense cap dependència. Enrutador, tipus MIME, ETags, interpretació de cossos, reintents. No perquè no existissin paquets per a això —existeixen i són bons—, sinó perquè l'objectiu era entendre el problema. Aquest exercici t'ha deixat una cosa valuosa: quan al Mòdul 6 instal·lis Express, no serà un acte de fe. Sabràs exactament quina feina t'està estalviant i a quin preu.

La conclusió no és "no instal·lis res". És que cada dependència és un deute: codi que no controles, que cal actualitzar, auditar i, algun dia, substituir. Instal·la quan l'estalvi sigui clarament més gran que aquest deute.

  1. Les primeres dependències reals d'Escena Viva

Amb el criteri anterior a la mà, afegim dos paquets. Un de producció i un de desenvolupament.

npm install dotenv
npm install --save-dev prettier

Per què dotenv passa el filtre. Fins ara, el port i la clau de l'API de divises del Mòdul 4 es llegien de process.env, amb la incomoditat d'haver-les d'exportar a mà a cada terminal. dotenv carrega un fitxer .env dins de process.env. És minúscul, té zero dependències, està mantingut i és l'estàndard de facto de l'ecosistema. Nota honesta: Node ja porta --env-file=.env, així que en un projecte nou en podries prescindir; l'instal·lem perquè te'l trobaràs en el 90 % dels projectes reals i perquè és un exemple perfecte de dependència ben triada. Al Mòdul 11 compararem les dues opcions a fons.

Per què prettier és de desenvolupament. Formata codi font. Res del que fa té sentit en un servidor. Va a devDependencies sense discussió.

Així queda el manifest:

{
  "name": "escena-viva",
  "version": "0.1.0",
  "private": true,
  "type": "commonjs",
  "main": "src/servidor/servidor.js",
  "engines": { "node": ">=24.5.0 <25" },
  "scripts": {
    "start": "node src/servidor/servidor.js"
  },
  "dependencies": {
    "dotenv": "^17.2.1"
  },
  "devDependencies": {
    "prettier": "^3.6.2"
  }
}

I l'ús, en un mòdul nou que centralitza la configuració d'entorn. Aquest fitxer s'ha de carregar abans que cap altre que llegeixi process.env:

// src/config/entorn.js
'use strict';

const path = require('node:path');
const { ARREL } = require('./rutes.js');

// Carrega .env dins de process.env. No sobreescriu el que ja existeixi:
// les variables reals del sistema sempre guanyen al fitxer.
require('dotenv').config({ path: path.join(ARREL, '.env') });

// Llegim un sol cop i validem aqui, no repartit pel codi.
const entorn = {
  port: Number(process.env.PORT ?? 3000),
  entornNode: process.env.NODE_ENV ?? 'desenvolupament',
  clauApiDivises: process.env.CLAU_API_DIVISES ?? null,
};

if (!Number.isInteger(entorn.port) || entorn.port < 1 || entorn.port > 65535) {
  // Diagnostic per stderr, com a tot el curs.
  console.error(`PORT invalid: ${process.env.PORT}`);
  process.exit(1);
}

module.exports = { entorn };

Punts a subratllar:

  • dotenv no sobreescriu variables ja presents a l'entorn. És exactament el que vols: en producció mana el sistema, no un fitxer oblidat al repositori.
  • La validació viu en un sol lloc. Un port invàlid ha de matar el procés en arrencar, no produir un error incomprensible tres minuts després.
  • .env és al .gitignore des del Mòdul 1. Allà hi viuen credencials; no es puja mai. El que sí que es puja és un .env.exemple amb les claus i valors ficticis, perquè qui cloni sàpiga què cal.

  1. Com resol Node un paquet instal·lat

Ja saps la resposta des del Mòdul 2, però ara té un exemple real al darrere. Quan src/config/entorn.js executa require('dotenv'): no comença per ./, ../ ni /, i no és un mòdul del nucli (node:path sí que ho seria), així que és un paquet. Node busca escena-viva/src/config/node_modules/dotenv (no existeix), puja a escena-viva/src/node_modules/dotenv (no existeix) i puja a escena-viva/node_modules/dotenv, on el troba. Aleshores llegeix el package.json de dotenv, segueix el seu camp main (o el seu exports) fins al fitxer real, l'executa un cop i el desa a la memòria cau de mòduls: el segon require('dotenv') no el torna a executar.

És la mateixa cerca ascendent que vas estudiar, sense cap regla nova. L'única cosa que ha canviat és que ara hi ha alguna cosa per trobar. I d'aquí surt un detall pràctic: la ruta del teu fitxer no importa. src/config/entorn.js i src/servidor/servidor.js escriuen el mateix require('dotenv') sense comptes de ../, perquè la cerca és cap amunt.

  1. Inspeccionar i mantenir: ls, outdated, update, uninstall

npm ls mostra l'arbre instal·lat:

npm ls              # nomes el primer nivell
npm ls --all        # tot l-arbre
npm ls dotenv       # qui depen de dotenv (clau a 05-06)
[email protected] /home/usuari/escena-viva
├── [email protected]
└── [email protected]

Aquest npm ls <paquet> és l'eina que faràs servir quan una auditoria t'avisi d'una vulnerabilitat en un paquet que tu no vas instal·lar mai: et diu qui l'arrossega.

npm outdated compara el que està instal·lat amb el que està publicat:

npm outdated
Package   Current  Wanted  Latest  Location            Depended by
dotenv     17.2.1  17.2.3  18.0.1  node_modules/dotenv  escena-viva

Les tres columnes diuen coses diferents i cal llegir-les bé:

Columna Significat
Current El que tens instal·lat ara mateix
Wanted La versió més alta que compleix el teu rang de package.json
Latest L'última publicada, compleixi el teu rang o no

Si Current < Wanted, un npm update ho arregla. Si Wanted < Latest, hi ha una versió major esperant i actualitzar exigeix canviar el rang a mà i llegir les notes de la nova versió. La raó d'aquesta distinció és tot el contingut de 05-03.

npm update puja cada paquet a la versió més alta permesa pel seu rang. Mai no salta a una versió major: és l'operació segura.

npm uninstall <paquet> (àlies npm rm) el treu de node_modules, del package.json i del lock. Sense això, un paquet que vas deixar de fer servir continua instal·lant-se i continua apareixent a les auditories per sempre.

  1. L'arbre, l'aplanament i les versions duplicades

Les teves dependències tenen dependències. Un npm ls --all en un projecte Express real pot ocupar centenars de línies. Aquest arbre s'ha de col·locar en un sistema de fitxers pla, i aquí és on npm pren una decisió amb conseqüències.

Suposa aquest cas:

escena-viva
├── paquet-a  -> necessita utilitat@^1.0.0
└── paquet-b  -> necessita utilitat@^1.2.0

Tots dos rangs són compatibles amb [email protected], així que npm instal·la una sola còpia, a l'arrel:

node_modules/
├── paquet-a/
├── paquet-b/
└── utilitat/     <- 1.4.0, compartida pels dos

Això és l'aplanament (hoisting): pujar tot el que es pugui a l'arrel per no duplicar. Ara canvia un rang:

escena-viva
├── paquet-a  -> necessita utilitat@^1.0.0
└── paquet-b  -> necessita utilitat@^2.0.0

1.x i 2.x són incompatibles per definició de semver. No hi ha cap versió que satisfaci tots dos, així que npm imbrica:

node_modules/
├── paquet-a/
├── paquet-b/
│   └── node_modules/
│       └── utilitat/    <- 2.1.0, nomes per a paquet-b
└── utilitat/            <- 1.4.0, per a tots els altres

I funciona sense trucs gràcies a la cerca ascendent de l'apartat 9: quan paquet-b demana utilitat, Node troba primer la còpia imbricada i deixa de buscar. Dues versions del mateix paquet conviuen al mateix procés sense assabentar-se l'una de l'altra.

Tres conseqüències pràctiques:

  • Pot haver-hi tres versions de la mateixa cosa instal·lades. És normal, no és una fallada, i explica per què node_modules pesa el que pesa.
  • Compte amb instanceof entre còpies. Si dues versions del mateix paquet defineixen una classe, un objecte creat per una no és instanceof la classe de l'altra. És una font d'errors desconcertants al món real.
  • L'aplanament crea dependències fantasma. Si utilitat és a l'arrel de node_modules, el teu propi codi pot fer require('utilitat') sense haver-la declarat i funcionarà... fins que paquet-a canviï el seu arbre i desaparegui. Aquesta és exactament la trampa que pnpm evita sent estricte.

npm dedupe intenta reorganitzar l'arbre per compartir més còpies. Ho veurem a 05-03, al costat del fitxer que registra tot aquest arbre amb precisió mil·limètrica: package-lock.json.

Errors Comuns i Consells

  • Instal·lar sense --save-dev per costum. Tot acaba a dependencies i el desplegament s'infla. Abans de cada instal·lació, pregunta't: això s'executa al servidor?
  • Cannot find module només en producció. Gairebé sempre és una dependència de producció classificada com a devDependencies. Mou-la amb npm install <paquet> (sense -D), que la reubica.
  • Esborrar node_modules com a primer recurs. De vegades cal, però sol amagar el problema real. Abans, prova npm ls <paquet> per veure què hi ha de debò instal·lat.
  • Editar package.json a mà i esperar que s'instal·li sol. Canviar el fitxer no instal·la res; cal executar npm install després perquè el lock i node_modules es posin al dia.
  • Instal·lar des d'una branca de git. #main canvia sota els teus peus. Fixa sempre una etiqueta o un commit.
  • Oblidar les cometes amb ^ o >. npm install paquet@>=2 sense cometes fa que el shell interpreti > com una redirecció i et crea un fitxer anomenat =2.
  • Consell: npm install --dry-run mostra què faria sense tocar res. Perfecte abans d'una instal·lació gran.
  • Consell: mira l'arbre tot just després d'instal·lar. npm ls --all | wc -l et diu quantes línies de dependències acabes d'acceptar. De vegades aquesta xifra sola et fa canviar d'idea.

Exercicis

Exercici 1. Classificar correctament. Per a cada paquet, decideix si aniria a dependencies o a devDependencies a Escena Viva i justifica-ho en una frase: express, mocha, dotenv, helmet, prettier, supertest, mongoose, nodemon. Després explica quin error concret veuria l'usuari si helmet estigués mal classificat i es desplegués amb npm ci --omit=dev.

Exercici 2. Instal·lar i verificar dotenv. Instal·la dotenv, crea un .env amb PORT=4000 i CLAU_API_DIVISES=clau-de-prova, escriu src/config/entorn.js com a l'apartat 8 i comprova que el servidor del Mòdul 4 arrenca al port 4000. Després executa PORT=5000 npm start i explica en quin port arrenca i per què.

Exercici 3. Mesurar el cost d'una dependència. Sense instal·lar res encara, aplica la llista de comprovació de l'apartat 7 a express. Després, en una carpeta d'usar i llençar fora del projecte, executa npm init -y && npm install express i compara: quants paquets s'han afegit (npm ls --all | wc -l), quant ocupa node_modules (du -sh node_modules) i què diu npm audit. Continua valent la pena?

Solucions

Solució 1. Producció: express (és el servidor), dotenv (es requereix en arrencar), helmet (middleware que corre a cada petició), mongoose (accés a dades en execució). Desenvolupament: mocha i supertest (només proves), prettier (només formata font), nodemon (només reinicia en desenvolupament; i a més el substituirem per node --watch a 05-04).

Si helmet estigués a devDependencies, el desplegament amb --omit=dev no l'instal·laria i el procés moriria en arrencar, al require, no a la primera petició:

Error: Cannot find module 'helmet'
Require stack:
- /app/src/servidor/servidor.js

El desconcertant és que en local funciona perfectament, perquè allà npm install sí que va instal·lar tots dos blocs. És l'argument més contundent per classificar bé des del principi.

Solució 2. Amb el .env a l'arrel i require('./config/entorn.js') al començament de l'arrencada, el servidor escolta al 4000.

Amb PORT=5000 npm start arrenca al 5000. La raó és a l'apartat 8: dotenv no sobreescriu variables que ja existeixin a process.env. La variable d'entorn real s'estableix abans que el procés arrenqui, així que quan dotenv hi arriba i veu PORT ja definida, la respecta.

Aquesta precedència és justament el que es vol en producció: el .env és un valor per defecte còmode per a desenvolupament, i l'entorn real del contenidor o del servidor mana sempre. Si necessitessis el contrari —estrany, i gairebé sempre símptoma d'un altre problema— existeix override: true.

Solució 3. Els números aproximats avui, amb Express 5:

added 66 packages, and audited 67 packages in 2s
found 0 vulnerabilities

$ du -sh node_modules
2.1M    node_modules

Uns 66 paquets per un d'instal·lat. Sona molt, i la reacció inicial sol ser de rebuig. Però aplica la llista: descàrregues en desenes de milions setmanals, mantingut per una fundació (OpenJS) i no per una persona, llicència MIT, 2 MB al disc, quinze anys d'història i zero vulnerabilitats conegudes. I la feina que substitueix la coneixes de primera mà: és tot el Mòdul 4 i força més.

El contrast és l'ensenyament. Seixanta-sis paquets per Express, amb aquest suport, és una bona compra. Seixanta-sis paquets per una funció que formata dates i que podries escriure en vint línies, no ho és. El número tot sol no decideix; decideix en relació amb el que obtens.

Conclusió

Escena Viva ja té les seves primeres dependències i, més important, un criteri per triar-les. Saps què toca npm install <paquet> —manifest, lock, node_modules, .bin i memòria cau— i que npm escriu rangs amb ^, no versions exactes, cosa que esmicolarem a la lliçó següent.

Distingeixes dependencies de devDependencies amb la regla de "apareix en un require de src/?", i saps que aquesta distinció no és burocràcia: en el desplegament amb npm ci --omit=dev decideix la mida de la imatge, el temps d'instal·lació i sobretot la superfície d'atac, perquè les eines de desenvolupament són les que més codi arrosseguen i cap no té motiu per ser en un servidor. També reconeixes peerDependencies —el contracte dels complements, que npm 7 endavant exigeix de debò— i optionalDependencies, que fallen en silenci a propòsit.

La llista de comprovació de l'apartat 7 és el que t'endús per sempre: mira primer si el nucli de Node ja ho fa (fetch, randomUUID, rm recursive, --watch, node:test), i després descàrregues, manteniment, transitives, mida i llicència. Cada dependència és un deute que cal actualitzar, auditar i algun dia substituir; de vegades la millor és la que no instal·les, com va demostrar el Mòdul 4 sencer i com recorda la història de left-pad.

I entens per fi com se sosté tot per sota: require('dotenv') funciona per la mateixa cerca ascendent del Mòdul 2, i l'aplanament comparteix una sola còpia quan els rangs són compatibles i imbrica quan no ho són, de manera que dues versions del mateix paquet poden conviure al mateix procés —amb la seva trampa d'instanceof i les seves dependències fantasma—.

Aquesta frase, "quan els rangs són compatibles", és la porta de la lliçó següent. A Versionat Semàntic i package-lock veurem què promet de debò ^1.2.3, per què ^0.x.y es comporta diferent, què instal·la el teu projecte d'aquí a sis mesos sense que hagis tocat res, i com package-lock.json converteix totes aquestes promeses en un arbre exacte, reproduïble i verificat amb hashos.

Curs de Node.js: De Principiant a Avançat

Mòdul 1: Introducció a Node.js

Mòdul 2: Conceptes Bàsics

Mòdul 3: Sistema de Fitxers i E/S

Mòdul 4: HTTP i Servidors Web

Mòdul 5: NPM i Gestió de Paquets

Mòdul 6: Framework Express.js

Mòdul 7: Bases de Dades i ORMs

Mòdul 8: Autenticació i Autorització

Mòdul 9: Proves i Depuració

Mòdul 10: Temes Avançats

Mòdul 11: Desplegament i DevOps

Mòdul 12: Projectes del Món Real

© Copyright 2026. Tots els drets reservats