A la lliçó anterior vas instal·lar dotenv i npm va escriure ^17.2.1 al manifest, no 17.2.1. Aquest accent circumflex és una decisió amb conseqüències enormes: significa que el teu projecte no està demanant una versió, està demanant un rang, i que la versió concreta que acabi instal·lada depèn de què hagi publicat l'autor de dotenv el dia que algú executi npm install.

Això és una bomba de rellotgeria o una comoditat extraordinària, segons com ho entenguis. Sense package-lock.json, dues persones del mateix equip poden instal·lar el mateix package.json en dies diferents i acabar amb arbres de dependències diferents. Amb ell, la instal·lació és reproduïble fins a l'últim byte.

Aquesta lliçó té dues meitats que s'expliquen mútuament: el sistema de versions que promet compatibilitat i el fitxer que fa que aquesta promesa no calgui.

Contingut

  1. SemVer: MAJOR.MENOR.PEDAÇ i el contracte implícit
  2. Versions de preproducció i el seu ordre de precedència
  3. La taula de rangs, amb la fila que gairebé ningú coneix
  4. Què instal·la cada rang avui i d'aquí a sis mesos
  5. package-lock.json: què conté exactament
  6. npm ci davant de npm install
  7. Conflictes del lock a git
  8. npm dedupe i --save-exact
  9. L'actualització menor que trenca
  10. De 0.1.0 a 1.0.0: versionar Escena Viva

  1. SemVer: MAJOR.MENOR.PEDAÇ i el contracte implícit

El versionat semàntic (semver.org) és una convenció que converteix tres números en una promesa verificable:

    17  .   2   .   1
     │       │       │
     │       │       └── PEDAC: correccions compatibles
     │       └────────── MENOR: funcionalitat nova, compatible
     └────────────────── MAJOR: canvis que trenquen compatibilitat

Les regles de quan puja cada número:

Tipus de canvi Puja Exemple
Corregir una fallada sense canviar l'API PEDAÇ 17.2.1 → 17.2.2
Afegir una funció o opció nova MENOR 17.2.1 → 17.3.0
Marcar alguna cosa com a obsoleta (sense treure-la) MENOR 17.2.1 → 17.3.0
Treure o reanomenar alguna cosa pública MAJOR 17.2.1 → 18.0.0
Canviar el comportament d'una funció existent MAJOR 17.2.1 → 18.0.0
Pujar la versió mínima de Node exigida MAJOR 17.2.1 → 18.0.0
Canviar comentaris, README o proves internes Res No es publica

En pujar un número, els de la seva dreta tornen a zero: de 17.2.1 a menor és 17.3.0, i a major és 18.0.0.

El contracte implícit és la part que s'oblida. Publicar 17.3.0 en comptes de 18.0.0 no és una preferència estètica: és afirmar davant de milers de projectes que poden actualitzar sense revisar el seu codi. I com que el 90 % d'aquests projectes té escrit ^17.2.1, aquesta versió menor entrarà a les seves instal·lacions automàticament. Si vas mentir, les seves compilacions es trenquen demà sense que ells hagin canviat ni una línia.

Aquesta és la raó que semver sigui, abans que una regla tècnica, una qüestió de responsabilitat. I també la raó que no te'n puguis refiar del tot: és una convenció, no una cosa que el registre verifiqui. El que sí que verifica és el fitxer de bloqueig, i per això les dues meitats de la lliçó van juntes.

  1. Versions de preproducció i el seu ordre de precedència

Abans d'una versió estable es publiquen versions de prova, amb un guionet:

1.0.0-alpha
1.0.0-alpha.1
1.0.0-beta.1
1.0.0-rc.1
1.0.0

Les regles de precedència, definides per l'especificació: una versió amb etiqueta de preproducció és sempre menor que la mateixa sense ella (1.0.0-rc.1 < 1.0.0, perquè és un assaig d'aquesta versió, no una de posterior); els identificadors es comparen d'esquerra a dreta; els numèrics com a números i els alfanumèrics alfabèticament; un número sempre és menor que un text (1.0.0-1 < 1.0.0-alpha); i a igualtat dels anteriors, guanya qui tingui més identificadors (1.0.0-alpha < 1.0.0-alpha.1).

