codecrypto-cli 1.0.9 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +296 -97
- package/dist/commands/deploy.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/deploy.ts +327 -107
- package/docker-build/Dockerfile +0 -18
- package/docker-build/standalone/.next/BUILD_ID +0 -1
- package/docker-build/standalone/.next/app-path-routes-manifest.json +0 -6
- package/docker-build/standalone/.next/build-manifest.json +0 -19
- package/docker-build/standalone/.next/package.json +0 -1
- package/docker-build/standalone/.next/prerender-manifest.json +0 -114
- package/docker-build/standalone/.next/required-server-files.json +0 -164
- package/docker-build/standalone/.next/routes-manifest.json +0 -68
- package/docker-build/standalone/.next/server/app/_global-error/page/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/_global-error/page/build-manifest.json +0 -16
- package/docker-build/standalone/.next/server/app/_global-error/page/next-font-manifest.json +0 -6
- package/docker-build/standalone/.next/server/app/_global-error/page/react-loadable-manifest.json +0 -1
- package/docker-build/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +0 -4
- package/docker-build/standalone/.next/server/app/_global-error/page.js +0 -11
- package/docker-build/standalone/.next/server/app/_global-error/page.js.map +0 -5
- package/docker-build/standalone/.next/server/app/_global-error/page.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +0 -2
- package/docker-build/standalone/.next/server/app/_global-error.html +0 -2
- package/docker-build/standalone/.next/server/app/_global-error.meta +0 -15
- package/docker-build/standalone/.next/server/app/_global-error.rsc +0 -13
- package/docker-build/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +0 -5
- package/docker-build/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +0 -13
- package/docker-build/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +0 -6
- package/docker-build/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +0 -4
- package/docker-build/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +0 -1
- package/docker-build/standalone/.next/server/app/_not-found/page/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/_not-found/page/build-manifest.json +0 -16
- package/docker-build/standalone/.next/server/app/_not-found/page/next-font-manifest.json +0 -11
- package/docker-build/standalone/.next/server/app/_not-found/page/react-loadable-manifest.json +0 -1
- package/docker-build/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +0 -4
- package/docker-build/standalone/.next/server/app/_not-found/page.js +0 -14
- package/docker-build/standalone/.next/server/app/_not-found/page.js.map +0 -5
- package/docker-build/standalone/.next/server/app/_not-found/page.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +0 -2
- package/docker-build/standalone/.next/server/app/_not-found.html +0 -1
- package/docker-build/standalone/.next/server/app/_not-found.meta +0 -16
- package/docker-build/standalone/.next/server/app/_not-found.rsc +0 -14
- package/docker-build/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +0 -14
- package/docker-build/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +0 -6
- package/docker-build/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +0 -5
- package/docker-build/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +0 -5
- package/docker-build/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +0 -4
- package/docker-build/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +0 -2
- package/docker-build/standalone/.next/server/app/favicon.ico/route/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/favicon.ico/route/build-manifest.json +0 -11
- package/docker-build/standalone/.next/server/app/favicon.ico/route.js +0 -6
- package/docker-build/standalone/.next/server/app/favicon.ico/route.js.map +0 -5
- package/docker-build/standalone/.next/server/app/favicon.ico/route.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/favicon.ico.body +0 -0
- package/docker-build/standalone/.next/server/app/favicon.ico.meta +0 -1
- package/docker-build/standalone/.next/server/app/index.html +0 -1
- package/docker-build/standalone/.next/server/app/index.meta +0 -14
- package/docker-build/standalone/.next/server/app/index.rsc +0 -16
- package/docker-build/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +0 -5
- package/docker-build/standalone/.next/server/app/index.segments/_full.segment.rsc +0 -16
- package/docker-build/standalone/.next/server/app/index.segments/_head.segment.rsc +0 -6
- package/docker-build/standalone/.next/server/app/index.segments/_index.segment.rsc +0 -5
- package/docker-build/standalone/.next/server/app/index.segments/_tree.segment.rsc +0 -4
- package/docker-build/standalone/.next/server/app/page/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/page/build-manifest.json +0 -16
- package/docker-build/standalone/.next/server/app/page/next-font-manifest.json +0 -11
- package/docker-build/standalone/.next/server/app/page/react-loadable-manifest.json +0 -1
- package/docker-build/standalone/.next/server/app/page/server-reference-manifest.json +0 -4
- package/docker-build/standalone/.next/server/app/page.js +0 -16
- package/docker-build/standalone/.next/server/app/page.js.map +0 -5
- package/docker-build/standalone/.next/server/app/page.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/page_client-reference-manifest.js +0 -2
- package/docker-build/standalone/.next/server/app-paths-manifest.json +0 -6
- package/docker-build/standalone/.next/server/chunks/66d90_example-navidad__next-internal_server_app_favicon_ico_route_actions_a30dceae.js +0 -3
- package/docker-build/standalone/.next/server/chunks/[externals]_next_dist_03fe02e0._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__4b49000d._.js +0 -21
- package/docker-build/standalone/.next/server/chunks/[turbopack]_runtime.js +0 -795
- package/docker-build/standalone/.next/server/chunks/ssr/10072_infra_example-navidad__next-internal_server_app_page_actions_a387aef9.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_example-navidad_377109b0._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_example-navidad_90799f30._.js +0 -4
- package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_example-navidad_app_b9057478._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/66d90_example-navidad__next-internal_server_app__global-error_page_actions_a079475f.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/66d90_example-navidad__next-internal_server_app__not-found_page_actions_ac88cec2.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_51be1544._.js +0 -4
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_8dba0557._.js +0 -6
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_client_components_41330064._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_client_components_builtin_forbidden_ff3a0457.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_client_components_builtin_global-error_e0d57e6e.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_client_components_builtin_unauthorized_f1c47e13.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_d332f292._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_esm_build_templates_app-page_cf6afba1.js +0 -4
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__02f3f427._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__2f460610._.js +0 -4
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__4722e53c._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__53b749fa._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__61942f2d._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__7707ad1b._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__864cadbf._.js +0 -10
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__9939e281._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__b4b0aa8a._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__d2b7072b._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[turbopack]_runtime.js +0 -795
- package/docker-build/standalone/.next/server/functions-config-manifest.json +0 -4
- package/docker-build/standalone/.next/server/middleware-build-manifest.js +0 -20
- package/docker-build/standalone/.next/server/middleware-manifest.json +0 -6
- package/docker-build/standalone/.next/server/next-font-manifest.js +0 -1
- package/docker-build/standalone/.next/server/next-font-manifest.json +0 -15
- package/docker-build/standalone/.next/server/pages/404.html +0 -1
- package/docker-build/standalone/.next/server/pages/500.html +0 -2
- package/docker-build/standalone/.next/server/pages-manifest.json +0 -4
- package/docker-build/standalone/.next/server/server-reference-manifest.js +0 -1
- package/docker-build/standalone/.next/server/server-reference-manifest.json +0 -5
- package/docker-build/standalone/.next/static/_NbfI2TKfapiyxsQgIG3h/_buildManifest.js +0 -11
- package/docker-build/standalone/.next/static/_NbfI2TKfapiyxsQgIG3h/_clientMiddlewareManifest.json +0 -1
- package/docker-build/standalone/.next/static/_NbfI2TKfapiyxsQgIG3h/_ssgManifest.js +0 -1
- package/docker-build/standalone/.next/static/chunks/57d1af92f5dc15fa.js +0 -1
- package/docker-build/standalone/.next/static/chunks/6ae71d5e8ea4d1eb.js +0 -1
- package/docker-build/standalone/.next/static/chunks/70977d70c9306213.js +0 -1
- package/docker-build/standalone/.next/static/chunks/777dac7104fe2a30.js +0 -5
- package/docker-build/standalone/.next/static/chunks/a6dad97d9634a72d.js +0 -1
- package/docker-build/standalone/.next/static/chunks/a6dad97d9634a72d.js.map +0 -1
- package/docker-build/standalone/.next/static/chunks/d6aec49b013224a2.css +0 -3
- package/docker-build/standalone/.next/static/chunks/turbopack-0ce517fb6224c1f0.js +0 -4
- package/docker-build/standalone/.next/static/media/4fa387ec64143e14-s.c1fdd6c2.woff2 +0 -0
- package/docker-build/standalone/.next/static/media/7178b3e590c64307-s.b97b3418.woff2 +0 -0
- package/docker-build/standalone/.next/static/media/797e433ab948586e-s.p.dbea232f.woff2 +0 -0
- package/docker-build/standalone/.next/static/media/8a480f0b521d4e75-s.8e0177b5.woff2 +0 -0
- package/docker-build/standalone/.next/static/media/bbc41e54d2fcbd21-s.799d8ef8.woff2 +0 -0
- package/docker-build/standalone/.next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2 +0 -0
- package/docker-build/standalone/.next/static/media/favicon.0b3bf435.ico +0 -0
- package/docker-build/standalone/package.json +0 -26
- package/docker-build/standalone/public/file.svg +0 -1
- package/docker-build/standalone/public/globe.svg +0 -1
- package/docker-build/standalone/public/next.svg +0 -1
- package/docker-build/standalone/public/vercel.svg +0 -1
- package/docker-build/standalone/public/window.svg +0 -1
- package/docker-build/standalone/server.js +0 -38
package/src/commands/deploy.ts
CHANGED
|
@@ -7,8 +7,8 @@ import * as path from 'path';
|
|
|
7
7
|
import * as os from 'os';
|
|
8
8
|
|
|
9
9
|
export const deployCommand = new Command('deploy')
|
|
10
|
-
.description('Build and deploy Docker image for Next.js
|
|
11
|
-
.argument('<project-path>', 'Path to the
|
|
10
|
+
.description('Build and deploy Docker image for Next.js or Express application')
|
|
11
|
+
.argument('<project-path>', 'Path to the project directory')
|
|
12
12
|
.argument('[dest-folder]', 'Destination folder for Docker build context', './docker-build')
|
|
13
13
|
.option('--skip-build', 'Skip npm run build (assume already built)', false)
|
|
14
14
|
.option('--no-push', 'Build image but do not push to registry')
|
|
@@ -123,129 +123,164 @@ export const deployCommand = new Command('deploy')
|
|
|
123
123
|
// - Con --no-push: options.push = false (no hace push)
|
|
124
124
|
const shouldPush = options.push !== false;
|
|
125
125
|
|
|
126
|
+
// Detectar automáticamente el tipo de proyecto analizando package.json
|
|
127
|
+
const allDependencies = {
|
|
128
|
+
...(packageJson.dependencies || {}),
|
|
129
|
+
...(packageJson.devDependencies || {}),
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
let projectType: 'nextjs' | 'express' | null = null;
|
|
133
|
+
|
|
134
|
+
if (allDependencies.next || allDependencies['nextjs']) {
|
|
135
|
+
projectType = 'nextjs';
|
|
136
|
+
} else if (allDependencies.express) {
|
|
137
|
+
projectType = 'express';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!projectType) {
|
|
141
|
+
console.error(chalk.red(`❌ Error: No se pudo detectar el tipo de proyecto`));
|
|
142
|
+
console.error(chalk.yellow(' El proyecto debe tener "next" o "express" en las dependencias del package.json'));
|
|
143
|
+
console.error(chalk.yellow(' Dependencias encontradas:'));
|
|
144
|
+
const depKeys = Object.keys(allDependencies).slice(0, 10);
|
|
145
|
+
depKeys.forEach(dep => {
|
|
146
|
+
console.error(chalk.gray(` - ${dep}`));
|
|
147
|
+
});
|
|
148
|
+
if (Object.keys(allDependencies).length > 10) {
|
|
149
|
+
console.error(chalk.gray(` ... y ${Object.keys(allDependencies).length - 10} más`));
|
|
150
|
+
}
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
|
|
126
154
|
console.log(chalk.gray('Deployment Configuration:'));
|
|
127
155
|
console.log(chalk.white(` Project: ${chalk.green(projectName)}`));
|
|
156
|
+
console.log(chalk.white(` Type: ${chalk.green(projectType)}`));
|
|
128
157
|
console.log(chalk.white(` Version: ${chalk.green(version)}`));
|
|
129
158
|
console.log(chalk.white(` Image: ${chalk.green(imageName)}`));
|
|
130
159
|
console.log(chalk.white(` Latest: ${chalk.green(imageLatest)}`));
|
|
131
160
|
console.log(chalk.white(` Push to Registry: ${shouldPush ? chalk.green('Yes') : chalk.yellow('No')}\n`));
|
|
132
161
|
|
|
133
|
-
//
|
|
134
|
-
if (!options.skipBuild) {
|
|
135
|
-
const buildSpinner = ora('Building Next.js application...').start();
|
|
136
|
-
try {
|
|
137
|
-
execSync('npm run build', {
|
|
138
|
-
cwd: resolvedProjectPath,
|
|
139
|
-
stdio: 'pipe'
|
|
140
|
-
});
|
|
141
|
-
buildSpinner.succeed('Build completed successfully');
|
|
142
|
-
} catch (error) {
|
|
143
|
-
buildSpinner.fail('Build failed');
|
|
144
|
-
console.error(chalk.red('Error during build. Make sure you have "output: standalone" in next.config.ts'));
|
|
145
|
-
process.exit(1);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Verificar que existe .next/standalone
|
|
150
|
-
const standalonePath = path.join(resolvedProjectPath, '.next', 'standalone');
|
|
151
|
-
if (!fs.existsSync(standalonePath)) {
|
|
152
|
-
console.error(chalk.red(`❌ Error: No se encontró .next/standalone`));
|
|
153
|
-
console.error(chalk.yellow('Asegúrate de tener "output: standalone" en next.config.ts y ejecutar "npm run build"'));
|
|
154
|
-
process.exit(1);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Paso 2: Preparar directorio destino
|
|
162
|
+
// Preparar directorio destino
|
|
158
163
|
const resolvedDestFolder = path.resolve(destFolder);
|
|
159
|
-
const standaloneDest = path.join(resolvedDestFolder, 'standalone');
|
|
160
|
-
|
|
161
|
-
const copySpinner = ora('Copying standalone files...').start();
|
|
162
164
|
if (fs.existsSync(resolvedDestFolder)) {
|
|
163
165
|
fs.rmSync(resolvedDestFolder, { recursive: true, force: true });
|
|
164
166
|
}
|
|
165
|
-
fs.mkdirSync(
|
|
167
|
+
fs.mkdirSync(resolvedDestFolder, { recursive: true });
|
|
166
168
|
|
|
167
|
-
// Copiar contenido de standalone
|
|
168
|
-
const nextDir = findDirectory(standalonePath, '.next');
|
|
169
|
-
if (nextDir) {
|
|
170
|
-
const parentDir = path.dirname(nextDir);
|
|
171
|
-
copyDirectory(parentDir, standaloneDest);
|
|
172
|
-
} else {
|
|
173
|
-
copyDirectory(standalonePath, standaloneDest);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Copiar .next/static
|
|
177
|
-
const staticPath = path.join(resolvedProjectPath, '.next', 'static');
|
|
178
|
-
if (fs.existsSync(staticPath)) {
|
|
179
|
-
const staticDest = path.join(standaloneDest, '.next', 'static');
|
|
180
|
-
fs.mkdirSync(staticDest, { recursive: true });
|
|
181
|
-
copyDirectory(staticPath, staticDest);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Copiar public
|
|
185
|
-
const publicPath = path.join(resolvedProjectPath, 'public');
|
|
186
|
-
if (fs.existsSync(publicPath)) {
|
|
187
|
-
const publicDest = path.join(standaloneDest, 'public');
|
|
188
|
-
fs.mkdirSync(publicDest, { recursive: true });
|
|
189
|
-
copyDirectory(publicPath, publicDest);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// Verificar server.js
|
|
193
|
-
const serverJsPath = path.join(standaloneDest, 'server.js');
|
|
194
|
-
if (!fs.existsSync(serverJsPath)) {
|
|
195
|
-
copySpinner.fail('server.js not found in standalone');
|
|
196
|
-
process.exit(1);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
copySpinner.succeed('Files copied successfully');
|
|
200
|
-
|
|
201
|
-
// Leer y procesar archivo .env si existe
|
|
202
|
-
let nextPublicEnvVars: string[] = [];
|
|
203
169
|
let runtimeEnvVars: string[] = [];
|
|
170
|
+
let nextPublicEnvVars: string[] = [];
|
|
171
|
+
let dockerfileContent: string;
|
|
172
|
+
|
|
173
|
+
// Determinar ruta del archivo .env (común para ambos tipos de proyecto)
|
|
204
174
|
const envFilePath = options.envFile
|
|
205
175
|
? path.resolve(options.envFile)
|
|
206
176
|
: path.join(resolvedProjectPath, '.env');
|
|
207
|
-
|
|
208
|
-
if (
|
|
209
|
-
|
|
210
|
-
const envLines = envContent.split('\n');
|
|
177
|
+
|
|
178
|
+
if (projectType === 'nextjs') {
|
|
179
|
+
// ========== LÓGICA PARA NEXT.JS ==========
|
|
211
180
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
181
|
+
// Paso 1: Build del proyecto si es necesario
|
|
182
|
+
if (!options.skipBuild) {
|
|
183
|
+
const buildSpinner = ora('Building Next.js application...').start();
|
|
184
|
+
try {
|
|
185
|
+
execSync('npm run build', {
|
|
186
|
+
cwd: resolvedProjectPath,
|
|
187
|
+
stdio: 'pipe'
|
|
188
|
+
});
|
|
189
|
+
buildSpinner.succeed('Build completed successfully');
|
|
190
|
+
} catch (error) {
|
|
191
|
+
buildSpinner.fail('Build failed');
|
|
192
|
+
console.error(chalk.red('Error during build. Make sure you have "output: standalone" in next.config.ts'));
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Verificar que existe .next/standalone
|
|
198
|
+
const standalonePath = path.join(resolvedProjectPath, '.next', 'standalone');
|
|
199
|
+
if (!fs.existsSync(standalonePath)) {
|
|
200
|
+
console.error(chalk.red(`❌ Error: No se encontró .next/standalone`));
|
|
201
|
+
console.error(chalk.yellow('Asegúrate de tener "output: standalone" en next.config.ts y ejecutar "npm run build"'));
|
|
202
|
+
process.exit(1);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Paso 2: Preparar directorio destino
|
|
206
|
+
const standaloneDest = path.join(resolvedDestFolder, 'standalone');
|
|
207
|
+
|
|
208
|
+
const copySpinner = ora('Copying standalone files...').start();
|
|
209
|
+
fs.mkdirSync(standaloneDest, { recursive: true });
|
|
210
|
+
|
|
211
|
+
// Copiar contenido de standalone
|
|
212
|
+
const nextDir = findDirectory(standalonePath, '.next');
|
|
213
|
+
if (nextDir) {
|
|
214
|
+
const parentDir = path.dirname(nextDir);
|
|
215
|
+
copyDirectory(parentDir, standaloneDest);
|
|
216
|
+
} else {
|
|
217
|
+
copyDirectory(standalonePath, standaloneDest);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Copiar .next/static
|
|
221
|
+
const staticPath = path.join(resolvedProjectPath, '.next', 'static');
|
|
222
|
+
if (fs.existsSync(staticPath)) {
|
|
223
|
+
const staticDest = path.join(standaloneDest, '.next', 'static');
|
|
224
|
+
fs.mkdirSync(staticDest, { recursive: true });
|
|
225
|
+
copyDirectory(staticPath, staticDest);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Copiar public
|
|
229
|
+
const publicPath = path.join(resolvedProjectPath, 'public');
|
|
230
|
+
if (fs.existsSync(publicPath)) {
|
|
231
|
+
const publicDest = path.join(standaloneDest, 'public');
|
|
232
|
+
fs.mkdirSync(publicDest, { recursive: true });
|
|
233
|
+
copyDirectory(publicPath, publicDest);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Verificar server.js
|
|
237
|
+
const serverJsPath = path.join(standaloneDest, 'server.js');
|
|
238
|
+
if (!fs.existsSync(serverJsPath)) {
|
|
239
|
+
copySpinner.fail('server.js not found in standalone');
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
copySpinner.succeed('Files copied successfully');
|
|
244
|
+
|
|
245
|
+
// Leer y procesar archivo .env si existe
|
|
246
|
+
// (envFilePath ya está definido arriba)
|
|
247
|
+
if (fs.existsSync(envFilePath)) {
|
|
248
|
+
const envContent = fs.readFileSync(envFilePath, 'utf-8');
|
|
249
|
+
const envLines = envContent.split('\n');
|
|
222
250
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
251
|
+
for (const line of envLines) {
|
|
252
|
+
const trimmed = line.trim();
|
|
253
|
+
// Ignorar comentarios y líneas vacías
|
|
254
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
255
|
+
|
|
256
|
+
const equalIndex = trimmed.indexOf('=');
|
|
257
|
+
if (equalIndex === -1) continue;
|
|
258
|
+
|
|
259
|
+
const key = trimmed.substring(0, equalIndex).trim();
|
|
260
|
+
const value = trimmed.substring(equalIndex + 1).trim();
|
|
261
|
+
|
|
262
|
+
if (key.startsWith('NEXT_PUBLIC_')) {
|
|
263
|
+
nextPublicEnvVars.push(`${key}=${value}`);
|
|
264
|
+
} else {
|
|
265
|
+
runtimeEnvVars.push(`${key}=${value}`);
|
|
266
|
+
}
|
|
227
267
|
}
|
|
228
268
|
}
|
|
229
|
-
}
|
|
230
269
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
return `ENV ${key}=${value}`;
|
|
246
|
-
}).join('\n');
|
|
247
|
-
|
|
248
|
-
const dockerfileContent = `FROM node:20-alpine
|
|
270
|
+
// Construir ARG y ENV para NEXT_PUBLIC_*
|
|
271
|
+
const buildArgs = nextPublicEnvVars.map(env => {
|
|
272
|
+
const [key, ...valueParts] = env.split('=');
|
|
273
|
+
const value = valueParts.join('=');
|
|
274
|
+
return `ARG ${key}=${value}`;
|
|
275
|
+
}).join('\n');
|
|
276
|
+
|
|
277
|
+
const buildEnvs = nextPublicEnvVars.map(env => {
|
|
278
|
+
const [key, ...valueParts] = env.split('=');
|
|
279
|
+
const value = valueParts.join('=');
|
|
280
|
+
return `ENV ${key}=${value}`;
|
|
281
|
+
}).join('\n');
|
|
282
|
+
|
|
283
|
+
dockerfileContent = `FROM node:20-alpine
|
|
249
284
|
WORKDIR /app
|
|
250
285
|
|
|
251
286
|
ENV NODE_ENV=production
|
|
@@ -264,12 +299,197 @@ EXPOSE 3000
|
|
|
264
299
|
# Arrancamos directamente con Node
|
|
265
300
|
CMD ["node", "server.js"]
|
|
266
301
|
`;
|
|
302
|
+
|
|
303
|
+
} else {
|
|
304
|
+
// ========== LÓGICA PARA EXPRESS ==========
|
|
305
|
+
|
|
306
|
+
// Paso 1: Instalar dependencias de producción si es necesario
|
|
307
|
+
if (!options.skipBuild) {
|
|
308
|
+
const installSpinner = ora('Installing production dependencies...').start();
|
|
309
|
+
try {
|
|
310
|
+
// Verificar si node_modules existe
|
|
311
|
+
const nodeModulesPath = path.join(resolvedProjectPath, 'node_modules');
|
|
312
|
+
if (!fs.existsSync(nodeModulesPath)) {
|
|
313
|
+
execSync('npm install --production', {
|
|
314
|
+
cwd: resolvedProjectPath,
|
|
315
|
+
stdio: 'pipe'
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
installSpinner.succeed('Dependencies ready');
|
|
319
|
+
} catch (error) {
|
|
320
|
+
installSpinner.fail('Failed to install dependencies');
|
|
321
|
+
console.error(chalk.red('Error installing dependencies'));
|
|
322
|
+
process.exit(1);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Paso 2: Copiar archivos del proyecto (sin node_modules, Docker lo instalará)
|
|
327
|
+
const copySpinner = ora('Copying project files...').start();
|
|
328
|
+
|
|
329
|
+
// Copiar todos los archivos excepto los que están en .dockerignore
|
|
330
|
+
const ignorePatterns = [
|
|
331
|
+
'node_modules',
|
|
332
|
+
'.git',
|
|
333
|
+
'.next',
|
|
334
|
+
'dist',
|
|
335
|
+
'build',
|
|
336
|
+
'.env',
|
|
337
|
+
'.env.local',
|
|
338
|
+
'.env.*.local',
|
|
339
|
+
'npm-debug.log*',
|
|
340
|
+
'yarn-debug.log*',
|
|
341
|
+
'yarn-error.log*',
|
|
342
|
+
'.DS_Store',
|
|
343
|
+
'coverage',
|
|
344
|
+
'.nyc_output',
|
|
345
|
+
];
|
|
346
|
+
|
|
347
|
+
function shouldIgnore(filePath: string, basePath: string): boolean {
|
|
348
|
+
const relativePath = path.relative(basePath, filePath);
|
|
349
|
+
return ignorePatterns.some(pattern => {
|
|
350
|
+
if (relativePath.includes(pattern)) return true;
|
|
351
|
+
// Verificar si es un archivo que empieza con el patrón
|
|
352
|
+
const parts = relativePath.split(path.sep);
|
|
353
|
+
return parts.some(part => part === pattern || part.startsWith(pattern));
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function copyProjectFiles(src: string, dest: string): void {
|
|
358
|
+
if (!fs.existsSync(dest)) {
|
|
359
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
363
|
+
for (const entry of entries) {
|
|
364
|
+
const srcPath = path.join(src, entry.name);
|
|
365
|
+
const destPath = path.join(dest, entry.name);
|
|
366
|
+
|
|
367
|
+
// Ignorar archivos y directorios según los patrones
|
|
368
|
+
if (shouldIgnore(srcPath, resolvedProjectPath)) {
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
try {
|
|
373
|
+
const stats = fs.lstatSync(srcPath);
|
|
374
|
+
|
|
375
|
+
if (stats.isDirectory()) {
|
|
376
|
+
copyProjectFiles(srcPath, destPath);
|
|
377
|
+
} else if (stats.isFile()) {
|
|
378
|
+
fs.copyFileSync(srcPath, destPath);
|
|
379
|
+
}
|
|
380
|
+
} catch (error: any) {
|
|
381
|
+
// Ignorar errores al copiar archivos especiales
|
|
382
|
+
if (error.code === 'ENOTSUP' || error.code === 'EINVAL' || error.code === 'EOPNOTSUPP') {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
throw error;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Copiar archivos del proyecto
|
|
391
|
+
copyProjectFiles(resolvedProjectPath, resolvedDestFolder);
|
|
392
|
+
|
|
393
|
+
// Verificar que existe package.json en el destino
|
|
394
|
+
const destPackageJson = path.join(resolvedDestFolder, 'package.json');
|
|
395
|
+
if (!fs.existsSync(destPackageJson)) {
|
|
396
|
+
copySpinner.fail('package.json not found');
|
|
397
|
+
console.error(chalk.red('❌ Error: package.json is required for Express application'));
|
|
398
|
+
process.exit(1);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Verificar que existe un archivo principal
|
|
402
|
+
const packageJson = JSON.parse(fs.readFileSync(destPackageJson, 'utf-8'));
|
|
403
|
+
const mainFile = packageJson.main || 'index.js';
|
|
404
|
+
const mainFilePath = path.join(resolvedDestFolder, mainFile);
|
|
405
|
+
|
|
406
|
+
if (!fs.existsSync(mainFilePath)) {
|
|
407
|
+
// Buscar otros archivos comunes
|
|
408
|
+
const commonFiles = ['index.js', 'server.js', 'app.js', 'main.js'];
|
|
409
|
+
let found = false;
|
|
410
|
+
for (const file of commonFiles) {
|
|
411
|
+
if (fs.existsSync(path.join(resolvedDestFolder, file))) {
|
|
412
|
+
found = true;
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (!found) {
|
|
417
|
+
copySpinner.fail(`Main entry file not found: ${mainFile}`);
|
|
418
|
+
console.error(chalk.red(`❌ Error: Could not find main entry file (${mainFile}) for Express application`));
|
|
419
|
+
process.exit(1);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
copySpinner.succeed('Files copied successfully');
|
|
424
|
+
|
|
425
|
+
// Leer y procesar archivo .env si existe
|
|
426
|
+
// (envFilePath ya está definido arriba)
|
|
427
|
+
if (fs.existsSync(envFilePath)) {
|
|
428
|
+
const envContent = fs.readFileSync(envFilePath, 'utf-8');
|
|
429
|
+
const envLines = envContent.split('\n');
|
|
430
|
+
|
|
431
|
+
for (const line of envLines) {
|
|
432
|
+
const trimmed = line.trim();
|
|
433
|
+
// Ignorar comentarios y líneas vacías
|
|
434
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
435
|
+
|
|
436
|
+
const equalIndex = trimmed.indexOf('=');
|
|
437
|
+
if (equalIndex === -1) continue;
|
|
438
|
+
|
|
439
|
+
const key = trimmed.substring(0, equalIndex).trim();
|
|
440
|
+
const value = trimmed.substring(equalIndex + 1).trim();
|
|
441
|
+
|
|
442
|
+
runtimeEnvVars.push(`${key}=${value}`);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Crear Dockerfile optimizado para Express
|
|
447
|
+
// (destPackageJson, packageJson y mainFile ya están declaradas arriba)
|
|
448
|
+
const startScript = packageJson.scripts?.start;
|
|
449
|
+
|
|
450
|
+
// Determinar el comando de inicio
|
|
451
|
+
let startCmd: string[];
|
|
452
|
+
if (startScript) {
|
|
453
|
+
// Si hay un script start, usarlo
|
|
454
|
+
startCmd = startScript.split(' ');
|
|
455
|
+
} else {
|
|
456
|
+
// Si no, usar node con el archivo principal
|
|
457
|
+
startCmd = ['node', mainFile];
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
dockerfileContent = `FROM node:20-alpine
|
|
461
|
+
|
|
462
|
+
WORKDIR /app
|
|
463
|
+
|
|
464
|
+
ENV NODE_ENV=production
|
|
465
|
+
ENV PORT=3000
|
|
466
|
+
|
|
467
|
+
# Copiar package files primero para aprovechar cache de Docker
|
|
468
|
+
COPY package*.json ./
|
|
469
|
+
|
|
470
|
+
# Instalar solo dependencias de producción
|
|
471
|
+
RUN npm ci --only=production && npm cache clean --force
|
|
472
|
+
|
|
473
|
+
# Copiar código fuente
|
|
474
|
+
COPY . .
|
|
475
|
+
|
|
476
|
+
# Exponemos el puerto
|
|
477
|
+
EXPOSE 3000
|
|
478
|
+
|
|
479
|
+
# Comando de inicio
|
|
480
|
+
CMD ${JSON.stringify(startCmd)}
|
|
481
|
+
`;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Paso 3: Crear Dockerfile
|
|
485
|
+
const dockerfileSpinner = ora('Creating Dockerfile...').start();
|
|
486
|
+
const dockerfilePath = path.join(resolvedDestFolder, 'Dockerfile');
|
|
267
487
|
fs.writeFileSync(dockerfilePath, dockerfileContent);
|
|
268
488
|
|
|
269
489
|
dockerfileSpinner.succeed('Dockerfile created');
|
|
270
490
|
|
|
271
|
-
// Mostrar contenido del Dockerfile
|
|
272
|
-
if (nextPublicEnvVars.length > 0) {
|
|
491
|
+
// Mostrar contenido del Dockerfile
|
|
492
|
+
if (projectType === 'nextjs' && nextPublicEnvVars.length > 0) {
|
|
273
493
|
console.log(chalk.gray('\n📄 Dockerfile content:'));
|
|
274
494
|
console.log(chalk.gray('─'.repeat(60)));
|
|
275
495
|
console.log(chalk.white(dockerfileContent));
|
|
@@ -280,7 +500,7 @@ CMD ["node", "server.js"]
|
|
|
280
500
|
console.log(chalk.gray(` - ${chalk.cyan(key)}`));
|
|
281
501
|
});
|
|
282
502
|
} else {
|
|
283
|
-
console.log(chalk.gray(
|
|
503
|
+
console.log(chalk.gray(`\n📄 Dockerfile created for ${projectType} application`));
|
|
284
504
|
}
|
|
285
505
|
|
|
286
506
|
// Paso 4: Verificar/crear builder multi-plataforma
|
package/docker-build/Dockerfile
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
FROM node:20-alpine
|
|
2
|
-
WORKDIR /app
|
|
3
|
-
|
|
4
|
-
ENV NODE_ENV=production
|
|
5
|
-
ENV PORT=3000
|
|
6
|
-
|
|
7
|
-
ARG NEXT_PUBLIC_API_URL=http://localhost:3000
|
|
8
|
-
|
|
9
|
-
ENV NEXT_PUBLIC_API_URL=http://localhost:3000
|
|
10
|
-
|
|
11
|
-
# Copiamos el contenido de standalone
|
|
12
|
-
COPY standalone/ .
|
|
13
|
-
|
|
14
|
-
# Exponemos el puerto para Traefik
|
|
15
|
-
EXPOSE 3000
|
|
16
|
-
|
|
17
|
-
# Arrancamos directamente con Node
|
|
18
|
-
CMD ["node", "server.js"]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
_NbfI2TKfapiyxsQgIG3h
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"pages": {
|
|
3
|
-
"/_app": []
|
|
4
|
-
},
|
|
5
|
-
"devFiles": [],
|
|
6
|
-
"polyfillFiles": [
|
|
7
|
-
"static/chunks/a6dad97d9634a72d.js"
|
|
8
|
-
],
|
|
9
|
-
"lowPriorityFiles": [
|
|
10
|
-
"static/_NbfI2TKfapiyxsQgIG3h/_ssgManifest.js",
|
|
11
|
-
"static/_NbfI2TKfapiyxsQgIG3h/_buildManifest.js"
|
|
12
|
-
],
|
|
13
|
-
"rootMainFiles": [
|
|
14
|
-
"static/chunks/6ae71d5e8ea4d1eb.js",
|
|
15
|
-
"static/chunks/70977d70c9306213.js",
|
|
16
|
-
"static/chunks/777dac7104fe2a30.js",
|
|
17
|
-
"static/chunks/turbopack-0ce517fb6224c1f0.js"
|
|
18
|
-
]
|
|
19
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"type": "commonjs"}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 4,
|
|
3
|
-
"routes": {
|
|
4
|
-
"/_global-error": {
|
|
5
|
-
"experimentalBypassFor": [
|
|
6
|
-
{
|
|
7
|
-
"type": "header",
|
|
8
|
-
"key": "next-action"
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
"type": "header",
|
|
12
|
-
"key": "content-type",
|
|
13
|
-
"value": "multipart/form-data;.*"
|
|
14
|
-
}
|
|
15
|
-
],
|
|
16
|
-
"initialRevalidateSeconds": false,
|
|
17
|
-
"srcRoute": "/_global-error",
|
|
18
|
-
"dataRoute": "/_global-error.rsc",
|
|
19
|
-
"allowHeader": [
|
|
20
|
-
"host",
|
|
21
|
-
"x-matched-path",
|
|
22
|
-
"x-prerender-revalidate",
|
|
23
|
-
"x-prerender-revalidate-if-generated",
|
|
24
|
-
"x-next-revalidated-tags",
|
|
25
|
-
"x-next-revalidate-tag-token"
|
|
26
|
-
]
|
|
27
|
-
},
|
|
28
|
-
"/_not-found": {
|
|
29
|
-
"initialStatus": 404,
|
|
30
|
-
"experimentalBypassFor": [
|
|
31
|
-
{
|
|
32
|
-
"type": "header",
|
|
33
|
-
"key": "next-action"
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
"type": "header",
|
|
37
|
-
"key": "content-type",
|
|
38
|
-
"value": "multipart/form-data;.*"
|
|
39
|
-
}
|
|
40
|
-
],
|
|
41
|
-
"initialRevalidateSeconds": false,
|
|
42
|
-
"srcRoute": "/_not-found",
|
|
43
|
-
"dataRoute": "/_not-found.rsc",
|
|
44
|
-
"allowHeader": [
|
|
45
|
-
"host",
|
|
46
|
-
"x-matched-path",
|
|
47
|
-
"x-prerender-revalidate",
|
|
48
|
-
"x-prerender-revalidate-if-generated",
|
|
49
|
-
"x-next-revalidated-tags",
|
|
50
|
-
"x-next-revalidate-tag-token"
|
|
51
|
-
]
|
|
52
|
-
},
|
|
53
|
-
"/favicon.ico": {
|
|
54
|
-
"initialHeaders": {
|
|
55
|
-
"cache-control": "public, max-age=0, must-revalidate",
|
|
56
|
-
"content-type": "image/x-icon",
|
|
57
|
-
"x-next-cache-tags": "_N_T_/layout,_N_T_/favicon.ico/layout,_N_T_/favicon.ico/route,_N_T_/favicon.ico"
|
|
58
|
-
},
|
|
59
|
-
"experimentalBypassFor": [
|
|
60
|
-
{
|
|
61
|
-
"type": "header",
|
|
62
|
-
"key": "next-action"
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
"type": "header",
|
|
66
|
-
"key": "content-type",
|
|
67
|
-
"value": "multipart/form-data;.*"
|
|
68
|
-
}
|
|
69
|
-
],
|
|
70
|
-
"initialRevalidateSeconds": false,
|
|
71
|
-
"srcRoute": "/favicon.ico",
|
|
72
|
-
"dataRoute": null,
|
|
73
|
-
"allowHeader": [
|
|
74
|
-
"host",
|
|
75
|
-
"x-matched-path",
|
|
76
|
-
"x-prerender-revalidate",
|
|
77
|
-
"x-prerender-revalidate-if-generated",
|
|
78
|
-
"x-next-revalidated-tags",
|
|
79
|
-
"x-next-revalidate-tag-token"
|
|
80
|
-
]
|
|
81
|
-
},
|
|
82
|
-
"/": {
|
|
83
|
-
"experimentalBypassFor": [
|
|
84
|
-
{
|
|
85
|
-
"type": "header",
|
|
86
|
-
"key": "next-action"
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
"type": "header",
|
|
90
|
-
"key": "content-type",
|
|
91
|
-
"value": "multipart/form-data;.*"
|
|
92
|
-
}
|
|
93
|
-
],
|
|
94
|
-
"initialRevalidateSeconds": false,
|
|
95
|
-
"srcRoute": "/",
|
|
96
|
-
"dataRoute": "/index.rsc",
|
|
97
|
-
"allowHeader": [
|
|
98
|
-
"host",
|
|
99
|
-
"x-matched-path",
|
|
100
|
-
"x-prerender-revalidate",
|
|
101
|
-
"x-prerender-revalidate-if-generated",
|
|
102
|
-
"x-next-revalidated-tags",
|
|
103
|
-
"x-next-revalidate-tag-token"
|
|
104
|
-
]
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
"dynamicRoutes": {},
|
|
108
|
-
"notFoundRoutes": [],
|
|
109
|
-
"preview": {
|
|
110
|
-
"previewModeId": "97906e79384b81f9f7dfdaf2500bd376",
|
|
111
|
-
"previewModeSigningKey": "c8a81f6f74dd50351ecd5dbef909560e00593cf675251719bb21e6883e641dd0",
|
|
112
|
-
"previewModeEncryptionKey": "19b4f3ad1cee9c6cca1d9181bc9538fb585641fa19708384b8411c7dc5bd32bc"
|
|
113
|
-
}
|
|
114
|
-
}
|