nept-frameworks 0.1.0
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/README.md +81 -0
- package/dist/framework-defaults.d.ts +514 -0
- package/dist/index.d.ts +458 -0
- package/dist/index.js +849 -0
- package/dist/lib/dockerfile-generator.d.ts +5 -0
- package/dist/lib/index.d.ts +5 -0
- package/dist/lib/next-js/next-dockerfile-generator.d.ts +2 -0
- package/dist/types/dockerfile.d.ts +24 -0
- package/dist/types/next-dockerfile.d.ts +1 -0
- package/package.json +42 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,849 @@
|
|
|
1
|
+
// src/lib/dockerfile-generator.ts
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
// src/framework-defaults.ts
|
|
6
|
+
var supported = {
|
|
7
|
+
next: {
|
|
8
|
+
displayName: "Next.js",
|
|
9
|
+
language: "TypeScript",
|
|
10
|
+
stackType: "fullstack",
|
|
11
|
+
defaultPort: 3000,
|
|
12
|
+
defaultRuntime: "node",
|
|
13
|
+
defaultVersion: "24.18.0-trixie-slim",
|
|
14
|
+
status: "supported",
|
|
15
|
+
deployment: {
|
|
16
|
+
kind: "js-artifact",
|
|
17
|
+
selfContained: true,
|
|
18
|
+
copies: [
|
|
19
|
+
["/app/public", "./public"],
|
|
20
|
+
["/app/.next/standalone", "./"],
|
|
21
|
+
["/app/.next/static", "./.next/static"]
|
|
22
|
+
],
|
|
23
|
+
entrypoint: "server.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
nuxt: {
|
|
27
|
+
displayName: "Nuxt",
|
|
28
|
+
language: "TypeScript",
|
|
29
|
+
stackType: "fullstack",
|
|
30
|
+
defaultPort: 3000,
|
|
31
|
+
defaultRuntime: "node",
|
|
32
|
+
defaultVersion: "24.18.0-trixie-slim",
|
|
33
|
+
status: "supported",
|
|
34
|
+
deployment: {
|
|
35
|
+
kind: "js-artifact",
|
|
36
|
+
selfContained: true,
|
|
37
|
+
copies: [["/app/.output", "./.output"]],
|
|
38
|
+
entrypoint: ".output/server/index.mjs"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
astro: {
|
|
42
|
+
displayName: "Astro",
|
|
43
|
+
language: "TypeScript",
|
|
44
|
+
stackType: "fullstack",
|
|
45
|
+
defaultPort: 3000,
|
|
46
|
+
defaultRuntime: "node",
|
|
47
|
+
defaultVersion: "24.18.0-trixie-slim",
|
|
48
|
+
status: "supported",
|
|
49
|
+
deployment: {
|
|
50
|
+
kind: "js-artifact",
|
|
51
|
+
selfContained: false,
|
|
52
|
+
copies: [["/app/dist", "./dist"]],
|
|
53
|
+
entrypoint: "dist/server/entry.mjs"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
sveltekit: {
|
|
57
|
+
displayName: "SvelteKit",
|
|
58
|
+
language: "TypeScript",
|
|
59
|
+
stackType: "fullstack",
|
|
60
|
+
defaultPort: 3000,
|
|
61
|
+
defaultRuntime: "node",
|
|
62
|
+
defaultVersion: "24.18.0-trixie-slim",
|
|
63
|
+
status: "supported",
|
|
64
|
+
deployment: {
|
|
65
|
+
kind: "js-artifact",
|
|
66
|
+
selfContained: false,
|
|
67
|
+
copies: [["/app/build", "./build"]],
|
|
68
|
+
entrypoint: "build/index.js"
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
remix: {
|
|
72
|
+
displayName: "Remix",
|
|
73
|
+
language: "TypeScript",
|
|
74
|
+
stackType: "fullstack",
|
|
75
|
+
defaultPort: 3000,
|
|
76
|
+
defaultRuntime: "node",
|
|
77
|
+
defaultVersion: "24.18.0-trixie-slim",
|
|
78
|
+
status: "supported",
|
|
79
|
+
deployment: {
|
|
80
|
+
kind: "js-artifact",
|
|
81
|
+
selfContained: false,
|
|
82
|
+
copies: [["/app/build", "./build"]],
|
|
83
|
+
entrypoint: "node_modules/@remix-run/serve/dist/cli.js",
|
|
84
|
+
entrypointArgument: "build/server/index.js"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
qwik: {
|
|
88
|
+
displayName: "Qwik",
|
|
89
|
+
language: "TypeScript",
|
|
90
|
+
stackType: "fullstack",
|
|
91
|
+
defaultPort: 3000,
|
|
92
|
+
defaultRuntime: "node",
|
|
93
|
+
defaultVersion: "24.18.0-trixie-slim",
|
|
94
|
+
status: "supported",
|
|
95
|
+
deployment: {
|
|
96
|
+
kind: "js-artifact",
|
|
97
|
+
selfContained: false,
|
|
98
|
+
copies: [
|
|
99
|
+
["/app/dist", "./dist"],
|
|
100
|
+
["/app/server", "./server"]
|
|
101
|
+
],
|
|
102
|
+
entrypoint: "server/entry.node-server.js"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var planned = (displayName, language, stackType, defaultPort, defaultRuntime, defaultVersion) => ({
|
|
107
|
+
displayName,
|
|
108
|
+
language,
|
|
109
|
+
stackType,
|
|
110
|
+
defaultPort,
|
|
111
|
+
defaultRuntime,
|
|
112
|
+
defaultVersion,
|
|
113
|
+
status: "planned"
|
|
114
|
+
});
|
|
115
|
+
var excluded = (displayName, language, defaultPort) => ({
|
|
116
|
+
displayName,
|
|
117
|
+
language,
|
|
118
|
+
stackType: "static",
|
|
119
|
+
defaultPort,
|
|
120
|
+
defaultRuntime: "nginx",
|
|
121
|
+
defaultVersion: "1.29.8-alpine",
|
|
122
|
+
status: "excluded"
|
|
123
|
+
});
|
|
124
|
+
var FRAMEWORK_DEFAULTS = {
|
|
125
|
+
...supported,
|
|
126
|
+
express: {
|
|
127
|
+
...planned("Express", "JavaScript", "backend", 3000, "node", "24.18.0-trixie-slim"),
|
|
128
|
+
status: "supported",
|
|
129
|
+
deployment: { kind: "js-source", build: false, entrypoint: "server.js" }
|
|
130
|
+
},
|
|
131
|
+
nest: {
|
|
132
|
+
...planned("NestJS", "TypeScript", "backend", 3000, "node", "24.18.0-trixie-slim"),
|
|
133
|
+
status: "supported",
|
|
134
|
+
deployment: { kind: "js-source", build: true, entrypoint: "dist/main.js" }
|
|
135
|
+
},
|
|
136
|
+
fastify: {
|
|
137
|
+
...planned("Fastify", "JavaScript", "backend", 3000, "node", "24.18.0-trixie-slim"),
|
|
138
|
+
status: "supported",
|
|
139
|
+
deployment: { kind: "js-source", build: false, entrypoint: "server.js" }
|
|
140
|
+
},
|
|
141
|
+
koa: {
|
|
142
|
+
...planned("Koa", "JavaScript", "backend", 3000, "node", "24.18.0-trixie-slim"),
|
|
143
|
+
status: "supported",
|
|
144
|
+
deployment: { kind: "js-source", build: false, entrypoint: "server.js" }
|
|
145
|
+
},
|
|
146
|
+
deno: {
|
|
147
|
+
...planned("Deno", "TypeScript", "backend", 8000, "deno", "2.9.2"),
|
|
148
|
+
status: "supported",
|
|
149
|
+
deployment: { kind: "deno-source", entrypoint: "main.ts" }
|
|
150
|
+
},
|
|
151
|
+
bun: {
|
|
152
|
+
...planned("Bun", "TypeScript", "backend", 3000, "bun", "1.3.14-slim"),
|
|
153
|
+
status: "supported",
|
|
154
|
+
deployment: { kind: "bun-source", entrypoint: "server.ts" }
|
|
155
|
+
},
|
|
156
|
+
django: {
|
|
157
|
+
...planned("Django", "Python", "backend", 8000, "python", "3.14.6-slim-trixie"),
|
|
158
|
+
status: "supported",
|
|
159
|
+
deployment: { kind: "python", command: ["gunicorn", "config.wsgi:application", "--bind", "0.0.0.0:8000"] }
|
|
160
|
+
},
|
|
161
|
+
flask: {
|
|
162
|
+
...planned("Flask", "Python", "backend", 8000, "python", "3.14.6-slim-trixie"),
|
|
163
|
+
status: "supported",
|
|
164
|
+
deployment: { kind: "python", command: ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"] }
|
|
165
|
+
},
|
|
166
|
+
fastapi: {
|
|
167
|
+
...planned("FastAPI", "Python", "backend", 8000, "python", "3.14.6-slim-trixie"),
|
|
168
|
+
status: "supported",
|
|
169
|
+
deployment: { kind: "python", command: ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"] }
|
|
170
|
+
},
|
|
171
|
+
python: {
|
|
172
|
+
...planned("Python", "Python", "backend", 8000, "python", "3.14.6-slim-trixie"),
|
|
173
|
+
status: "supported",
|
|
174
|
+
deployment: { kind: "python", command: ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"] }
|
|
175
|
+
},
|
|
176
|
+
go: {
|
|
177
|
+
...planned("Go", "Go", "backend", 8080, "go", "1.26.5-trixie"),
|
|
178
|
+
status: "supported",
|
|
179
|
+
deployment: { kind: "go" }
|
|
180
|
+
},
|
|
181
|
+
gin: {
|
|
182
|
+
...planned("Gin", "Go", "backend", 8080, "go", "1.26.5-trixie"),
|
|
183
|
+
status: "supported",
|
|
184
|
+
deployment: { kind: "go" }
|
|
185
|
+
},
|
|
186
|
+
echo: {
|
|
187
|
+
...planned("Echo", "Go", "backend", 1323, "go", "1.26.5-trixie"),
|
|
188
|
+
status: "supported",
|
|
189
|
+
deployment: { kind: "go" }
|
|
190
|
+
},
|
|
191
|
+
rust: {
|
|
192
|
+
...planned("Rust", "Rust", "backend", 8080, "rust", "1.97.0-slim-trixie"),
|
|
193
|
+
status: "supported",
|
|
194
|
+
deployment: { kind: "rust" }
|
|
195
|
+
},
|
|
196
|
+
actix: {
|
|
197
|
+
...planned("Actix Web", "Rust", "backend", 8080, "rust", "1.97.0-slim-trixie"),
|
|
198
|
+
status: "supported",
|
|
199
|
+
deployment: { kind: "rust" }
|
|
200
|
+
},
|
|
201
|
+
rocket: {
|
|
202
|
+
...planned("Rocket", "Rust", "backend", 8000, "rust", "1.97.0-slim-trixie"),
|
|
203
|
+
status: "supported",
|
|
204
|
+
deployment: { kind: "rust" }
|
|
205
|
+
},
|
|
206
|
+
java: {
|
|
207
|
+
...planned("Java", "Java", "backend", 8080, "java", "25.0.3_9-jre-noble"),
|
|
208
|
+
status: "supported",
|
|
209
|
+
deployment: { kind: "java", mode: "class" }
|
|
210
|
+
},
|
|
211
|
+
springBoot: {
|
|
212
|
+
...planned("Spring Boot", "Java", "backend", 8080, "java", "25.0.3_9-jre-noble"),
|
|
213
|
+
status: "supported",
|
|
214
|
+
deployment: { kind: "java", mode: "jar" }
|
|
215
|
+
},
|
|
216
|
+
quarkus: {
|
|
217
|
+
...planned("Quarkus", "Java", "backend", 8080, "java", "25.0.3_9-jre-noble"),
|
|
218
|
+
status: "supported",
|
|
219
|
+
deployment: { kind: "java", mode: "quarkus" }
|
|
220
|
+
},
|
|
221
|
+
ruby: {
|
|
222
|
+
...planned("Ruby", "Ruby", "backend", 4567, "ruby", "4.0.5-slim-trixie"),
|
|
223
|
+
status: "supported",
|
|
224
|
+
deployment: { kind: "ruby", command: ["ruby", "app.rb"] }
|
|
225
|
+
},
|
|
226
|
+
rails: {
|
|
227
|
+
...planned("Ruby on Rails", "Ruby", "backend", 3000, "ruby", "4.0.5-slim-trixie"),
|
|
228
|
+
status: "supported",
|
|
229
|
+
deployment: { kind: "ruby", command: ["bundle", "exec", "rails", "server", "-b", "0.0.0.0", "-p", "3000"] }
|
|
230
|
+
},
|
|
231
|
+
php: {
|
|
232
|
+
...planned("PHP", "PHP", "backend", 8080, "php", "8.5.8-apache-trixie"),
|
|
233
|
+
status: "supported",
|
|
234
|
+
deployment: { kind: "php" }
|
|
235
|
+
},
|
|
236
|
+
laravel: {
|
|
237
|
+
...planned("Laravel", "PHP", "backend", 8080, "php", "8.5.8-apache-trixie"),
|
|
238
|
+
status: "supported",
|
|
239
|
+
deployment: { kind: "php" }
|
|
240
|
+
},
|
|
241
|
+
symfony: {
|
|
242
|
+
...planned("Symfony", "PHP", "backend", 8080, "php", "8.5.8-apache-trixie"),
|
|
243
|
+
status: "supported",
|
|
244
|
+
deployment: { kind: "php" }
|
|
245
|
+
},
|
|
246
|
+
csharp: {
|
|
247
|
+
...planned("C#", "C#", "backend", 8080, "dotnet", "10.0-noble"),
|
|
248
|
+
status: "supported",
|
|
249
|
+
deployment: { kind: "dotnet", aspnet: false, dll: "App.dll" }
|
|
250
|
+
},
|
|
251
|
+
aspnet: {
|
|
252
|
+
...planned("ASP.NET Core", "C#", "backend", 8080, "dotnet", "10.0-noble"),
|
|
253
|
+
status: "supported",
|
|
254
|
+
deployment: { kind: "dotnet", aspnet: true, dll: "App.dll" }
|
|
255
|
+
},
|
|
256
|
+
other: {
|
|
257
|
+
...planned("Other", "Other", "backend", 8080, "custom", "required"),
|
|
258
|
+
status: "supported",
|
|
259
|
+
deployment: { kind: "custom" }
|
|
260
|
+
},
|
|
261
|
+
html: excluded("HTML/CSS/JS", "HTML", 80),
|
|
262
|
+
react: excluded("React", "JavaScript", 80),
|
|
263
|
+
vue: excluded("Vue", "JavaScript", 80),
|
|
264
|
+
angular: excluded("Angular", "TypeScript", 80),
|
|
265
|
+
svelte: excluded("Svelte", "JavaScript", 80),
|
|
266
|
+
vite: excluded("Vite", "JavaScript", 80),
|
|
267
|
+
gatsby: excluded("Gatsby", "JavaScript", 80),
|
|
268
|
+
solid: excluded("Solid", "JavaScript", 80)
|
|
269
|
+
};
|
|
270
|
+
function getJavaScriptDeployment(framework) {
|
|
271
|
+
const deployment = FRAMEWORK_DEFAULTS[framework].deployment;
|
|
272
|
+
if (deployment?.kind !== "js-artifact") {
|
|
273
|
+
throw new Error(`${framework} is not an artifact framework`);
|
|
274
|
+
}
|
|
275
|
+
return deployment;
|
|
276
|
+
}
|
|
277
|
+
function defaultVersionFor(runtime) {
|
|
278
|
+
if (runtime === "bun")
|
|
279
|
+
return "1.3.14-slim";
|
|
280
|
+
if (runtime === "deno")
|
|
281
|
+
return "2.9.2";
|
|
282
|
+
return "24.18.0-trixie-slim";
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// src/lib/dockerfile-generator.ts
|
|
286
|
+
var packageManagers = {
|
|
287
|
+
bun: {
|
|
288
|
+
lockfile: "bun.lock",
|
|
289
|
+
install: "bun install --frozen-lockfile",
|
|
290
|
+
production: "bun install --frozen-lockfile --production",
|
|
291
|
+
build: "bun run build",
|
|
292
|
+
cache: "/root/.bun/install/cache"
|
|
293
|
+
},
|
|
294
|
+
npm: {
|
|
295
|
+
lockfile: "package-lock.json",
|
|
296
|
+
install: "npm ci --no-audit --no-fund",
|
|
297
|
+
production: "npm prune --omit=dev",
|
|
298
|
+
build: "npm run build",
|
|
299
|
+
cache: "/root/.npm"
|
|
300
|
+
},
|
|
301
|
+
pnpm: {
|
|
302
|
+
lockfile: "pnpm-lock.yaml",
|
|
303
|
+
install: "corepack enable && pnpm install --frozen-lockfile",
|
|
304
|
+
production: "pnpm prune --prod",
|
|
305
|
+
build: "pnpm run build",
|
|
306
|
+
cache: "/root/.local/share/pnpm/store"
|
|
307
|
+
},
|
|
308
|
+
yarn: {
|
|
309
|
+
lockfile: "yarn.lock",
|
|
310
|
+
install: "corepack enable && yarn install --immutable",
|
|
311
|
+
production: "yarn workspaces focus --production",
|
|
312
|
+
build: "yarn run build",
|
|
313
|
+
cache: "/root/.yarn/berry/cache"
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
var DOCKERIGNORE = `node_modules
|
|
317
|
+
.next
|
|
318
|
+
.nuxt
|
|
319
|
+
.output
|
|
320
|
+
dist
|
|
321
|
+
build
|
|
322
|
+
.svelte-kit
|
|
323
|
+
.astro
|
|
324
|
+
.git
|
|
325
|
+
.env*
|
|
326
|
+
!.env.example
|
|
327
|
+
coverage
|
|
328
|
+
*.log
|
|
329
|
+
`;
|
|
330
|
+
var NEXT_DOCKERIGNORE = DOCKERIGNORE;
|
|
331
|
+
function detectPackageManager(projectDir = ".") {
|
|
332
|
+
const matches = Object.entries(packageManagers).filter(([, value]) => existsSync(join(projectDir, value.lockfile)));
|
|
333
|
+
if (matches.length !== 1) {
|
|
334
|
+
throw new Error(matches.length === 0 ? `No supported lockfile found in ${projectDir}` : `Multiple lockfiles found in ${projectDir}: ${matches.map(([, value]) => value.lockfile).join(", ")}`);
|
|
335
|
+
}
|
|
336
|
+
return matches[0][0];
|
|
337
|
+
}
|
|
338
|
+
function inferPackageManager(installCommand) {
|
|
339
|
+
if (!installCommand)
|
|
340
|
+
return detectPackageManager();
|
|
341
|
+
const command = installCommand.trim();
|
|
342
|
+
if (/^(?:corepack enable && )?pnpm\b/.test(command))
|
|
343
|
+
return "pnpm";
|
|
344
|
+
if (/^(?:corepack enable && )?yarn\b/.test(command))
|
|
345
|
+
return "yarn";
|
|
346
|
+
if (/^npm\b/.test(command))
|
|
347
|
+
return "npm";
|
|
348
|
+
if (/^bun\b/.test(command))
|
|
349
|
+
return "bun";
|
|
350
|
+
return detectPackageManager();
|
|
351
|
+
}
|
|
352
|
+
function inferRuntime(framework, command) {
|
|
353
|
+
if (framework === "bun")
|
|
354
|
+
return "bun";
|
|
355
|
+
if (framework === "deno")
|
|
356
|
+
return "deno";
|
|
357
|
+
if (command && /^(?:\[\s*"bun"|bun\b)/.test(command.trim()))
|
|
358
|
+
return "bun";
|
|
359
|
+
return FRAMEWORK_DEFAULTS[framework].defaultRuntime;
|
|
360
|
+
}
|
|
361
|
+
function isJavaScriptFramework(framework) {
|
|
362
|
+
const kind = FRAMEWORK_DEFAULTS[framework].deployment?.kind;
|
|
363
|
+
return kind === "js-artifact" || kind === "js-source";
|
|
364
|
+
}
|
|
365
|
+
function applyParams(dockerfile, params, defaultOutput) {
|
|
366
|
+
let result = dockerfile;
|
|
367
|
+
if (params.outputDir && defaultOutput) {
|
|
368
|
+
if (/[\r\n]/.test(params.outputDir) || params.outputDir.includes("..")) {
|
|
369
|
+
throw new Error(`Invalid output directory: ${params.outputDir}`);
|
|
370
|
+
}
|
|
371
|
+
const output = `/app/${params.outputDir.replace(/^\.\//, "").replace(/\/$/, "")}`;
|
|
372
|
+
result = result.replaceAll(defaultOutput, output);
|
|
373
|
+
}
|
|
374
|
+
const buildInstructions = [
|
|
375
|
+
params.installCMD && `RUN ${singleLine(params.installCMD, "install command")}`,
|
|
376
|
+
...(params.buildCMD ?? []).map((command) => `RUN ${singleLine(command, "build command")}`)
|
|
377
|
+
].filter(Boolean).join(`
|
|
378
|
+
`);
|
|
379
|
+
if (buildInstructions)
|
|
380
|
+
result = insertBeforeRuntime(result, buildInstructions);
|
|
381
|
+
const environment = Object.entries(params.envVars).map(([key, value]) => {
|
|
382
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
383
|
+
throw new Error(`Invalid environment variable name: ${key}`);
|
|
384
|
+
}
|
|
385
|
+
return `ENV ${key}=${JSON.stringify(value)}`;
|
|
386
|
+
}).join(`
|
|
387
|
+
`);
|
|
388
|
+
if (environment)
|
|
389
|
+
result = insertBeforeFinalUser(result, environment);
|
|
390
|
+
if (params.runCMD) {
|
|
391
|
+
result = insertBeforeFinalCommand(result, `RUN ${singleLine(params.runCMD, "run command")}`);
|
|
392
|
+
}
|
|
393
|
+
if (params.cmd) {
|
|
394
|
+
result = result.replace(/CMD [^\n]+(?=\n?$)/, `CMD ${singleLine(params.cmd, "CMD")}`);
|
|
395
|
+
}
|
|
396
|
+
return result;
|
|
397
|
+
}
|
|
398
|
+
function insertBeforeRuntime(dockerfile, instructions) {
|
|
399
|
+
const firstStage = dockerfile.indexOf(`
|
|
400
|
+
FROM `);
|
|
401
|
+
const runtime = dockerfile.lastIndexOf(`
|
|
402
|
+
FROM `);
|
|
403
|
+
if (runtime !== -1 && runtime !== firstStage) {
|
|
404
|
+
return `${dockerfile.slice(0, runtime)}
|
|
405
|
+
${instructions}
|
|
406
|
+
${dockerfile.slice(runtime)}`;
|
|
407
|
+
}
|
|
408
|
+
return insertBeforeFinalUser(dockerfile, instructions);
|
|
409
|
+
}
|
|
410
|
+
function insertBeforeFinalUser(dockerfile, instructions) {
|
|
411
|
+
const user = dockerfile.lastIndexOf(`
|
|
412
|
+
USER `);
|
|
413
|
+
if (user !== -1) {
|
|
414
|
+
return `${dockerfile.slice(0, user)}
|
|
415
|
+
${instructions}${dockerfile.slice(user)}`;
|
|
416
|
+
}
|
|
417
|
+
return insertBeforeFinalCommand(dockerfile, instructions);
|
|
418
|
+
}
|
|
419
|
+
function insertBeforeFinalCommand(dockerfile, instructions) {
|
|
420
|
+
const command = dockerfile.lastIndexOf(`
|
|
421
|
+
CMD `);
|
|
422
|
+
if (command === -1)
|
|
423
|
+
return `${dockerfile.trimEnd()}
|
|
424
|
+
${instructions}
|
|
425
|
+
`;
|
|
426
|
+
return `${dockerfile.slice(0, command)}
|
|
427
|
+
${instructions}${dockerfile.slice(command)}`;
|
|
428
|
+
}
|
|
429
|
+
function singleLine(value, label) {
|
|
430
|
+
if (!value.trim() || /[\r\n]/.test(value))
|
|
431
|
+
throw new Error(`Invalid ${label}`);
|
|
432
|
+
return value.trim();
|
|
433
|
+
}
|
|
434
|
+
function generateDockerfile(params) {
|
|
435
|
+
const framework = Object.keys(FRAMEWORK_DEFAULTS).find((candidate) => candidate.toLowerCase() === params.framework.toLowerCase());
|
|
436
|
+
if (!framework)
|
|
437
|
+
throw new Error(`Unsupported framework: ${params.framework}`);
|
|
438
|
+
const runtime = inferRuntime(framework, params.cmd);
|
|
439
|
+
const packageManager = inferPackageManager(params.installCMD);
|
|
440
|
+
const version = params.version || FRAMEWORK_DEFAULTS[framework].defaultVersion;
|
|
441
|
+
const bunVersion = runtime === "bun" || framework === "bun" ? version : defaultVersionFor("bun");
|
|
442
|
+
const composerVersion = "2.10.2";
|
|
443
|
+
const denoVersion = framework === "deno" ? version : defaultVersionFor("deno");
|
|
444
|
+
const dotnetVersion = framework === "csharp" || framework === "aspnet" ? version : FRAMEWORK_DEFAULTS.csharp.defaultVersion;
|
|
445
|
+
const goVersion = ["go", "gin", "echo"].includes(framework) ? version : FRAMEWORK_DEFAULTS.go.defaultVersion;
|
|
446
|
+
const javaVersion = ["java", "springBoot", "quarkus"].includes(framework) ? version : FRAMEWORK_DEFAULTS.java.defaultVersion;
|
|
447
|
+
const mavenVersion = "3.9.16-eclipse-temurin-25-noble";
|
|
448
|
+
const nodeVersion = isJavaScriptFramework(framework) && runtime === "node" ? version : defaultVersionFor("node");
|
|
449
|
+
const phpVersion = ["php", "laravel", "symfony"].includes(framework) ? version : FRAMEWORK_DEFAULTS.php.defaultVersion;
|
|
450
|
+
const pythonVersion = ["django", "flask", "fastapi", "python"].includes(framework) ? version : FRAMEWORK_DEFAULTS.python.defaultVersion;
|
|
451
|
+
const rubyVersion = ["ruby", "rails"].includes(framework) ? version : FRAMEWORK_DEFAULTS.ruby.defaultVersion;
|
|
452
|
+
const rustVersion = ["rust", "actix", "rocket"].includes(framework) ? version : FRAMEWORK_DEFAULTS.rust.defaultVersion;
|
|
453
|
+
const finish = (dockerfile, outputDir) => applyParams(dockerfile, params, outputDir);
|
|
454
|
+
validateImageTag(bunVersion);
|
|
455
|
+
validateImageTag(composerVersion);
|
|
456
|
+
validateImageTag(denoVersion);
|
|
457
|
+
validateImageTag(dotnetVersion);
|
|
458
|
+
validateImageTag(goVersion);
|
|
459
|
+
validateImageTag(javaVersion);
|
|
460
|
+
validateImageTag(mavenVersion);
|
|
461
|
+
validateImageTag(nodeVersion);
|
|
462
|
+
validateImageTag(phpVersion);
|
|
463
|
+
validateImageTag(pythonVersion);
|
|
464
|
+
validateImageTag(rubyVersion);
|
|
465
|
+
validateImageTag(rustVersion);
|
|
466
|
+
const deployment = FRAMEWORK_DEFAULTS[framework].deployment;
|
|
467
|
+
if (!deployment)
|
|
468
|
+
throw new Error(`Unsupported framework: ${framework}`);
|
|
469
|
+
if (deployment.kind === "deno-source") {
|
|
470
|
+
return finish(generateDenoDockerfile(deployment.entrypoint, denoVersion));
|
|
471
|
+
}
|
|
472
|
+
if (deployment.kind === "bun-source") {
|
|
473
|
+
return finish(generateBunSourceDockerfile(deployment.entrypoint, bunVersion));
|
|
474
|
+
}
|
|
475
|
+
if (deployment.kind === "python") {
|
|
476
|
+
return finish(generatePythonDockerfile(pythonVersion, FRAMEWORK_DEFAULTS[framework].defaultPort, deployment.command));
|
|
477
|
+
}
|
|
478
|
+
if (deployment.kind === "go") {
|
|
479
|
+
return finish(generateGoDockerfile(FRAMEWORK_DEFAULTS[framework].defaultPort, goVersion));
|
|
480
|
+
}
|
|
481
|
+
if (deployment.kind === "rust") {
|
|
482
|
+
return finish(generateRustDockerfile(FRAMEWORK_DEFAULTS[framework].defaultPort, rustVersion));
|
|
483
|
+
}
|
|
484
|
+
if (deployment.kind === "java") {
|
|
485
|
+
return finish(generateJavaDockerfile(deployment.mode, FRAMEWORK_DEFAULTS[framework].defaultPort, javaVersion, mavenVersion));
|
|
486
|
+
}
|
|
487
|
+
if (deployment.kind === "ruby") {
|
|
488
|
+
return finish(generateRubyDockerfile(rubyVersion, FRAMEWORK_DEFAULTS[framework].defaultPort, deployment.command));
|
|
489
|
+
}
|
|
490
|
+
if (deployment.kind === "php") {
|
|
491
|
+
return finish(generatePhpDockerfile(phpVersion, composerVersion));
|
|
492
|
+
}
|
|
493
|
+
if (deployment.kind === "dotnet") {
|
|
494
|
+
return finish(generateDotnetDockerfile(deployment.aspnet, deployment.dll, dotnetVersion));
|
|
495
|
+
}
|
|
496
|
+
if (deployment.kind === "custom") {
|
|
497
|
+
return generateParamDockerfile(params);
|
|
498
|
+
}
|
|
499
|
+
if (deployment.kind === "js-source") {
|
|
500
|
+
return finish(generateJavaScriptSourceDockerfile({
|
|
501
|
+
build: deployment.build,
|
|
502
|
+
bunVersion,
|
|
503
|
+
entrypoint: deployment.entrypoint,
|
|
504
|
+
nodeVersion,
|
|
505
|
+
packageManager,
|
|
506
|
+
runtime
|
|
507
|
+
}));
|
|
508
|
+
}
|
|
509
|
+
const manager = packageManager;
|
|
510
|
+
const commands = packageManagers[manager];
|
|
511
|
+
const target = getJavaScriptDeployment(framework);
|
|
512
|
+
if (!commands)
|
|
513
|
+
throw new Error(`Unsupported package manager: ${manager}`);
|
|
514
|
+
if (!target)
|
|
515
|
+
throw new Error(`Unsupported framework: ${framework}`);
|
|
516
|
+
if (runtime !== "bun" && runtime !== "node") {
|
|
517
|
+
throw new Error(`Unsupported runtime: ${runtime}`);
|
|
518
|
+
}
|
|
519
|
+
const buildImage = manager === "bun" ? `oven/bun:${bunVersion}` : `node:${nodeVersion}`;
|
|
520
|
+
const runtimeImage = runtime === "bun" ? `oven/bun:${bunVersion}` : `node:${nodeVersion}`;
|
|
521
|
+
const user = runtime === "bun" ? "bun" : "node";
|
|
522
|
+
const buildEnvironment = framework === "nuxt" ? `ENV NITRO_PRESET=${runtime === "bun" ? "bun" : "node-server"}
|
|
523
|
+
` : "";
|
|
524
|
+
const prepareBuild = framework === "next" ? "mkdir -p public && " : "";
|
|
525
|
+
const buildCache = framework === "next" ? "--mount=type=cache,target=/app/.next/cache " : "";
|
|
526
|
+
const productionDependencies = target.selfContained ? "" : `
|
|
527
|
+
FROM dependencies AS production-dependencies
|
|
528
|
+
RUN ${commands.production}
|
|
529
|
+
`;
|
|
530
|
+
const prepareRuntime = framework === "next" ? `RUN mkdir .next && chown ${user}:${user} .next
|
|
531
|
+
` : "";
|
|
532
|
+
const copyDependencies = target.selfContained ? "" : `COPY --from=production-dependencies --chown=${user}:${user} /app/node_modules ./node_modules
|
|
533
|
+
COPY --from=production-dependencies --chown=${user}:${user} /app/package.json ./package.json
|
|
534
|
+
`;
|
|
535
|
+
const copies = target.copies.map(([source, destination]) => `COPY --from=build --chown=${user}:${user} ${source} ${destination}`).join(`
|
|
536
|
+
`);
|
|
537
|
+
const command = [runtime, target.entrypoint, target.entrypointArgument].filter(Boolean).map((part) => JSON.stringify(part)).join(", ");
|
|
538
|
+
return finish(`# syntax=docker/dockerfile:1
|
|
539
|
+
|
|
540
|
+
ARG BUILD_IMAGE=${buildImage}
|
|
541
|
+
ARG RUNTIME_IMAGE=${runtimeImage}
|
|
542
|
+
|
|
543
|
+
FROM \${BUILD_IMAGE} AS dependencies
|
|
544
|
+
WORKDIR /app
|
|
545
|
+
COPY package.json ${commands.lockfile} ./
|
|
546
|
+
RUN --mount=type=cache,target=${commands.cache} ${commands.install}
|
|
547
|
+
${productionDependencies}
|
|
548
|
+
FROM dependencies AS build
|
|
549
|
+
WORKDIR /app
|
|
550
|
+
COPY . .
|
|
551
|
+
ENV NEXT_TELEMETRY_DISABLED=1
|
|
552
|
+
${buildEnvironment}RUN ${buildCache}${prepareBuild}${commands.build}
|
|
553
|
+
|
|
554
|
+
FROM \${RUNTIME_IMAGE} AS runtime
|
|
555
|
+
WORKDIR /app
|
|
556
|
+
ENV NODE_ENV=production \\
|
|
557
|
+
NEXT_TELEMETRY_DISABLED=1 \\
|
|
558
|
+
HOST=0.0.0.0 \\
|
|
559
|
+
HOSTNAME=0.0.0.0 \\
|
|
560
|
+
PORT=3000
|
|
561
|
+
${prepareRuntime}${copyDependencies}${copies}
|
|
562
|
+
USER ${user}
|
|
563
|
+
EXPOSE 3000
|
|
564
|
+
CMD [${command}]
|
|
565
|
+
`, (target.copies.find(([, destination]) => destination === "./") ?? target.copies[0])?.[0]);
|
|
566
|
+
}
|
|
567
|
+
function generateJavaScriptSourceDockerfile({
|
|
568
|
+
build,
|
|
569
|
+
bunVersion,
|
|
570
|
+
entrypoint,
|
|
571
|
+
nodeVersion,
|
|
572
|
+
packageManager,
|
|
573
|
+
runtime
|
|
574
|
+
}) {
|
|
575
|
+
if (runtime !== "bun" && runtime !== "node") {
|
|
576
|
+
throw new Error(`Unsupported runtime for JavaScript server: ${runtime}`);
|
|
577
|
+
}
|
|
578
|
+
const commands = packageManagers[packageManager];
|
|
579
|
+
const buildImage = packageManager === "bun" ? `oven/bun:${bunVersion}` : `node:${nodeVersion}`;
|
|
580
|
+
const runtimeImage = runtime === "bun" ? `oven/bun:${bunVersion}` : `node:${nodeVersion}`;
|
|
581
|
+
const user = runtime;
|
|
582
|
+
const buildStage = build ? `
|
|
583
|
+
FROM dependencies AS build
|
|
584
|
+
COPY . .
|
|
585
|
+
RUN ${commands.build}
|
|
586
|
+
` : "";
|
|
587
|
+
const sourceCopy = build ? `COPY --from=build --chown=${user}:${user} /app/dist ./dist
|
|
588
|
+
COPY --from=build --chown=${user}:${user} /app/public ./public` : `COPY --chown=${user}:${user} . .`;
|
|
589
|
+
return `# syntax=docker/dockerfile:1
|
|
590
|
+
|
|
591
|
+
FROM ${buildImage} AS dependencies
|
|
592
|
+
WORKDIR /app
|
|
593
|
+
COPY package.json ${commands.lockfile} ./
|
|
594
|
+
RUN --mount=type=cache,target=${commands.cache} ${commands.install}
|
|
595
|
+
|
|
596
|
+
FROM dependencies AS production-dependencies
|
|
597
|
+
RUN ${commands.production}
|
|
598
|
+
${buildStage}
|
|
599
|
+
FROM ${runtimeImage} AS runtime
|
|
600
|
+
WORKDIR /app
|
|
601
|
+
ENV NODE_ENV=production HOST=0.0.0.0 PORT=3000
|
|
602
|
+
COPY --from=production-dependencies --chown=${user}:${user} /app/node_modules ./node_modules
|
|
603
|
+
COPY --from=production-dependencies --chown=${user}:${user} /app/package.json ./package.json
|
|
604
|
+
${sourceCopy}
|
|
605
|
+
USER ${user}
|
|
606
|
+
EXPOSE 3000
|
|
607
|
+
CMD [${JSON.stringify(runtime)}, ${JSON.stringify(entrypoint)}]
|
|
608
|
+
`;
|
|
609
|
+
}
|
|
610
|
+
function generateDenoDockerfile(entrypoint, version) {
|
|
611
|
+
return `# syntax=docker/dockerfile:1
|
|
612
|
+
|
|
613
|
+
FROM denoland/deno:${version} AS dependencies
|
|
614
|
+
WORKDIR /app
|
|
615
|
+
COPY deno.json ./
|
|
616
|
+
COPY ${entrypoint} ./
|
|
617
|
+
RUN deno cache ${entrypoint}
|
|
618
|
+
|
|
619
|
+
FROM denoland/deno:${version} AS runtime
|
|
620
|
+
WORKDIR /app
|
|
621
|
+
ENV HOST=0.0.0.0 PORT=8000
|
|
622
|
+
COPY --from=dependencies --chown=deno:deno /deno-dir /deno-dir
|
|
623
|
+
COPY --chown=deno:deno . .
|
|
624
|
+
USER deno
|
|
625
|
+
EXPOSE 8000
|
|
626
|
+
CMD ["run", "--allow-net", "--allow-read", "--allow-env", "${entrypoint}"]
|
|
627
|
+
`;
|
|
628
|
+
}
|
|
629
|
+
function generateBunSourceDockerfile(entrypoint, bunVersion) {
|
|
630
|
+
return `# syntax=docker/dockerfile:1
|
|
631
|
+
|
|
632
|
+
FROM oven/bun:${bunVersion} AS dependencies
|
|
633
|
+
WORKDIR /app
|
|
634
|
+
COPY package.json bun.lock ./
|
|
635
|
+
RUN --mount=type=cache,target=/root/.bun/install/cache bun install --frozen-lockfile --production
|
|
636
|
+
|
|
637
|
+
FROM oven/bun:${bunVersion} AS runtime
|
|
638
|
+
WORKDIR /app
|
|
639
|
+
ENV NODE_ENV=production HOST=0.0.0.0 PORT=3000
|
|
640
|
+
COPY --from=dependencies --chown=bun:bun /app/node_modules ./node_modules
|
|
641
|
+
COPY --chown=bun:bun . .
|
|
642
|
+
USER bun
|
|
643
|
+
EXPOSE 3000
|
|
644
|
+
CMD ["bun", "${entrypoint}"]
|
|
645
|
+
`;
|
|
646
|
+
}
|
|
647
|
+
function generatePythonDockerfile(version, port, command) {
|
|
648
|
+
return `# syntax=docker/dockerfile:1
|
|
649
|
+
|
|
650
|
+
FROM python:${version} AS dependencies
|
|
651
|
+
WORKDIR /app
|
|
652
|
+
COPY requirements.txt ./
|
|
653
|
+
RUN --mount=type=cache,target=/root/.cache/pip pip install --prefix=/install -r requirements.txt
|
|
654
|
+
|
|
655
|
+
FROM python:${version} AS runtime
|
|
656
|
+
WORKDIR /app
|
|
657
|
+
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 PORT=${port}
|
|
658
|
+
RUN useradd --create-home --uid 10001 app
|
|
659
|
+
COPY --from=dependencies /install /usr/local
|
|
660
|
+
COPY --chown=app:app . .
|
|
661
|
+
USER app
|
|
662
|
+
EXPOSE ${port}
|
|
663
|
+
CMD [${command.map((part) => JSON.stringify(part)).join(", ")}]
|
|
664
|
+
`;
|
|
665
|
+
}
|
|
666
|
+
function generateGoDockerfile(port, version) {
|
|
667
|
+
return `# syntax=docker/dockerfile:1
|
|
668
|
+
|
|
669
|
+
FROM golang:${version} AS build
|
|
670
|
+
WORKDIR /app
|
|
671
|
+
COPY go.mod go.sum* ./
|
|
672
|
+
RUN --mount=type=cache,target=/go/pkg/mod go mod download
|
|
673
|
+
COPY . .
|
|
674
|
+
RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/app .
|
|
675
|
+
|
|
676
|
+
FROM debian:13.5-slim AS runtime
|
|
677
|
+
WORKDIR /app
|
|
678
|
+
ENV PORT=${port}
|
|
679
|
+
COPY --from=build --chown=10001:10001 /out/app /app/app
|
|
680
|
+
USER 10001:10001
|
|
681
|
+
EXPOSE ${port}
|
|
682
|
+
CMD ["/app/app"]
|
|
683
|
+
`;
|
|
684
|
+
}
|
|
685
|
+
function generateRustDockerfile(port, version) {
|
|
686
|
+
return `# syntax=docker/dockerfile:1
|
|
687
|
+
|
|
688
|
+
FROM rust:${version} AS build
|
|
689
|
+
WORKDIR /app
|
|
690
|
+
COPY Cargo.toml Cargo.lock ./
|
|
691
|
+
COPY src ./src
|
|
692
|
+
RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=/app/target cargo build --locked --release && cp target/release/app /tmp/app
|
|
693
|
+
|
|
694
|
+
FROM debian:13.5-slim AS runtime
|
|
695
|
+
WORKDIR /app
|
|
696
|
+
ENV PORT=${port} ROCKET_ADDRESS=0.0.0.0 ROCKET_PORT=${port}
|
|
697
|
+
COPY --from=build --chown=10001:10001 /tmp/app /app/app
|
|
698
|
+
USER 10001:10001
|
|
699
|
+
EXPOSE ${port}
|
|
700
|
+
CMD ["/app/app"]
|
|
701
|
+
`;
|
|
702
|
+
}
|
|
703
|
+
function generateJavaDockerfile(mode, port, version, mavenVersion) {
|
|
704
|
+
const jdkVersion = version.replace("-jre-", "-jdk-");
|
|
705
|
+
if (mode === "class") {
|
|
706
|
+
return `# syntax=docker/dockerfile:1
|
|
707
|
+
|
|
708
|
+
FROM eclipse-temurin:${jdkVersion} AS build
|
|
709
|
+
WORKDIR /app
|
|
710
|
+
COPY Main.java ./
|
|
711
|
+
RUN javac Main.java
|
|
712
|
+
|
|
713
|
+
FROM eclipse-temurin:${version} AS runtime
|
|
714
|
+
WORKDIR /app
|
|
715
|
+
ENV PORT=${port}
|
|
716
|
+
COPY --from=build --chown=10001:10001 /app/Main.class ./
|
|
717
|
+
USER 10001:10001
|
|
718
|
+
EXPOSE ${port}
|
|
719
|
+
CMD ["java", "Main"]
|
|
720
|
+
`;
|
|
721
|
+
}
|
|
722
|
+
const copy = mode === "jar" ? "COPY --from=build --chown=10001:10001 /app/target/app.jar /app/app.jar" : "COPY --from=build --chown=10001:10001 /app/target/quarkus-app /app/quarkus-app";
|
|
723
|
+
const command = mode === "jar" ? '["java", "-jar", "/app/app.jar"]' : '["java", "-jar", "/app/quarkus-app/quarkus-run.jar"]';
|
|
724
|
+
return `# syntax=docker/dockerfile:1
|
|
725
|
+
|
|
726
|
+
FROM maven:${mavenVersion} AS build
|
|
727
|
+
WORKDIR /app
|
|
728
|
+
COPY pom.xml ./
|
|
729
|
+
RUN --mount=type=cache,target=/root/.m2 mvn --batch-mode dependency:go-offline
|
|
730
|
+
COPY src ./src
|
|
731
|
+
RUN --mount=type=cache,target=/root/.m2 mvn --batch-mode package -DskipTests
|
|
732
|
+
|
|
733
|
+
FROM eclipse-temurin:${version} AS runtime
|
|
734
|
+
WORKDIR /app
|
|
735
|
+
ENV PORT=${port}
|
|
736
|
+
${copy}
|
|
737
|
+
USER 10001:10001
|
|
738
|
+
EXPOSE ${port}
|
|
739
|
+
CMD ${command}
|
|
740
|
+
`;
|
|
741
|
+
}
|
|
742
|
+
function generateRubyDockerfile(version, port, command) {
|
|
743
|
+
return `# syntax=docker/dockerfile:1
|
|
744
|
+
|
|
745
|
+
FROM ruby:${version} AS dependencies
|
|
746
|
+
WORKDIR /app
|
|
747
|
+
RUN apt-get update && apt-get install -y --no-install-recommends build-essential && rm -rf /var/lib/apt/lists/*
|
|
748
|
+
COPY Gemfile ./
|
|
749
|
+
RUN --mount=type=cache,target=/usr/local/bundle/cache bundle config set without development:test && bundle lock && bundle install
|
|
750
|
+
|
|
751
|
+
FROM ruby:${version} AS runtime
|
|
752
|
+
WORKDIR /app
|
|
753
|
+
ENV RAILS_ENV=production RACK_ENV=production PORT=${port}
|
|
754
|
+
RUN useradd --create-home --uid 10001 app
|
|
755
|
+
COPY --from=dependencies /usr/local/bundle /usr/local/bundle
|
|
756
|
+
COPY --chown=app:app . .
|
|
757
|
+
COPY --from=dependencies --chown=app:app /app/Gemfile.lock ./Gemfile.lock
|
|
758
|
+
RUN mkdir -p tmp/pids log storage && chown -R app:app tmp log storage
|
|
759
|
+
USER app
|
|
760
|
+
EXPOSE ${port}
|
|
761
|
+
CMD [${command.map((part) => JSON.stringify(part)).join(", ")}]
|
|
762
|
+
`;
|
|
763
|
+
}
|
|
764
|
+
function generatePhpDockerfile(version, composerVersion) {
|
|
765
|
+
return `# syntax=docker/dockerfile:1
|
|
766
|
+
|
|
767
|
+
FROM composer:${composerVersion} AS dependencies
|
|
768
|
+
WORKDIR /app
|
|
769
|
+
COPY composer.json ./
|
|
770
|
+
RUN --mount=type=cache,target=/tmp/cache COMPOSER_CACHE_DIR=/tmp/cache composer install --no-dev --no-interaction --classmap-authoritative
|
|
771
|
+
COPY . .
|
|
772
|
+
RUN composer dump-autoload --no-dev --classmap-authoritative
|
|
773
|
+
|
|
774
|
+
FROM php:${version} AS runtime
|
|
775
|
+
WORKDIR /app
|
|
776
|
+
ENV APACHE_DOCUMENT_ROOT=/app/public
|
|
777
|
+
RUN a2enmod rewrite && sed -ri 's!Listen 80!Listen 8080!; s!AllowOverride None!AllowOverride All!g' /etc/apache2/ports.conf /etc/apache2/apache2.conf && rm -rf /var/www/html && ln -s /app/public /var/www/html && mkdir -p /var/run/apache2 /var/lock/apache2 /var/log/apache2 && chown -R www-data:www-data /var/run/apache2 /var/lock/apache2 /var/log/apache2 /app
|
|
778
|
+
COPY --from=dependencies --chown=www-data:www-data /app /app
|
|
779
|
+
RUN mkdir -p storage/framework/cache storage/framework/sessions storage/framework/views bootstrap/cache && chown -R www-data:www-data storage bootstrap/cache
|
|
780
|
+
USER www-data
|
|
781
|
+
EXPOSE 8080
|
|
782
|
+
CMD ["apache2-foreground"]
|
|
783
|
+
`;
|
|
784
|
+
}
|
|
785
|
+
function generateDotnetDockerfile(aspnet, dll, version) {
|
|
786
|
+
const runtime = aspnet ? "aspnet" : "runtime";
|
|
787
|
+
return `# syntax=docker/dockerfile:1
|
|
788
|
+
|
|
789
|
+
FROM mcr.microsoft.com/dotnet/sdk:${version} AS build
|
|
790
|
+
WORKDIR /src
|
|
791
|
+
COPY *.csproj ./
|
|
792
|
+
RUN --mount=type=cache,target=/root/.nuget/packages dotnet restore
|
|
793
|
+
COPY . .
|
|
794
|
+
RUN --mount=type=cache,target=/root/.nuget/packages dotnet publish -c Release -o /out --no-restore
|
|
795
|
+
|
|
796
|
+
FROM mcr.microsoft.com/dotnet/${runtime}:${version} AS runtime
|
|
797
|
+
WORKDIR /app
|
|
798
|
+
ENV ASPNETCORE_HTTP_PORTS=8080 PORT=8080
|
|
799
|
+
COPY --from=build --chown=app:app /out ./
|
|
800
|
+
USER app
|
|
801
|
+
EXPOSE 8080
|
|
802
|
+
CMD ["dotnet", "${dll}"]
|
|
803
|
+
`;
|
|
804
|
+
}
|
|
805
|
+
function generateParamDockerfile(params) {
|
|
806
|
+
const image = params.version.includes(":") ? params.version : `node:${params.version}`;
|
|
807
|
+
validateImage(image);
|
|
808
|
+
const workdir = params.outputDir ? `/app/${params.outputDir.replace(/^\.\//, "").replace(/\/$/, "")}` : "/app";
|
|
809
|
+
return applyParams(`# syntax=docker/dockerfile:1
|
|
810
|
+
|
|
811
|
+
FROM ${image}
|
|
812
|
+
WORKDIR /app
|
|
813
|
+
COPY --chown=node:node . .
|
|
814
|
+
WORKDIR ${workdir}
|
|
815
|
+
USER node
|
|
816
|
+
CMD ["node", "server.js"]
|
|
817
|
+
`, { ...params, outputDir: null });
|
|
818
|
+
}
|
|
819
|
+
function validateImage(value) {
|
|
820
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9_./:-]*$/.test(value)) {
|
|
821
|
+
throw new Error(`Invalid container image: ${value}`);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
function validateImageTag(value) {
|
|
825
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(value)) {
|
|
826
|
+
throw new Error(`Invalid container image tag: ${value}`);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// src/lib/next-js/next-dockerfile-generator.ts
|
|
831
|
+
function generateNextDockerfile(options) {
|
|
832
|
+
return generateDockerfile({ ...options, framework: "next" });
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// src/index.ts
|
|
836
|
+
var detectPackageManager2 = detectPackageManager;
|
|
837
|
+
var DOCKERIGNORE2 = DOCKERIGNORE;
|
|
838
|
+
var FRAMEWORK_DEFAULTS2 = FRAMEWORK_DEFAULTS;
|
|
839
|
+
var generateDockerfile2 = generateDockerfile;
|
|
840
|
+
var generateNextDockerfile2 = generateNextDockerfile;
|
|
841
|
+
var NEXT_DOCKERIGNORE2 = NEXT_DOCKERIGNORE;
|
|
842
|
+
export {
|
|
843
|
+
generateNextDockerfile2 as generateNextDockerfile,
|
|
844
|
+
generateDockerfile2 as generateDockerfile,
|
|
845
|
+
detectPackageManager2 as detectPackageManager,
|
|
846
|
+
NEXT_DOCKERIGNORE2 as NEXT_DOCKERIGNORE,
|
|
847
|
+
FRAMEWORK_DEFAULTS2 as FRAMEWORK_DEFAULTS,
|
|
848
|
+
DOCKERIGNORE2 as DOCKERIGNORE
|
|
849
|
+
};
|