// Arma una carpeta lista para copiar al servidor: release/devolucion-proveedores/ // // npm run publicar compila todo y arma la carpeta // npm run publicar -- --sin-build reutiliza los builds que ya existen (libs/shared/dist, apps/*/dist) // // Contenido: la API compilada, la web compilada y solo las dependencias de producción de la API // (sin Angular CLI ni herramientas de desarrollo). Las dependencias de la API son JavaScript puro, // así que se puede publicar desde un Mac o Linux y ejecutar en Windows. import { spawnSync } from 'node:child_process'; import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs'; import { dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; const raiz = resolve(dirname(fileURLToPath(import.meta.url)), '..'); const destino = join(raiz, 'release', 'devolucion-proveedores'); const app = join(destino, 'app'); const sinBuild = process.argv.includes('--sin-build'); const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm'; function ejecutar(comando, args, cwd) { console.log(`\n$ ${comando} ${args.join(' ')} (${cwd})`); // shell: true en Windows porque npm es un .cmd const r = spawnSync(comando, args, { cwd, stdio: 'inherit', shell: process.platform === 'win32' }); if (r.status !== 0) { console.error(`\nFalló: ${comando} ${args.join(' ')}`); process.exit(r.status ?? 1); } } function copiar(origen, destinoRelativo) { const desde = join(raiz, origen); if (!existsSync(desde)) { console.error(`Falta ${origen}. Ejecute "npm run publicar" sin --sin-build (o "npm run build" antes).`); process.exit(1); } cpSync(desde, join(app, destinoRelativo ?? origen), { recursive: true }); } function tamano(carpeta) { let total = 0; for (const e of readdirSync(carpeta, { withFileTypes: true, recursive: true })) { if (e.isFile()) total += statSync(join(e.parentPath, e.name)).size; } return `${(total / 1024 / 1024).toFixed(1)} MB`; } console.log('Publicando Devolución a Proveedores'); if (!sinBuild) ejecutar(npm, ['run', 'build'], raiz); rmSync(destino, { recursive: true, force: true }); mkdirSync(app, { recursive: true }); // Lo mínimo para que `npm ci` resuelva los mismos paquetes del package-lock: el package.json raíz // y el de cada workspace (la web no se instala, pero debe estar declarada para que el lock coincida). copiar('package.json'); copiar('package-lock.json'); copiar('libs/shared/package.json'); copiar('libs/shared/dist'); copiar('apps/api/package.json'); copiar('apps/api/dist'); copiar('apps/api/.env.example'); copiar('apps/web/package.json'); copiar('apps/web/dist/web/browser'); ejecutar(npm, ['ci', '--omit=dev', '--workspace=@dp/shared', '--workspace=api', '--no-audit', '--no-fund'], app); // npm deja enlaces simbólicos (el de cada workspace y los atajos de .bin) que no sobreviven al copiar la // carpeta de un Mac/Linux a Windows. La API importa @dp/shared al ejecutarse, así que ese enlace se // reemplaza por una copia real; los demás no se usan y se quitan. const nodeModules = join(app, 'node_modules'); rmSync(join(nodeModules, 'api'), { recursive: true, force: true }); const compartido = join(nodeModules, '@dp', 'shared'); rmSync(compartido, { recursive: true, force: true }); // quita solo el enlace, no su destino mkdirSync(compartido, { recursive: true }); cpSync(join(app, 'libs', 'shared', 'package.json'), join(compartido, 'package.json')); cpSync(join(app, 'libs', 'shared', 'dist'), join(compartido, 'dist'), { recursive: true }); rmSync(join(app, 'libs'), { recursive: true, force: true }); for (const e of readdirSync(nodeModules, { withFileTypes: true, recursive: true })) { if (e.name === '.bin') rmSync(join(e.parentPath, e.name), { recursive: true, force: true }); } const enlaces = readdirSync(app, { withFileTypes: true, recursive: true }) .filter((e) => e.isSymbolicLink()) .map((e) => join(e.parentPath, e.name)); if (enlaces.length > 0) { console.error(`\nQuedaron enlaces simbólicos en el paquete (no sobreviven en Windows):\n ${enlaces.join('\n ')}`); process.exit(1); } // Archivos de despliegue para Windows junto a la carpeta app/ for (const archivo of readdirSync(join(raiz, 'deploy', 'windows'))) { cpSync(join(raiz, 'deploy', 'windows', archivo), join(destino, archivo)); } for (const carpeta of ['logs', 'certificados']) mkdirSync(join(destino, carpeta), { recursive: true }); writeFileSync(join(destino, 'certificados', 'LEEME.txt'), 'Ponga aquí el certificado HTTPS (.pfx, o .key y .crt) y apunte el .env a estos archivos.\n'); const version = JSON.parse(readFileSync(join(raiz, 'package.json'), 'utf8')).name; writeFileSync( join(destino, 'VERSION.txt'), `${version}\nPublicado: ${new Date().toISOString()}\nNode de la publicación: ${process.version}\nSistema: ${process.platform}\n`, ); console.log(`\nListo: ${destino} (${tamano(destino)})`); console.log('Siguiente paso: copie esa carpeta al servidor y siga DEPLOY.md.');