Una sèrie completa ordenada:

1.0.0-alpha  <  1.0.0-alpha.1  <  1.0.0-alpha.beta  <  1.0.0-beta
             <  1.0.0-beta.2   <  1.0.0-beta.11     <  1.0.0-rc.1  <  1.0.0

Fixa't en beta.2 < beta.11: com que l'identificador és numèric es compara com a número, no com a text. Si es comparés com a text, 11 aniria abans que 2.

El més important en el dia a dia: les versions de preproducció no entren mai en un rang normal. Si el teu manifest diu ^1.0.0 i es publica 2.0.0-beta.1, npm no la instal·larà. Per rebre-les cal demanar-les explícitament (npm install paquet@beta) o escriure un rang que les inclogui. És una protecció deliberada, i és correcta.

  1. La taula de rangs, amb la fila que gairebé ningú coneix

Aquesta és la taula que cal saber-se de memòria. Suposem que l'última publicada és 1.9.2 i que existeixen també 2.0.0 i 1.2.9.

Rang a package.json Nom Permet Instal·la avui
1.2.3 Exacte Només 1.2.3 1.2.3
~1.2.3 Titlla Pedaços: >=1.2.3 <1.3.0 1.2.9
^1.2.3 Circumflex Menors i pedaços: >=1.2.3 <2.0.0 1.9.2
1.2.x / 1.2 Comodí parcial Igual que ~1.2.0 1.2.9
1.x / 1 Comodí parcial Igual que ^1.0.0 1.9.2
>=1.2.3 <2 Rang explícit El que diu 1.9.2
1.2.3 - 1.5.0 Guionet Tots dos extrems inclosos 1.5.0
* o "" Qualsevol Qualsevol versió 2.0.0
latest Etiqueta La marcada com a latest 2.0.0

La forma curta de recordar les dues importants: ~ deixa pujar l'últim número; ^ deixa pujar l'últim que no sigui zero per l'esquerra.

La fila que gairebé ningú coneix: ^0.x.y

Aquí hi ha el detall que produeix sorpreses desagradables. El circumflex es defineix com "no canviïs el primer número diferent de zero", i això dona un comportament diferent quan la major és 0:

Rang Equival a Comentari
^1.2.3 >=1.2.3 <2.0.0 L'habitual
^0.2.3 >=0.2.3 <0.3.0 Només pedaços: 0.2 actua com si fos la major
^0.0.3 >=0.0.3 <0.0.4 Només aquesta versió: equival a fixar-la

La lògica és sensata: a 0.x la biblioteca declara que la seva API encara es mou, així que semver tracta cada versió menor com a potencialment incompatible. La conseqüència pràctica sí que sorprèn: un npm update no mou res en un paquet 0.x tret dels pedaços. Si esperaves passar de 0.2.9 a 0.4.0 automàticament, no passarà; cal canviar el rang a mà.

I el corol·lari per quan publiquis tu: mentre siguis a 0.x no promets res, i qui et faci servir ho sap. És exactament per això que Escena Viva va començar a 0.1.0 i no a 1.0.0.

  1. Què instal·la cada rang avui i d'aquí a sis mesos

L'experiment mental que aclareix el problema. Avui, amb [email protected] com a última publicada:

Rang Instal·la avui
17.2.1 17.2.1
~17.2.1 17.2.1
^17.2.1 17.2.1

Els tres coincideixen. Ara avança sis mesos: s'han publicat 17.2.5, 17.6.0 i 18.0.0. Algú clona el repositori, executa npm install sense haver tocat el package.json i obté:

Rang Instal·la d'aquí a sis mesos Ha canviat el teu codi?
17.2.1 17.2.1 No
~17.2.1 17.2.5 No
^17.2.1 17.6.0 No
* 18.0.0 No

