Skip to content

Commit 27fde67

Browse files
committed
Only fallback to require when import isn't available
1 parent e985e21 commit 27fde67

File tree

1 file changed

+90
-48
lines changed

1 file changed

+90
-48
lines changed

packages/php-wasm/node/src/lib/get-php-loader-module.ts

Lines changed: 90 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -10,81 +10,123 @@ import type { PHPLoaderModule, SupportedPHPVersion } from '@php-wasm/universal';
1010
* - @php-wasm/node-8-3
1111
* - etc.
1212
*
13-
* In CommonJS environments (like Jest), we use require() to avoid dynamic import issues.
14-
* In ESM environments, we use dynamic import().
13+
* ## Module Loading Strategy
14+
*
15+
* Uses a try-catch fallback approach:
16+
* 1. **Tries `import()` first** - Works in ESM, modern CJS (Node 12.20+), and test
17+
* runners like Vitest
18+
* 2. **Falls back to `require()`** - Only if import() fails (rare in modern
19+
* environments)
20+
*
21+
* ### Why This Approach?
22+
*
23+
* **Development**: In monorepo development, workspace symlinks point to source directories
24+
* without built files. Modern test runners (like Vitest) provide both `module` and `require`
25+
* but should use `import()` to work with these symlinks. The try-catch approach correctly
26+
* uses `import()` in these environments.
27+
*
28+
* **Production**: Published packages have built files in the correct locations, so both
29+
* `import()` (ESM consumers) and `require()` (old CJS consumers) work correctly.
30+
*
31+
* This avoids environment-specific detection hacks and is future-proof as environments evolve.
1532
*
1633
* @param version The PHP version to load.
1734
* @returns The PHP loader module.
1835
*/
1936
export async function getPHPLoaderModule(
2037
version: SupportedPHPVersion = LatestSupportedPHPVersion
2138
): Promise<PHPLoaderModule> {
22-
// CommonJS: require() avoids dynamic import() issues without --experimental-vm-modules
23-
if (
24-
typeof module !== 'undefined' &&
25-
typeof module.exports !== 'undefined'
26-
) {
39+
// Try dynamic import() first - the modern, preferred approach
40+
// Works in: ESM, Vitest, modern Node.js CJS (12.20+), and with workspace symlinks
41+
try {
2742
switch (version) {
2843
case '8.5':
2944
// @ts-ignore
30-
return require('@php-wasm/node-8-5').getPHPLoaderModule();
45+
return (
46+
await import('@php-wasm/node-8-5')
47+
).getPHPLoaderModule();
3148
case '8.4':
3249
// @ts-ignore
33-
return require('@php-wasm/node-8-4').getPHPLoaderModule();
50+
return (
51+
await import('@php-wasm/node-8-4')
52+
).getPHPLoaderModule();
3453
case '8.3':
3554
// @ts-ignore
36-
return require('@php-wasm/node-8-3').getPHPLoaderModule();
55+
return (
56+
await import('@php-wasm/node-8-3')
57+
).getPHPLoaderModule();
3758
case '8.2':
3859
// @ts-ignore
39-
return require('@php-wasm/node-8-2').getPHPLoaderModule();
60+
return (
61+
await import('@php-wasm/node-8-2')
62+
).getPHPLoaderModule();
4063
case '8.1':
4164
// @ts-ignore
42-
return require('@php-wasm/node-8-1').getPHPLoaderModule();
65+
return (
66+
await import('@php-wasm/node-8-1')
67+
).getPHPLoaderModule();
4368
case '8.0':
4469
// @ts-ignore
45-
return require('@php-wasm/node-8-0').getPHPLoaderModule();
70+
return (
71+
await import('@php-wasm/node-8-0')
72+
).getPHPLoaderModule();
4673
case '7.4':
4774
// @ts-ignore
48-
return require('@php-wasm/node-7-4').getPHPLoaderModule();
75+
return (
76+
await import('@php-wasm/node-7-4')
77+
).getPHPLoaderModule();
4978
case '7.3':
5079
// @ts-ignore
51-
return require('@php-wasm/node-7-3').getPHPLoaderModule();
80+
return (
81+
await import('@php-wasm/node-7-3')
82+
).getPHPLoaderModule();
5283
case '7.2':
5384
// @ts-ignore
54-
return require('@php-wasm/node-7-2').getPHPLoaderModule();
85+
return (
86+
await import('@php-wasm/node-7-2')
87+
).getPHPLoaderModule();
5588
}
5689
throw new Error(`Unsupported PHP version ${version}`);
90+
} catch (error) {
91+
// Fallback: Use require() only if import() failed
92+
// This handles extremely rare cases: old Node.js versions or restricted environments
93+
// where dynamic import() is not available
94+
if (
95+
typeof module !== 'undefined' &&
96+
typeof module.exports !== 'undefined' &&
97+
typeof require === 'function'
98+
) {
99+
switch (version) {
100+
case '8.5':
101+
// @ts-ignore
102+
return require('@php-wasm/node-8-5').getPHPLoaderModule();
103+
case '8.4':
104+
// @ts-ignore
105+
return require('@php-wasm/node-8-4').getPHPLoaderModule();
106+
case '8.3':
107+
// @ts-ignore
108+
return require('@php-wasm/node-8-3').getPHPLoaderModule();
109+
case '8.2':
110+
// @ts-ignore
111+
return require('@php-wasm/node-8-2').getPHPLoaderModule();
112+
case '8.1':
113+
// @ts-ignore
114+
return require('@php-wasm/node-8-1').getPHPLoaderModule();
115+
case '8.0':
116+
// @ts-ignore
117+
return require('@php-wasm/node-8-0').getPHPLoaderModule();
118+
case '7.4':
119+
// @ts-ignore
120+
return require('@php-wasm/node-7-4').getPHPLoaderModule();
121+
case '7.3':
122+
// @ts-ignore
123+
return require('@php-wasm/node-7-3').getPHPLoaderModule();
124+
case '7.2':
125+
// @ts-ignore
126+
return require('@php-wasm/node-7-2').getPHPLoaderModule();
127+
}
128+
}
129+
// Re-throw the original error if require() also isn't available
130+
throw error;
57131
}
58-
59-
// In ESM, use dynamic import
60-
switch (version) {
61-
case '8.5':
62-
// @ts-ignore
63-
return (await import('@php-wasm/node-8-5')).getPHPLoaderModule();
64-
case '8.4':
65-
// @ts-ignore
66-
return (await import('@php-wasm/node-8-4')).getPHPLoaderModule();
67-
case '8.3':
68-
// @ts-ignore
69-
return (await import('@php-wasm/node-8-3')).getPHPLoaderModule();
70-
case '8.2':
71-
// @ts-ignore
72-
return (await import('@php-wasm/node-8-2')).getPHPLoaderModule();
73-
case '8.1':
74-
// @ts-ignore
75-
return (await import('@php-wasm/node-8-1')).getPHPLoaderModule();
76-
case '8.0':
77-
// @ts-ignore
78-
return (await import('@php-wasm/node-8-0')).getPHPLoaderModule();
79-
case '7.4':
80-
// @ts-ignore
81-
return (await import('@php-wasm/node-7-4')).getPHPLoaderModule();
82-
case '7.3':
83-
// @ts-ignore
84-
return (await import('@php-wasm/node-7-3')).getPHPLoaderModule();
85-
case '7.2':
86-
// @ts-ignore
87-
return (await import('@php-wasm/node-7-2')).getPHPLoaderModule();
88-
}
89-
throw new Error(`Unsupported PHP version ${version}`);
90132
}

0 commit comments

Comments
 (0)