Skip to content

Commit 2ca34ac

Browse files
fix(sveltekit): production server crash from bundled TypeScript compiler (#2799)
* fix(sveltekit): patch server chunks with rollup-renamed __filename bindings The adapter-node chunk patch skipped any chunk matching /\b(const|let|var)\s+__(file|dir)name\b/ — but $ is not a regex word character, so rollup-renamed declarations like `__filename$1` (produced when adapter-node re-bundles the intermediate server output and our banner's declaration collides) satisfied the check. Chunks that declared only a renamed binding while a bundled CJS dependency referenced the bare `__filename` were skipped, and the production server crashed at boot (observed on main with the TypeScript compiler bundled via cosmiconfig through @workflow/world-postgres). Anchor both regexes with (?![\w$]) so renamed identifiers no longer match. Verified: the sveltekit workbench production server now boots and serves health checks (with and without a base path), and queue deliveries from start() succeed. Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com> * fix(sveltekit): keep the TypeScript compiler out of the server bundle Since the world-target injection change, the sveltekit workbench's hooks.server.ts imports @workflow/world-postgres, whose dependency chain (graphile-worker -> cosmiconfig) reaches cosmiconfig's TS-config loader. At runtime that loader's require('typescript') is lazy and never fires, but SvelteKit bundles the whole chain into the server and rollup's CJS conversion hoists it into an eager top-level evaluation — executing the entire TypeScript compiler at boot and crashing the server ("__filename is not defined" inside the bundled compiler). Alias 'typescript' to a stub module in the SvelteKit plugin, following the existing pg-native pattern. Server output shrinks from 36MB to 11MB and boots cleanly. Verified: sveltekit workbench production build boots, serves flow?__health (200), and start() runs execute with clean queue deliveries. The chunk-patch regex fix from the previous commit stays as hardening for any other CJS dependency that references __filename. Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com> * Update .changeset/fix-sveltekit-filename-chunk-patch.md Signed-off-by: Peter Wielander <mittgfu@gmail.com> --------- Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com> Signed-off-by: Peter Wielander <mittgfu@gmail.com> Co-authored-by: Peter Wielander <mittgfu@gmail.com>
1 parent 54f46f9 commit 2ca34ac

5 files changed

Lines changed: 35 additions & 2 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@workflow/sveltekit": patch
3+
"@workflow/builders": patch
4+
---
5+
6+
Fix SvelteKit production server crash at boot if a world package pulls cosmiconfig into the server bundle.

‎packages/builders/src/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export {
3333
} from './node-compat-banner.js';
3434
export { createNodeModuleErrorPlugin } from './node-module-esbuild-plugin.js';
3535
export { WORKFLOW_OPTIONAL_PG_NATIVE_ALIAS } from './optional-pg-native-alias.js';
36+
export { WORKFLOW_OPTIONAL_TYPESCRIPT_ALIAS } from './optional-typescript-alias.js';
3637
export {
3738
createPseudoPackagePlugin,
3839
PSEUDO_PACKAGES,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { fileURLToPath } from 'node:url';
2+
3+
export const WORKFLOW_OPTIONAL_TYPESCRIPT_ALIAS = fileURLToPath(
4+
new URL('./optional-typescript.js', import.meta.url)
5+
);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Stub aliased in place of the `typescript` package in framework server
2+
// bundles. It is only reachable through cosmiconfig's TS-config loader
3+
// (via world packages -> graphile-worker), where `require('typescript')`
4+
// is lazy and never fires at runtime — but bundling converts it into an
5+
// eager top-level evaluation, pulling the entire compiler into the server
6+
// output and executing it at boot.
7+
const typescript = {};
8+
9+
export default typescript;

‎packages/sveltekit/src/plugin.ts‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
WORKFLOW_NODE_COMPAT_BANNER,
88
WORKFLOW_NODE_FILENAME_BANNER,
99
WORKFLOW_OPTIONAL_PG_NATIVE_ALIAS,
10+
WORKFLOW_OPTIONAL_TYPESCRIPT_ALIAS,
1011
WORKFLOW_WORLD_TARGET_MODULE,
1112
} from '@workflow/builders';
1213
import { workflowTransformPlugin } from '@workflow/rollup';
@@ -48,6 +49,7 @@ export function workflowPlugin(options: WorkflowPluginOptions = {}): Plugin[] {
4849
alias: {
4950
[WORKFLOW_WORLD_TARGET_MODULE]: workflowTargetWorldAlias,
5051
'pg-native': WORKFLOW_OPTIONAL_PG_NATIVE_ALIAS,
52+
typescript: WORKFLOW_OPTIONAL_TYPESCRIPT_ALIAS,
5153
},
5254
},
5355
};
@@ -143,9 +145,19 @@ function patchAdapterNodeServerChunks(cwd: string): void {
143145
// that already declares either identifier (const/let/var, e.g. a
144146
// CJS-interop shim) would produce a duplicate top-level declaration
145147
// and crash the server with a SyntaxError at startup.
146-
const referencesFilename = /\b__(?:file|dir)name\b/.test(source);
148+
//
149+
// The `(?![\w$])` lookaheads matter: when adapter-node re-bundles the
150+
// intermediate output, rollup renames colliding declarations to e.g.
151+
// `__filename$1`. A bare `\b` boundary matches those ($ is not a word
152+
// character), which made this skip chunks that declare only a RENAMED
153+
// binding while still referencing the bare `__filename` (observed with
154+
// the bundled `typescript` compiler pulled in via cosmiconfig — the
155+
// server crashed at boot with "__filename is not defined").
156+
const referencesFilename = /(?<![\w$])__(?:file|dir)name(?![\w$])/.test(
157+
source
158+
);
147159
const declaresOwnBinding =
148-
/\b(?:const|let|var)\s+__(?:file|dir)name\b/.test(source);
160+
/\b(?:const|let|var)\s+__(?:file|dir)name(?![\w$])/.test(source);
149161
if (!referencesFilename || declaresOwnBinding) {
150162
continue;
151163
}

0 commit comments

Comments
 (0)