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
npm install <paquet>: què canvia al disc i al manifestdependenciesdavant dedevDependencies- Per què la distinció importa de debò en el desplegament
peerDependenciesioptionalDependencies- Instal·lar una versió, un rang, una etiqueta o un repositori git
- Instal·lació global: quan es justifica (gairebé mai)
- Triar una dependència amb criteri
- Les primeres dependències reals d'Escena Viva
- Com resol Node un paquet instal·lat
- Inspeccionar i mantenir:
ls,outdated,update,uninstall - L'arbre, l'aplanament i les versions duplicades
npm install <paquet>: què canvia al disc i al manifest
npm install <paquet>: què canvia al disc i al manifestAnem amb l'exemple canònic:
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.
dependencies davant de devDependencies
dependencies davant de devDependenciesnpm 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.
- 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.
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=devsubstitueix l'antic--production, que encara funciona però està obsolet. Veuràs--productionen tutorials antics i enDockerfileheretats.
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.
peerDependencies i optionalDependencies
peerDependencies i optionalDependenciesHi 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.
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 |
- 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 compostLes 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:
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-arranjamentFixa 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.
- Instal·lació global: quan es justifica (gairebé mai)
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.
- 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.
- 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.
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:
dotenvno 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.gitignoredes del Mòdul 1. Allà hi viuen credencials; no es puja mai. El que sí que es puja és un.env.exempleamb les claus i valors ficticis, perquè qui cloni sàpiga què cal.
- 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.
- Inspeccionar i mantenir:
ls, outdated, update, uninstall
ls, outdated, update, uninstallnpm 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:
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.
- 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:
Tots dos rangs són compatibles amb [email protected], així que npm instal·la una sola còpia, a l'arrel:
Això és l'aplanament (hoisting): pujar tot el que es pugui a l'arrel per no duplicar. Ara canvia un rang:
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_modulespesa el que pesa. - Compte amb
instanceofentre còpies. Si dues versions del mateix paquet defineixen una classe, un objecte creat per una no ésinstanceofla 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 denode_modules, el teu propi codi pot ferrequire('utilitat')sense haver-la declarat i funcionarà... fins quepaquet-acanviï 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-devper costum. Tot acaba adependenciesi el desplegament s'infla. Abans de cada instal·lació, pregunta't: això s'executa al servidor? Cannot find modulenomés en producció. Gairebé sempre és una dependència de producció classificada com adevDependencies. Mou-la ambnpm install <paquet>(sense-D), que la reubica.- Esborrar
node_modulescom a primer recurs. De vegades cal, però sol amagar el problema real. Abans, provanpm ls <paquet>per veure què hi ha de debò instal·lat. - Editar
package.jsona mà i esperar que s'instal·li sol. Canviar el fitxer no instal·la res; cal executarnpm installdesprés perquè el lock inode_moduleses posin al dia. - Instal·lar des d'una branca de git.
#maincanvia sota els teus peus. Fixa sempre una etiqueta o un commit. - Oblidar les cometes amb
^o>.npm install paquet@>=2sense cometes fa que el shell interpreti>com una redirecció i et crea un fitxer anomenat=2. - Consell:
npm install --dry-runmostra 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 -let 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ó:
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
- Què és Node.js?
- Instal·lació i Configuració de l'Entorn
- El Teu Primer Programa en Node.js
- El REPL de Node.js
- JavaScript Modern per a Node.js
- El Projecte del Curs: la Plataforma Escena Viva
Mòdul 2: Conceptes Bàsics
- Arquitectura de Node.js
- El Bucle d'Esdeveniments (Event Loop)
- Callbacks i Programació Asíncrona
- Promeses i async/await
- Esdeveniments i EventEmitter
- Mòduls CommonJS i require()
- Mòduls ES i Interoperabilitat
Mòdul 3: Sistema de Fitxers i E/S
- Lectura i Escriptura de Fitxers
- El Mòdul fs a Fons
- Rutes Multiplataforma amb el Mòdul path
- Treballant amb Streams
- Streams de Transformació i pipeline
- Buffers i Dades Binàries
Mòdul 4: HTTP i Servidors Web
- Creant un Servidor HTTP Simple
- Gestió de Sol·licituds i Respostes
- Enrutament Manual
- Servint Fitxers Estàtics
- Rebent Dades: Cossos de Petició i JSON
- Consumint APIs Externes des de Node.js
Mòdul 5: NPM i Gestió de Paquets
- Introducció a NPM i package.json
- Instal·lació i Ús de Paquets
- Versionat Semàntic i package-lock
- Scripts d'npm i Automatització del Projecte
- Creació i Publicació de Paquets
- Seguretat i Manteniment de Dependències
Mòdul 6: Framework Express.js
- Introducció a Express.js
- Configuració d'una Aplicació Express
- Enrutament a Express
- Middleware
- Middleware de Tercers Essencials
- Validació de Dades d'Entrada
- Gestió d'Errors
Mòdul 7: Bases de Dades i ORMs
- Introducció a les Bases de Dades
- Usant MongoDB amb Mongoose
- Operacions CRUD
- Relacions, Poblat i Consultes Avançades
- Usant Bases de Dades SQL amb Sequelize
- Migracions, Transaccions i Dades de Prova
Mòdul 8: Autenticació i Autorització
- Introducció a l'Autenticació
- Registre d'Usuaris i Hash de Contrasenyes
- Sessions i Galetes amb Passport.js
- Autenticació amb JWT
- Control d'Accés Basat en Rols
- Bones Pràctiques de Seguretat en APIs
Mòdul 9: Proves i Depuració
- Introducció a les Proves
- Proves Unitàries amb Mocha i Chai
- Dobles de Prova amb Sinon
- Proves d'Integració
- Cobertura i Automatització de les Proves
- Depuració d'Aplicacions Node.js
Mòdul 10: Temes Avançats
- El Mòdul Cluster
- Fils de Treball (Worker Threads)
- Memòria Cau i Cues de Treball amb Redis
- Optimització del Rendiment
- Construcció d'APIs RESTful
- GraphQL amb Node.js
Mòdul 11: Desplegament i DevOps
- Configuració i Variables d'Entorn
- Registre i Monitoratge en Producció
- Usant PM2 per a la Gestió de Processos
- Empaquetatge amb Docker
- Desplegant a Heroku i Altres PaaS
- Integració i Desplegament Continus