Tres persones amb el mateix repositori i tres arbres diferents. Aquest és el problema exacte que resol el fitxer de bloqueig.

Compara la recomanació de cada rang segons el paper del projecte:

Situació Rang recomanat Motiu
Aplicació amb lock (Escena Viva) ^ El lock ja fixa la versió real; el rang només marca la política d'actualització
Biblioteca publicada ^ ampli Els rangs estrets causen duplicats als projectes que et fan servir
Dependència amb historial de trencar ~ o exacte Menys marge per a sorpreses
Qualsevol projecte Mai * Renuncies a tota garantia a canvi de res

  1. package-lock.json: què conté exactament

Es genera sol, tan bon punt hi ha alguna dependència. Aquest és un fragment real, retallat:

{
  "name": "escena-viva",
  "version": "0.1.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "escena-viva",
      "version": "0.1.0",
      "license": "MIT",
      "dependencies": {
        "dotenv": "^17.2.1"
      },
      "devDependencies": {
        "prettier": "^3.6.2"
      },
      "engines": {
        "node": ">=24.5.0 <25"
      }
    },
    "node_modules/dotenv": {
      "version": "17.2.1",
      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz",
      "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78hjB1PYYow==",
      "engines": { "node": ">=12" },
      "funding": { "url": "https://dotenvx.com" }
    },
    "node_modules/prettier": {
      "version": "3.6.2",
      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
      "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfQqFsuHLoDrIhcVYWyO0nAvqEhIkKMYQIsy0mRnNlqUXWkuVjK4X8oEeWmnCLYUEQA==",
      "dev": true,
      "bin": { "prettier": "bin/prettier.cjs" },
      "engines": { "node": ">=14" }
    }
  }
}

Camp per camp:

Camp Què és
lockfileVersion: 3 Format del fitxer. El 3 és el de npm 7 endavant
packages[""] El projecte mateix: còpia dels seus rangs declarats
version La versió exacta resolta. Aquí no hi ha rangs
resolved URL exacta del tarball descarregat
integrity Hash SHA-512 del contingut, en format SRI
dev: true Marca que només cal en desenvolupament (permet --omit=dev)
bin Executables que s'enllaçaran a node_modules/.bin
engines Requisits de Node del paquet, copiats per poder validar-los

El camp integrity és el que fa que això sigui seguretat i no només comoditat. A cada instal·lació npm descarrega el tarball, en calcula el SHA-512 i el compara amb el registrat. Si no coincideix —perquè algú ha manipulat el registre, perquè un mirall ha servit una altra cosa, perquè una memòria cau s'ha corromput— la instal·lació falla. És integritat criptogràfica de tot el teu arbre de dependències, de franc.

I d'aquí ve la regla que no es negocia:

package-lock.json SÍ que es puja al control de versions. Sempre.

