6
6
* found in the LICENSE file at https://angular.io/license
7
7
*/
8
8
9
+ import { existsSync } from 'fs' ;
9
10
import * as path from 'path' ;
11
+ import { URL , pathToFileURL } from 'url' ;
12
+ import { Compilation , Configuration } from 'webpack' ;
10
13
11
14
export interface EmittedFiles {
12
15
id ?: string ;
@@ -17,7 +20,7 @@ export interface EmittedFiles {
17
20
extension : string ;
18
21
}
19
22
20
- export function getEmittedFiles ( compilation : import ( 'webpack' ) . Compilation ) : EmittedFiles [ ] {
23
+ export function getEmittedFiles ( compilation : Compilation ) : EmittedFiles [ ] {
21
24
const files : EmittedFiles [ ] = [ ] ;
22
25
const chunkFileNames = new Set < string > ( ) ;
23
26
@@ -51,3 +54,51 @@ export function getEmittedFiles(compilation: import('webpack').Compilation): Emi
51
54
52
55
return files ;
53
56
}
57
+
58
+ /**
59
+ * This uses a dynamic import to load a module which may be ESM.
60
+ * CommonJS code can load ESM code via a dynamic import. Unfortunately, TypeScript
61
+ * will currently, unconditionally downlevel dynamic import into a require call.
62
+ * require calls cannot load ESM code and will result in a runtime error. To workaround
63
+ * this, a Function constructor is used to prevent TypeScript from changing the dynamic import.
64
+ * Once TypeScript provides support for keeping the dynamic import this workaround can
65
+ * be dropped.
66
+ *
67
+ * @param modulePath The path of the module to load.
68
+ * @returns A Promise that resolves to the dynamically imported module.
69
+ */
70
+ function loadEsmModule < T > ( modulePath : string | URL ) : Promise < T > {
71
+ return new Function ( 'modulePath' , `return import(modulePath);` ) ( modulePath ) as Promise < T > ;
72
+ }
73
+
74
+ export async function getWebpackConfig ( configPath : string ) : Promise < Configuration > {
75
+ if ( ! existsSync ( configPath ) ) {
76
+ throw new Error ( `Webpack configuration file ${ configPath } does not exist.` ) ;
77
+ }
78
+
79
+ switch ( path . extname ( configPath ) ) {
80
+ case '.mjs' :
81
+ // Load the ESM configuration file using the TypeScript dynamic import workaround.
82
+ // Once TypeScript provides support for keeping the dynamic import this workaround can be
83
+ // changed to a direct dynamic import.
84
+ return ( await loadEsmModule < { default : Configuration } > ( pathToFileURL ( configPath ) ) ) . default ;
85
+ case '.cjs' :
86
+ return require ( configPath ) ;
87
+ default :
88
+ // The file could be either CommonJS or ESM.
89
+ // CommonJS is tried first then ESM if loading fails.
90
+ try {
91
+ return require ( configPath ) ;
92
+ } catch ( e ) {
93
+ if ( e . code === 'ERR_REQUIRE_ESM' ) {
94
+ // Load the ESM configuration file using the TypeScript dynamic import workaround.
95
+ // Once TypeScript provides support for keeping the dynamic import this workaround can be
96
+ // changed to a direct dynamic import.
97
+ return ( await loadEsmModule < { default : Configuration } > ( pathToFileURL ( configPath ) ) )
98
+ . default ;
99
+ }
100
+
101
+ throw e ;
102
+ }
103
+ }
104
+ }
0 commit comments