A la lliçó anterior vam convertir el camp scripts en la interfície única del projecte: qualsevol persona que arribi a Escena Viva sap que npm start arrenca el servidor i npm run comprovar valida el codi, sense necessitat de conèixer les rutes internes. Fins ara hem estat sempre a la mateixa banda del taulell: érem consumidors de paquets. En aquesta lliçó canviem de banda i en publiquem un.
El cas concret és real i modest, que és exactament com han de començar aquestes coses. src/utils/format.js conté tres funcions —formatarPreu, formatarData i generarCodiEntrada— que ja estem copiant i enganxant en dos projectes interns més: el panell de taquilla i el generador d'informes comptables. Aquest és el símptoma que justifica extreure un paquet. Convertirem aquest fitxer en @escena-viva/format, decidint amb precisió què es pot importar des de fora, què es puja al registre i què passa quan publiques una cosa que després vols retirar.
Contingut
- Quan extreure un paquet i quan no
- El cas d'Escena Viva:
@escena-viva/format - Estructura d'un paquet publicable
- L'API pública:
main,exportsitypes - Què es puja:
filesdavant de.npmignore - Paquets amb àmbit i
publishConfig - Provar abans de publicar:
npm packinpm link - Publicar: login,
--dry-run, 2FA i tokens - Versions noves i etiquetes de distribució
- Despublicar gairebé mai es pot
- Errors Comuns i Consells
- Exercicis
- Conclusió
- Quan extreure un paquet i quan no
Extreure codi a un paquet té un cost permanent: un repositori més, un cicle de versions més, i l'obligació de no trencar qui el consumeix. Aquest cost només es paga quan hi ha reutilització real.
| Senyal | Extreure? | Motiu |
|---|---|---|
| El mateix fitxer copiat en dos projectes o més | Sí | Les còpies divergeixen i els errors s'arreglen un sol cop |
| Codi estable, amb poca deriva funcional | Sí | Un paquet que canvia cada setmana és un llast per als seus consumidors |
| API petita i ben definida (3-6 funcions) | Sí | La superfície que cal mantenir compatible és assumible |
| Es fa servir només en aquest projecte | No | N'hi ha prou amb un mòdul intern ben col·locat |
| Depèn de l'estat global de l'aplicació | No | Un paquet ha de ser una funció de les seves entrades |
| S'extreu "per si de cas" o perquè queda professional | No | És cost sense benefici |
La regla pràctica és la de les tres còpies: quan vas a fer la tercera còpia manual d'un fragment, aquest fragment demana un paquet.
El nostre format.js ho compleix: està copiat en dos projectes, té tres funcions pures, no toca disc ni xarxa, i el seu comportament no ha canviat des del mòdul 1.
- El cas d'Escena Viva:
@escena-viva/format
@escena-viva/formatAquest és el codi que extraurem, tal com era al projecte:
// src/utils/format.js (versio que hi havia a Escena Viva)
function formatarPreu(preuCentims) {
const euros = (preuCentims / 100).toFixed(2);
return `${euros.replace('.', ',')} €`;
}
function formatarData(dataIso) {
const data = new Date(dataIso);
const dia = String(data.getUTCDate()).padStart(2, '0');
const mes = String(data.getUTCMonth() + 1).padStart(2, '0');
return `${dia}/${mes}/${data.getUTCFullYear()}`;
}
function generarCodiEntrada(any, sequencia) {
const numero = String(sequencia).padStart(6, '0');
return `EV-${any}-${numero}`;
}
module.exports = { formatarPreu, formatarData, generarCodiEntrada };Creem un directori germà del projecte (no a dins) per al paquet:
L'indicador --scope fa que el nom inicial sigui @escena-viva/escena-viva-format; l'ajustem a mà al package.json. El manifest final del paquet queda així:
{
"name": "@escena-viva/format",
"version": "0.1.0",
"description": "Format de preus, dates i codis d'entrada d'Escena Viva",
"license": "MIT",
"type": "commonjs",
"main": "./index.js",
"exports": {
".": "./index.js",
"./preu": "./lib/preu.js",
"./package.json": "./package.json"
},
"files": ["index.js", "lib/", "README.md", "LICENSE"],
"engines": { "node": ">=20" },
"publishConfig": { "access": "public" },
"scripts": {
"test": "node --test",
"prepublishOnly": "npm test"
}
}Fixa't en tres coses que ja no hi apareixen: private: true (un paquet privat no es pot publicar), main apuntant a un fitxer de servidor, i dependencies. Aquest paquet no té cap dependència, i això és una virtut, no una mancança.
El codi es reorganitza en mòduls petits dins de lib/ i un index.js que reexporta:
// lib/preu.js — converteix centims enters en una cadena llegible en euros.
function formatarPreu(preuCentims) {
if (!Number.isInteger(preuCentims)) {
throw new TypeError('El preu ha de ser un enter de centims');
}
const euros = (preuCentims / 100).toFixed(2);
return `${euros.replace('.', ',')} €`;
}
module.exports = { formatarPreu };// index.js — punt d-entrada unic del paquet: reexporta l-API publica.
const { formatarPreu } = require('./lib/preu.js');
const { formatarData } = require('./lib/data.js');
const { generarCodiEntrada } = require('./lib/codi.js');
module.exports = { formatarPreu, formatarData, generarCodiEntrada };A Escena Viva, el canvi del costat consumidor és mínim. S'esborra src/utils/format.js, se substitueix el require als fitxers que el feien servir i es declara la dependència:
// Abans, a src/informes/ocupacio.js
const { formatarPreu, formatarData } = require('../utils/format.js');
// Despres
const { formatarPreu, formatarData } = require('@escena-viva/format');Comencem a 0.1.0 a propòsit. Com vam veure a 05-03, al rang ^0.x.y l'accent circumflex només permet canvis de pedaç, així que un 0.x ens deixa marge per reorganitzar l'API sense trencar ningú per accident. Quan s'estabilitzi, saltarem a 1.0.0 com a acte deliberat.
- Estructura d'un paquet publicable
Un paquet petit i responsable cap en molt pocs fitxers:
escena-viva-format/ ├── package.json Manifest: nom, versio, exports, files ├── index.js Punt d-entrada de l-API publica ├── lib/ preu.js, data.js, codi.js ├── test/format.test.js ├── README.md Que fa, com s-installa, exemples ├── CHANGELOG.md Que ha canviat a cada versio └── LICENSE Text complet de la llicencia
El README.md no és documentació decorativa: és la pàgina que la gent veu al registre i, a la pràctica, la primera cosa que decideix si el teu paquet es fa servir. Ha de contenir l'exemple mínim que funciona copiat i enganxat: instal·lació en una línia i tres línies d'ús amb la seva sortida (formatarPreu(2450) // '24,50 €').
El fitxer LICENSE amb el text complet importa més del que sembla: sense ell, legalment el teu codi és "tots els drets reservats" i una empresa amb advocats no el podrà fer servir encara que estigui publicat en obert. El camp license del package.json ha de coincidir amb aquest fitxer.
- L'API pública:
main, exports i types
main, exports i typesHistòricament, main era l'únic control: indicava el fitxer que es carregava en fer require('paquet'). El seu problema és que no impedia res. Qualsevol podia escriure require('@escena-viva/format/lib/preu.js') i acoblar-se a la teva estructura interna; el dia que reanomenessis lib/ hauries trencat un consumidor sense haver canviat cap funció pública.
El camp exports ho resol. És avui la manera correcta de declarar l'API pública perquè fa dues coses alhora: mapa els noms públics a fitxers reals i bloqueja tot el que no estigui llistat.
Amb aquest mapa, el comportament des de fora del paquet és:
| Importació | Resultat | Motiu |
|---|---|---|
require('@escena-viva/format') |
Funciona | La clau . apunta a index.js |
require('@escena-viva/format/preu') |
Funciona | Subruta declarada explícitament |
require('@escena-viva/format/lib/preu.js') |
ERR_PACKAGE_PATH_NOT_EXPORTED |
La ruta interna no és al mapa |
require('@escena-viva/format/lib/data.js') |
ERR_PACKAGE_PATH_NOT_EXPORTED |
Ídem, encara que el fitxer existeixi |
require('@escena-viva/format/package.json') |
Funciona | Declarada a propòsit |
Aquest bloqueig és una llibertat per a tu: mentre index.js i ./preu continuïn retornant el mateix, pots reorganitzar lib/ sense publicar una versió major. Observa que ./package.json es declara explícitament perquè diverses eines d'anàlisi el llegeixen; si no el poses, també queda bloquejat.
exports admet a més condicions, útils quan un paquet ofereix CommonJS i ESM. Node tria la branca segons com es carregui el paquet, i default ha d'anar sempre l'última perquè s'avaluen en ordre:
Sobre types: encara que tu no facis servir TypeScript, molts dels teus consumidors sí. Declarar "types": "./index.d.ts" i escriure un fitxer de vint línies amb les signatures fa que el teu paquet s'autocompleti als seus editors. És opcional, però és de les coses amb millor relació entre esforç i agraïment.
- Què es puja:
files davant de .npmignore
files davant de .npmignoreQuan publiques, npm empaqueta un directori sencer en un tarball. Decidir què hi entra té dos mecanismes possibles i no són equivalents.
| Mecanisme | Com funciona | Risc |
|---|---|---|
.npmignore |
Llista negra: es puja tot tret del que hi és llistat | Un fitxer nou es puja per defecte |
files a package.json |
Llista blanca: només es puja el que hi és llistat | Un fitxer nou queda fora per defecte |
files és més segur per la mateixa raó que un tallafocs que denega per defecte és més segur que un que permet per defecte. Amb .npmignore, el dia que algú afegeixi notes-internes.md o un .env.produccio al repositori, aquest fitxer viatjarà al registre públic tret que algú es recordi d'actualitzar la llista negra. Amb files, aquest mateix fitxer simplement no existeix per a npm.
Hi ha un detall que confon: si no hi ha files ni .npmignore, npm fa servir el .gitignore com a llista negra; i si hi ha .npmignore, el .gitignore deixa d'aplicar-se del tot, cosa que produeix sorpreses desagradables.
Alguns fitxers s'inclouen sempre (package.json, README, LICENSE i el fitxer de main) i d'altres s'exclouen sempre (node_modules/, .git/, package-lock.json, .npmrc). Que .npmrc estigui sempre exclòs és una salvaguarda important, perquè allà hi viuen els tokens. Però no confiïs en salvaguardes: fes servir files.
- Paquets amb àmbit i
publishConfig
publishConfig@escena-viva/format és un paquet amb àmbit (scoped): el @escena-viva és un espai de noms associat a un usuari o organització del registre. Evita col·lisions de noms —format a seques està agafat des de fa anys—, agrupa els paquets d'una mateixa organització i permet polítiques d'accés comunes.
El detall que sorprèn tothom la primera vegada és que els paquets amb àmbit són privats per defecte, i publicar privat requereix un pla de pagament. Si el teu paquet és obert cal dir-ho amb npm publish --access public, però escriure aquest indicador cada vegada és una invitació a l'oblit. Millor deixar-ho al manifest:
publishConfig també serveix per al cas contrari, molt habitual a l'empresa: un paquet intern que ha d'anar al registre privat de la companyia i mai al públic. Fixar-hi el registry evita una fuita de codi per un npm publish distret.
- Provar abans de publicar:
npm pack i npm link
npm pack i npm linkPublicar és irreversible a la pràctica, així que la comprovació prèvia no és opcional.
npm pack construeix exactament el mateix tarball que es pujaria, però el deixa al teu disc:
npm notice 📦 @escena-viva/[email protected] npm notice Tarball Contents npm notice 1.1kB LICENSE npm notice 842B README.md npm notice 318B index.js npm notice 402B lib/codi.js npm notice 380B lib/data.js npm notice 455B lib/preu.js npm notice 621B package.json npm notice total files: 7 npm notice filename: escena-viva-format-0.1.0.tgz
Aquesta llista és el moment de la veritat. El que cal buscar activament:
- Hi apareix cap
.env? Seria una filtració de credencials publicada en obert. - Hi apareix
dades/amb les vendes de prova? Podria contenir correus reals. - Hi apareix
test/? No és perillós, però infla la descàrrega de tots els teus consumidors. - Hi falta
index.jso algun fitxer delib/? El paquet s'instal·laria trencat.
npm pack --dry-run mostra la mateixa llista sense escriure res, i tar -tzf fitxer.tgz inspecciona un tarball ja creat. La prova definitiva és instal·lar aquest tarball al projecte real:
Si l'informe d'ocupació continua imprimint 24,50 €, el paquet funciona tal com el rebrà qualsevol.
L'alternativa per al desenvolupament diari és npm link, que crea enllaços simbòlics:
La primera ordre enllaça el paquet a la carpeta global de npm; la segona crea dins de node_modules/@escena-viva/format un enllaç simbòlic a la teva carpeta de treball. Cada canvi que desis al paquet el veu el projecte a l'instant, sense reinstal·lar. Les seves raresses convé conèixer-les abans de perdre-hi una tarda:
npm installal projecte pot desfer l'enllaç i tornar a baixar la versió del registre.- L'enllaç no respecta
filesniexportsamb la mateixa fidelitat que un tarball: pots estar fent servir un fitxer que després no es publicarà. - Si paquet i projecte depenen del mateix mòdul, es poden carregar dues còpies diferents (problema clàssic amb biblioteques que mantenen estat intern).
Regla pràctica: npm link per iterar ràpid, npm pack més instal·lació del tarball per a la comprovació final. Per desfer-ho, npm unlink @escena-viva/format i npm install.
- Publicar: login,
--dry-run, 2FA i tokens
--dry-run, 2FA i tokensEl primer pas és autenticar-se. npm login obre el navegador i desa el token resultant al teu .npmrc d'usuari (~/.npmrc), mai al del projecte. Després, un assaig que fa tot el procés —construir el tarball, validar el manifest, comprovar permisos— tret de la pujada, i només aleshores la publicació real:
L'última ordre executa abans el ganxo prepublishOnly que vam definir, que al seu torn llança npm test. És l'aplicació pràctica del que vam veure a 05-04: un ganxo que impedeix publicar una versió amb les proves vermelles.
Sobre la seguretat del compte, dues mesures que no són negociables si el teu paquet el fa servir algú més. La primera, 2FA (doble factor): s'activa amb npm profile enable-2fa auth-and-writes i fa que cada publicació demani un codi temporal; la majoria dels segrestos de paquets coneguts han estat segrestos del compte del mantenidor, no fallades del registre. La segona, tokens d'accés granulars per a la CI: un servidor d'integració contínua no pot introduir un codi de 2FA, així que necessita un token, i no ha de ser un de clàssic amb permisos totals, sinó un de granular, limitat als paquets que ha de publicar i amb data de caducitat, desat com a secret del sistema de CI i mai al repositori. Veurem la configuració completa de secrets i desplegament automàtic al mòdul 11.
- Versions noves i etiquetes de distribució
No editis mai el camp version a mà. npm version ho fa, a més de deixar el repositori coherent:
npm version patch # 0.1.0 -> 0.1.1 (correccio compatible)
npm version minor # 0.1.1 -> 0.2.0 (funcionalitat nova)
npm version major # 0.2.0 -> 1.0.0 (ruptura)Cadascuna d'aquestes ordres, en un directori amb git:
- Comprova que l'arbre de treball està net (si no, avorta).
- Actualitza
versionapackage.jsoni apackage-lock.json. - Crea un commit amb el número de versió com a missatge.
- Crea una etiqueta de git
v0.1.1apuntant a aquest commit.
Aquesta etiqueta és el que et permetrà, d'aquí a dos anys, recuperar el codi exacte d'una versió publicada. Recorda pujar-la: git push --follow-tags. Per a prellançaments, npm version prerelease --preid=beta porta de 1.0.0 a 1.0.1-beta.0.
I aquí entren les etiquetes de distribució, que són àlies mòbils cap a versions concretes. Quan algú escriu npm install @escena-viva/format, npm resol l'etiqueta latest. Si publiques una beta sense res més, es converteix en latest i tothom se l'endú sense demanar-la. La forma correcta és npm publish --tag beta: així latest continua apuntant a l'última estable i qui vulgui la beta l'ha de demanar amb npm install @escena-viva/format@beta.
Les etiquetes es gestionen després de publicar sense necessitat de republicar res:
npm dist-tag ls @escena-viva/format
npm dist-tag add @escena-viva/[email protected] next
npm dist-tag add @escena-viva/[email protected] latest
npm dist-tag rm @escena-viva/format betaMoure latest és, de fet, l'única manera neta de "retirar" una versió dolenta: no l'esborres, però deixes de servir-la per defecte.
- Despublicar gairebé mai es pot
Aquí convé abaixar el ritme, perquè la intuïció enganya. Publicar no és com pujar un fitxer a un servidor propi: és un compromís públic. La política del registre és aproximadament aquesta:
| Situació | Es pot despublicar? |
|---|---|
| Menys de 72 hores des de la publicació | Sí, amb npm unpublish |
| Més de 72 hores, sense dependents i amb una sola versió | Només el paquet sencer, en condicions estrictes |
| Més de 72 hores i amb altres paquets que en depenen | No |
Versió concreta que algú té al seu package-lock.json |
No |
La raó d'aquesta rigidesa té nom propi. El 2016, l'autor del paquet left-pad —onze línies de codi que omplien una cadena per l'esquerra— el va despublicar després d'una disputa sobre el nom d'un altre paquet. left-pad era dependència transitiva d'eines fetes servir per mig món, així que durant hores van fallar compilacions a milers d'organitzacions. La conseqüència va ser l'enduriment de la política de despublicació: l'estabilitat de l'ecosistema pesa més que el dret a retirar el codi propi.
L'alternativa correcta quan una versió és dolenta o un paquet queda obsolet és npm deprecate, que no esborra res però avisa a cada instal·lació:
npm deprecate @escena-viva/[email protected] "Error d-arrodoniment; fes servir 0.1.1"
npm deprecate @escena-viva/format@"<0.2.0" "Sense manteniment; migra a 0.2.x"
npm deprecate @escena-viva/format "Substituit per @escena-viva/utils"
npm deprecate @escena-viva/[email protected] "" # retirar l-avisEl missatge apareix com a advertència en instal·lar, no trenca res i dona temps a migrar. És el que fa un mantenidor responsable.
Un cas especial i urgent: si has publicat credencials per accident, despublicar no és la solució. Encara que aconsegueixis retirar-ho, el tarball ja s'ha replicat en memòries cau i miralls. El que cal fer és rotar immediatament aquestes credencials, i després publicar una versió neta i marcar la dolenta com a obsoleta.
D'aquí que l'ordre correcte de treball sigui sempre: npm pack → revisar la llista → npm publish --dry-run → npm publish.
- Bones pràctiques d'un paquet responsable
- README amb exemples executables. Un bloc que es pugui copiar i funcioni a la primera val més que tres paràgrafs de descripció.
- CHANGELOG.md. Una entrada per versió, amb les ruptures destacades. És la primera cosa que llegeix qui va a actualitzar.
- SemVer honest. La versió no la decideix la teva percepció de la mida del canvi, sinó el seu efecte en el consumidor. Si reanomenes un paràmetre, és major encara que siguin dues línies.
- Zero dependències si és possible. Cada dependència teva es converteix en transitiva de tots els teus consumidors, amb la seva superfície de risc.
@escena-viva/formatno en necessita cap. enginesdeclarat i proves abans de publicar ambprepublishOnly.- Repositori accessible. Els camps
repository,bugsihomepagepermeten trobar el codi i obrir incidències.
Errors Comuns i Consells
Publicar amb private: true al manifest. npm s'hi nega amb This package has been marked as private. És una protecció deliberada: treu-la només quan el paquet és realment publicable.
Oblidar --access public en un paquet amb àmbit. L'error 402 Payment Required no significa que npm et vulgui cobrar per publicar codi obert; significa que està intentant publicar-lo com a privat. Afegeix publishConfig.access.
Fer servir .npmignore i descobrir un .env al tarball. La llista negra falla en silenci davant de fitxers nous. Canvia a files i verifica sempre amb npm pack.
Publicar la carpeta equivocada. npm publish empaqueta el directori actual. Comprova pwd abans; el --dry-run t'ho confirma mostrant el nom del paquet.
Editar version a mà i oblidar l'etiqueta de git. Al cap d'uns mesos tindràs versions publicades sense cap commit identificable al darrere. Fes servir sempre npm version.
Publicar una beta sense --tag. Es converteix en latest i tota la teva base d'usuaris se la instal·la. És dels errors més cars i més fàcils de cometre.
Confiar en npm link com a prova final. L'enllaç simbòlic no exercita files ni exports igual que un tarball. Prova el .tgz abans de publicar, i treballa sempre com si la publicació fos definitiva, perquè a efectes pràctics ho és.
Exercicis
Exercici 1: bloquejar una ruta interna
Un company, en un altre projecte, ha escrit require('@escena-viva/format/lib/codi.js') per fer servir generarCodiEntrada sense carregar la resta. Explica quin error obtindrà amb l'exports que hem definit, i escriu l'exports que li donaria accés a aquesta funció mitjançant la subruta pública @escena-viva/format/codi sense exposar l'estructura de lib/.
Exercici 2: revisar el tarball
Al directori del paquet has afegit, sense adonar-te'n, un fitxer .env amb NPM_TOKEN=... i una carpeta dades/vendes-teatro-almendra.json amb correus de prova. El package.json té files: ["index.js", "lib/", "README.md", "LICENSE"]. Respon: es pujarien aquests fitxers? Quina ordre ho comprova? Canviaria la resposta si en comptes de files hi hagués un .npmignore amb la línia dades/?
Exercici 3: una versió dolenta publicada
Has publicat @escena-viva/[email protected] i quatre dies després detectes que formatarPreu(2450) retorna '24.50 €' amb punt en comptes de coma. Ja hi ha dos projectes interns que la tenen al seu package-lock.json. Escriu la seqüència completa d'ordres per resoldre-ho correctament i explica per què no comences per npm unpublish.
Solucions
Solució 1. Obtindrà ERR_PACKAGE_PATH_NOT_EXPORTED, perquè el mapa d'exports denega per defecte tota ruta no declarada, encara que el fitxer existeixi físicament dins del paquet. L'exports corregit afegeix una subruta pública que apunta al fitxer intern:
"exports": {
".": "./index.js",
"./preu": "./lib/preu.js",
"./codi": "./lib/codi.js",
"./package.json": "./package.json"
}Ara require('@escena-viva/format/codi') funciona, i la ruta amb lib/ continua bloquejada. L'avantatge és que el nom públic ./codi i el fitxer real ./lib/codi.js queden desacoblats: si demà mous el fitxer, n'hi ha prou amb canviar el mapa, sense versió major.
Solució 2. No, no es pujarien. files és una llista blanca: només entra al tarball el que hi és enumerat, i ni .env ni dades/ hi són. A més, npm exclou .npmrc sempre, encara que això no cobreix un .env.
Es comprova amb npm pack --dry-run (o npm pack i després tar -tzf), llegint la llista de fitxers del tarball.
Amb .npmignore la resposta canvia perillosament: dades/ sí que quedaria exclòs perquè figura a la llista, però .env es pujaria, ja que no hi és llistat i .npmignore desactiva del tot el .gitignore. Aquest és exactament el motiu pel qual files és més segur: falla cap al costat de no publicar.
Solució 3. No es comença per npm unpublish perquè han passat més de 72 hores i a més hi ha projectes que ja depenen d'aquesta versió; el registre ho rebutjarà, i encara que ho permetés, trencaries aquestes instal·lacions. La seqüència correcta és publicar l'arranjament i assenyalar la versió dolenta:
npm test # 1. Corregir el codi i cobrir-lo amb una prova
npm version patch # 2. 0.2.0 -> 0.2.1
git push --follow-tags
npm pack --dry-run # 3. Revisar contingut i assajar
npm publish --dry-run
npm publish # 4. Publicar l-arranjament
npm deprecate @escena-viva/[email protected] "Separador decimal incorrecte; actualitza a 0.2.1"
npm dist-tag ls @escena-viva/format # 5. Confirmar que latest es la versio bonaEls projectes afectats rebran l'avís d'obsolescència a la seva propera instal·lació i, com que el seu rang és ^0.2.0, un npm update els portarà 0.2.1 sense cap més intervenció. Convé a més afegir l'entrada corresponent al CHANGELOG.md.
Conclusió
Publicar un paquet és sobretot un exercici de decidir fronteres. Hem vist que l'extracció es justifica per reutilització real —la regla de les tres còpies— i no per elegància, i hem convertit src/utils/format.js en @escena-viva/format, un paquet amb àmbit, sense dependències i amb una API de tres funcions.
Les decisions importants es concentren en quatre camps del manifest: main com a punt d'entrada clàssic, exports com a declaració estricta del que es pot importar i mur davant de les rutes internes, files com a llista blanca del que viatja al registre, i publishConfig.access perquè un paquet amb àmbit es publiqui en obert. Al seu voltant, un flux de comprovació que no convé saltar-se: npm pack per llegir el tarball amb els ulls oberts, instal·lació del .tgz per a la prova real, npm publish --dry-run com a assaig i només aleshores npm publish, amb 2FA al compte i tokens granulars a la integració contínua.
I una lliçó que convé interioritzar abans de necessitar-la: el que s'ha publicat és pràcticament definitiu. Fora de la finestra de 72 hores no hi ha marxa enrere, com va ensenyar el cas de left-pad; el que sí que hi ha és npm deprecate, versions noves i etiquetes de distribució per dirigir la gent cap al codi bo.
A la lliçó següent, Seguretat i Manteniment de Dependències, donem la volta a l'argument. Si publicar significa que altres executaran el teu codi, instal·lar significa que tu executes el de desconeguts: veurem npm audit i com llegir-lo de debò, npm ls per localitzar qui arrossega una dependència vulnerable, overrides per forçar una versió apedaçada, els atacs que cal saber reconèixer —typosquatting, comptes segrestats, paquets abandonats— i la rutina de manteniment que deixarem escrita al README d'Escena Viva.
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
