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
- SemVer:
MAJOR.MENOR.PEDAÇi el contracte implícit - Versions de preproducció i el seu ordre de precedència
- La taula de rangs, amb la fila que gairebé ningú coneix
- Què instal·la cada rang avui i d'aquí a sis mesos
package-lock.json: què conté exactamentnpm cidavant denpm install- Conflictes del lock a git
npm dedupei--save-exact- L'actualització menor que trenca
- De
0.1.0a1.0.0: versionar Escena Viva
- SemVer:
MAJOR.MENOR.PEDAÇ i el contracte implícit
MAJOR.MENOR.PEDAÇ i el contracte implícitEl 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 compatibilitatLes 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.
- Versions de preproducció i el seu ordre de precedència
Abans d'una versió estable es publiquen versions de prova, amb un guionet:
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.0Fixa'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.
- 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.
- 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 |
package-lock.json: què conté exactament
package-lock.json: què conté exactamentEs 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.jsonSÍ 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.
npm ci davant de npm install
npm ci davant de npm installAmb 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=deven producció). Mainpm install.
- 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 commitAlternativa 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).
npm dedupe i --save-exact
npm dedupe i --save-exactnpm 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.0Si 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.
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 ^:
O com a política del projecte, al .npmrc de 05-01:
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).
- 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.
- De
0.1.0 a 1.0.0: versionar Escena Viva
0.1.0 a 1.0.0: versionar Escena VivaEscena 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 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=betaSi 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.jsonal.gitignore. És l'error més car del mòdul: destrueix la reproduïbilitat. El que s'ignora ésnode_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 installa 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 updatepugi una versió major. No ho fa mai, per disseny. Ni tampoc menors en paquets0.x, per la regla de^0.x.y. - Publicar
1.0.0sense voler prometre estabilitat. Si la teva API encara es mou, queda't a0.x: és informació honesta per a qui et faci servir. - Posar
*olatestcom 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.jsonmereix una pregunta. - Consell:
npm view <paquet> versions --jsonllista 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
- 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