Les raons: reproduïbilitat (el teu portàtil, el de la teva companya, la CI i el servidor instal·len el mateix, avui i d'aquí a un any); seguretat, perquè els hashos viatgen amb el repositori; depuració, ja que git log package-lock.json et diu quina versió va canviar i quan, que sol ser la resposta a "això funcionava la setmana passada"; i auditoria, perquè npm audit analitza l'arbre exacte del lock i no una aproximació.

L'única excepció real és una biblioteca publicada: el seu lock no afecta qui la instal·la, perquè cada projecte resol el seu propi arbre. Tot i així, moltes biblioteques el pugen perquè les seves pròpies proves siguin reproduïbles. Escena Viva és una aplicació: el puja sense discussió.

I el seu revers: el lock no s'edita mai a mà. És un fitxer generat. Es canvia executant ordres de npm.

  1. npm ci davant de npm install

Amb el lock ja sobre la taula, la comparació clau del mòdul:

npm install npm ci
Llegeix package.json Sí Sí
Llegeix package-lock.json Sí, si existeix Obligatori: sense lock, falla
Modifica el lock Sí, si cal Mai
Si el lock no concorda amb el manifest L'actualitza en silenci Falla amb error
node_modules previ L'actualitza de forma incremental L'esborra sencer i reinstal·la
Velocitat Més lenta (resol versions) Més ràpida (només instal·la el que hi ha escrit)
Accepta npm ci <paquet> Sí, npm install <paquet> No existeix
Ús previst Desenvolupament, afegir dependències CI, Docker, producció

La fila decisiva és la quarta. Si algú edita el package.json a mà —puja un rang, afegeix una dependència— i no executa npm install, el lock queda desincronitzat. En aquest estat, npm install ho arregla en silenci; npm ci es planta:

npm error `npm ci` can only install packages when your package.json and
npm error package-lock.json are in sync. Please update your lock file with
npm error `npm install` before continuing.

Aquest error és una bona notícia: la CI ha detectat que el repositori és incoherent abans de desplegar res. Per això la regla operativa del mòdul, que reutilitzarem al Mòdul 11:

  • A la teva màquina: npm install, npm install <paquet>, npm update. Modifiquen el lock, i aquest canvi es confirma a git com a part de la feina.
  • A CI, Docker i producció: npm ci (amb --omit=dev en producció). Mai npm install.

  1. Conflictes del lock a git

És inevitable: dues branques afegeixen dependències diferents, es fusionen, i git presenta un conflicte en un fitxer generat de tres mil línies.

El que no es fa: obrir el fitxer i triar a mà entre marcadors <<<<<<<. El lock és un graf coherent; resoldre'l per trossos produeix un arbre inconsistent que "gairebé" funciona.

El que es fa: descartar el fitxer i regenerar-lo a partir dels manifestos, que sí que són llegibles per humans.

# 1. Resol primer el conflicte de package.json, que es petit i llegible.
git checkout --ours package-lock.json   # o --theirs: tant es, es regenerara
npm install                             # regenera el lock coherent amb el manifest fusionat
npm ci && npm test                      # verifica que el resultat installa i funciona
git add package.json package-lock.json
git commit

Alternativa igual de vàlida: esborrar el lock i executar npm install. És més agressiva —pot pujar versions dins dels rangs, ja que es resol tot de nou— així que la primera opció és preferible quan vols tocar el mínim.

Consell d'higiene: una dependència nova mereix la seva pròpia confirmació, amb package.json i package-lock.json junts i res més. Així el conflicte, si arriba, és diminut, i la revisió de codi pot mirar de debò què hi va entrar (05-06).

  1. npm dedupe i --save-exact

npm dedupe reorganitza l'arbre per compartir el màxim de còpies. Després de diverses instal·lacions successives és fàcil acabar amb duplicats que ja no calen:

node_modules/
├── paquet-a/
│   └── node_modules/utilitat/   <- 1.4.0
└── paquet-b/
    └── node_modules/utilitat/   <- 1.5.0

Si tots dos rangs admeten 1.5.0, npm dedupe puja una sola còpia a l'arrel i esborra les imbricades. Menys disc, menys superfície d'auditoria, i adeu al problema d'instanceof entre còpies diferents de la mateixa classe.

npm ls utilitat     # quantes copies hi ha
npm dedupe          # reorganitza i actualitza el lock

Modifica node_modules i el lock, així que s'executa en desenvolupament i se'n confirma el resultat. Mai en producció.

--save-exact (àlies -E) desa la versió sense ^:

npm install dotenv --save-exact     # "dotenv": "17.2.1"

O com a política del projecte, al .npmrc de 05-01:

save-exact=true

Compensa? La resposta honesta és gairebé mai en una aplicació amb lock, perquè el lock ja fixa la versió real i el rang només expressa quina política d'actualització acceptes. Amb ^ i lock, npm ci és igual de determinista.

Fixar versions exactes sí que compensa en tres casos concrets:

Cas Motiu
Dependència amb historial de trencar en versions menors Menys marge per a sorpreses
Eines que afecten la sortida generada (compiladors, formatadors) Que la sortida no canviï sense avisar
Entorn regulat que exigeix justificar cada canvi de versió Tota pujada és explícita i revisable

El cost és real: amb versions exactes, npm update deixa de servir i actualitzar exigeix tocar el manifest paquet a paquet. En un projecte gran això es delega a Dependabot o Renovate (05-06).

  1. L'actualització menor que trenca

L'escenari que justifica tot l'anterior. Un dimarts, la CI d'Escena Viva falla. Ningú no ha tocat el codi des de divendres.

Causa: [email protected] es va publicar el dilluns. El teu manifest diu ^17.2.1, la CI no feia servir lock i npm install va portar la versió nova. Un canvi de comportament que l'autor va considerar menor —com interpreta les cometes als valors del .env, per exemple— trenca una de les teves proves.

El que cal extreure d'aquesta història:

^ no és una garantia, és una expectativa. Confia que un tercer classifiqui bé el seu propi canvi. La majoria ho fa; equivocar-se és fàcil, perquè ningú no coneix tots els usos de la seva biblioteca. Un canvi que l'autor veu com una correcció pot ser el comportament del qual tu depenies.

El lock converteix aquesta expectativa en un fet. Amb package-lock.json al repositori i npm ci a la CI, el dimarts s'hauria instal·lat 17.2.1, igual que el divendres. La versió nova entraria el dia que algú executi npm update deliberadament, vegi el canvi al diff del lock i passi les proves abans de fusionar.

La diferència no és que la fallada desaparegui: és qui controla quan passa. Sense lock, et sorprèn un dimarts al matí en producció. Amb lock, passa en una branca, amb un responsable i amb proves al davant.

I per això l'ordre correcte d'actualitzar és sempre el mateix:

npm outdated                 # que hi ha disponible i de quin tipus
npm update                   # puja dins dels rangs: segur
npm test                     # verifica (Modul 9)
git add package-lock.json && git commit -m "Actualitza dependencies menors"

Per saltar una versió major, el procés és diferent i no automatitzable: llegir les notes de la versió, canviar el rang a mà, adaptar el codi i provar. Branca a part, sempre.

  1. De 0.1.0 a 1.0.0: versionar Escena Viva

Escena Viva va néixer a 0.1.0 perquè la seva API es movia. Acabat el Mòdul 4, té una API HTTP pública i estable —GET /api/esdeveniments, POST /comandes—, un domini assentat i un client (el front-end de public/) que en depèn. És el moment del salt.

npm version 1.0.0

npm version fa tres coses, no una: canvia version a package.json i a package-lock.json, crea una confirmació de git amb aquest canvi (amb 1.0.0 com a missatge per defecte) i crea una etiqueta de git anotada, v1.0.0, que és l'única cosa que imprimeix per pantalla.

També accepta els salts per nom, que és com es fa servir cada dia:

npm version patch      # 1.0.0 -> 1.0.1
npm version minor      # 1.0.1 -> 1.1.0
npm version major      # 1.1.0 -> 2.0.0
npm version 1.1.0-beta.1 --preid=beta

Si no vols la confirmació ni l'etiqueta —perquè el teu flux de publicació les genera d'una altra manera— existeix --no-git-tag-version.

Què implica de debò el salt a 1.0.0 a Escena Viva:

Abans (0.x) Després (1.x)
Qualsevol versió menor podia trencar Només un salt a 2.0.0 pot trencar
Els rangs ^0.1.0 només admetien pedaços ^1.0.0 admet tota la sèrie 1.x
Canviar l'API era rutina Canviar l'API exigeix pla de migració

En concret, a partir d'ara: treure un camp de la resposta de GET /api/esdeveniments és major; afegir un camp nou és menor; canviar el significat d'error.codi a la taula d'errors del Mòdul 4 és major; corregir un càlcul d'aforament mal fet és pedaç.

Aquest compromís és el mateix que has estat exigint a dotenv durant tota la lliçó. Aquí canvies de banda de la taula, i per això el mòdul continua cap a la publicació.

Errors Comuns i Consells

  • Afegir package-lock.json al .gitignore. És l'error més car del mòdul: destrueix la reproduïbilitat. El que s'ignora és node_modules/, mai el lock.
  • Resoldre conflictes del lock a mà. Produeix arbres incoherents que fallen de maneres estranyes. Regenera'l amb npm install.
  • Fer servir npm install a la CI. Pot modificar el lock durant la compilació i desplegar una cosa diferent de la que vas provar. npm ci, sempre.
  • Esperar que npm update pugi una versió major. No ho fa mai, per disseny. Ni tampoc menors en paquets 0.x, per la regla de ^0.x.y.
  • Publicar 1.0.0 sense voler prometre estabilitat. Si la teva API encara es mou, queda't a 0.x: és informació honesta per a qui et faci servir.
  • Posar * o latest com a rang. Qualsevol versió major hi entra sense avisar. No hi ha cap cas en què compensi.
  • Consell: revisa el diff del lock. En una revisió de codi, un lock que canvia sense que canviï package.json mereix una pregunta.
  • Consell: npm view <paquet> versions --json llista totes les versions publicades. Útil per veure el ritme de llançaments abans d'adoptar una dependència.

Exercicis

Exercici 1. Resoldre rangs a mà. Un paquet té publicades aquestes versions: 0.9.0, 1.0.0, 1.2.0, 1.2.5, 1.9.0, 2.0.0-beta.1, 2.0.0, 2.1.0. Digues què instal·laria cadascun d'aquests rangs: ^1.2.0, ~1.2.0, 1.2.x, >=1.0.0 <2, ^2.0.0, *, 1.2.0 - 1.9.0. Després repeteix l'exercici suposant que les versions publicades són 0.1.0, 0.2.0, 0.2.5, 0.3.0 i el rang és ^0.2.0.

Exercici 2. Veure el lock en acció. A Escena Viva, executa npm ls dotenv i anota la versió. Obre package-lock.json i localitza'n la version, el resolved i l'integrity. Ara esborra node_modules, executa npm ci i comprova que la versió és idèntica. Després edita el package.json canviant el rang a ^17.0.0 sense executar npm install i llança npm ci. Explica què passa i per què és el comportament desitjable.

Exercici 3. Versionar Escena Viva. Executa npm version 1.0.0 amb l'arbre de git net. Comprova amb git log -1 i git tag què ha creat exactament. Després decideix quin tipus de salt (pedaç, menor o major) correspon a cada canvi: (a) afegir el camp salaAccessible a la resposta de GET /api/esdeveniments; (b) corregir el càlcul de places lliures, que restava malament; (c) reanomenar preuCentims a importCentims a la resposta de l'API; (d) canviar LLINDAR_AFORAMENT_BAIX de 20 a 15; (e) exigir Node 26 a engines.

Solucions

Solució 1. Primera part:

Rang Instal·la Motiu
^1.2.0 1.9.0 >=1.2.0 <2.0.0; la més alta de la sèrie 1
~1.2.0 1.2.5 >=1.2.0 <1.3.0; només pedaços
1.2.x 1.2.5 Equivalent a ~1.2.0
>=1.0.0 <2 1.9.0 Exclou explícitament la sèrie 2
^2.0.0 2.1.0 No 2.0.0-beta.1: les de preproducció no entren en rangs normals
* 2.1.0 La més alta estable
1.2.0 - 1.9.0 1.9.0 El guionet inclou tots dos extrems

Segona part: ^0.2.0 instal·la 0.2.5, no 0.3.0. És la regla de ^0.x.y: amb la major a zero, el circumflex protegeix també el número menor, perquè 0.3.0 es considera potencialment incompatible. Aquesta és la resposta que més gent falla.

Solució 2. Després de npm ci, npm ls dotenv mostra exactament la mateixa versió: mana el lock, no el rang.

En canviar el rang a ^17.0.0 sense instal·lar, npm ci falla:

npm error `npm ci` can only install packages when your package.json and
npm error package-lock.json are in sync.
npm error Invalid: lock file's [email protected] does not satisfy dotenv@^17.0.0

És desitjable perquè la desincronització és un error real del repositori, no un detall. Algú va tocar el manifest sense regenerar el lock, així que ningú no sap quin arbre es pretenia desplegar. npm install ho taparia en silenci i desplegaria una resolució que ningú no ha revisat; npm ci atura el desplegament i obliga a arreglar-ho en una branca. S'arregla executant npm install i confirmant el lock resultant.

Solució 3. npm version 1.0.0 produeix:

$ git log -1 --oneline
a1b2c3d 1.0.0

$ git tag
v1.0.0

$ git show --stat HEAD
 package.json      | 2 +-
 package-lock.json | 4 ++--

Classificació dels canvis:

Canvi Salt Raó
(a) Afegir salaAccessible Menor → 1.1.0 Afegeix informació; un client que la ignori continua funcionant
(b) Corregir places lliures Pedaç → 1.0.1 Corregeix una fallada sense canviar la forma de la resposta
(c) Reanomenar a importCentims Major → 2.0.0 Tot client que llegís preuCentims es trenca
(d) LLINDAR_AFORAMENT_BAIX de 20 a 15 Menor → 1.1.0 Canvia el comportament observable sense trencar contractes; si aquesta constant estigués documentada com a part de l'API pública, seria major
(e) Exigir Node 26 Major → 2.0.0 Deixa fora entorns que abans funcionaven

El cas (d) és l'interessant: la resposta depèn de si aquesta constant forma part del contracte públic. Aquesta ambigüitat és exactament la part difícil de semver, i la raó que un CHANGELOG clar valgui tant com els números.

Conclusió

Ja saps llegir el llenguatge amb què l'ecosistema sencer es comunica. SemVer converteix tres números en una promesa: PEDAÇ corregeix, MENOR afegeix sense trencar, MAJOR trenca. Les versions de preproducció són sempre menors que la seva estable i no entren als rangs normals. I de la taula de rangs t'endús dues formes: ~ deixa pujar l'últim número, ^ l'últim que no sigui zero per l'esquerra —d'aquí que ^0.2.3 només admeti pedaços, la regla que gairebé ningú coneix i que explica per què npm update de vegades sembla no fer res.

Però la lliçó de fons és que ^ és una expectativa, no una garantia: depèn que un tercer classifiqui bé el seu propi canvi. Qui converteix aquesta expectativa en un fet és package-lock.json, amb el seu arbre exacte, les seves versions resoltes, les seves URL i sobretot el seu integrity SHA-512, que fa fallar la instal·lació si el contingut descarregat no és byte a byte el que es va registrar. Per això es puja sempre al repositori, per això no s'edita mai a mà, i per això els seus conflictes a git es resolen regenerant-lo, no triant entre marcadors.

D'aquí surt la regla operativa que t'acompanyarà fins al final del curs: npm install a la teva màquina —modifica el lock, i aquest canvi es confirma i es revisa— i npm ci a la CI, a Docker i en producció, que exigeix el lock, el respecta al peu de la lletra, esborra node_modules i falla si el manifest i el lock no concorden. Aquesta fallada és una bona notícia: atura un desplegament incoherent abans que arribi a ningú.

Escena Viva és ja 1.0.0, amb la seva etiqueta v1.0.0 a git creada per npm version, i aquest número és un compromís: a partir d'avui, treure un camp de l'API o canviar el significat d'un error.codi obliga a pujar a 2.0.0.

A la lliçó següent, Scripts d'npm i Automatització del Projecte, omplim l'últim buit del manifest. El camp scripts es convertirà en la interfície única del projecte —npm start, npm run dev, npm run informe, npm test— perquè ningú no hagi de llegir el README per endevinar una ordre. I pel camí descobriràs per què funciona una eina que no vas instal·lar mai globalment: el PATH estès amb node_modules/.bin.

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