@@ -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 */
1936export 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