Post-process adapter-node output into a single self-contained build/bundle.mjs (614 KB) via esbuild, then ship it on a fresh alpine:3.21 base with just the node binary copied in. Drops the node_modules + package manager baggage that comes with node:25-alpine. - Add esbuild devDep + `bundle` script (scripts/bundle.mjs) - Dockerfile: drop `deps` stage; final stage is alpine + node binary + bundle + static client assets - Uncompressed image: 177 MB -> 149 MB (-16%) - Verified: /, /healthz, static assets all respond identically; outbound TLS to api.marktvogt.de works via node's built-in CA bundle
29 lines
1.0 KiB
JavaScript
29 lines
1.0 KiB
JavaScript
// Bundles the SvelteKit adapter-node output into a single self-contained
|
|
// file so the runtime image can ship without node_modules.
|
|
//
|
|
// Input: build/index.js (+ its static + dynamic imports from build/**)
|
|
// Output: build/bundle.mjs
|
|
//
|
|
// Dropping node_modules shrinks the image from ~130 MB to ~60 MB.
|
|
|
|
import { build } from 'esbuild';
|
|
|
|
await build({
|
|
entryPoints: ['build/index.js'],
|
|
bundle: true,
|
|
platform: 'node',
|
|
format: 'esm',
|
|
outfile: 'build/bundle.mjs',
|
|
// Keep node built-ins external; bundle everything else (including deps
|
|
// pulled in transitively by @sveltejs/kit, valibot, etc.).
|
|
external: ['node:*'],
|
|
// ESM output lacks the CommonJS `require` global; some transitive deps
|
|
// call it via interop helpers. This shim makes it available.
|
|
banner: {
|
|
js: "import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);"
|
|
},
|
|
// Dynamic imports in manifest.js reference hashed chunks by string
|
|
// literal — esbuild statically traces these, no splitting needed.
|
|
logLevel: 'info'
|
|
});
|