@@ -10,13 +10,15 @@ import { traverse, builders as b, is } from 'estree-toolkit';
1010import { parseModule } from 'meriyah' ;
1111
1212import { transmogrify } from '../transmogrify' ;
13+ import { ImportManager } from '../imports' ;
1314import { replaceLwcImport } from './lwc-import' ;
1415import { catalogTmplImport } from './catalog-tmpls' ;
1516import { catalogStaticStylesheets , catalogAndReplaceStyleImports } from './stylesheets' ;
1617import { addGenerateMarkupFunction } from './generate-markup' ;
1718import { catalogWireAdapters } from './wire' ;
1819
1920import { removeDecoratorImport } from './remove-decorator-import' ;
21+ import type { ComponentTransformOptions } from '../shared' ;
2022import type { Identifier as EsIdentifier , Program as EsProgram } from 'estree' ;
2123import type { Visitors , ComponentMetaState } from './types' ;
2224import type { CompilationMode } from '@lwc/shared' ;
@@ -33,13 +35,28 @@ const visitors: Visitors = {
3335 catalogAndReplaceStyleImports ( path , state ) ;
3436 removeDecoratorImport ( path ) ;
3537 } ,
36- ImportExpression ( path ) {
37- return path . replaceWith (
38- b . callExpression (
39- b . memberExpression ( b . identifier ( 'Promise' ) , b . identifier ( 'resolve' ) ) ,
40- [ ]
41- )
42- ) ;
38+ ImportExpression ( path , state ) {
39+ const { experimentalDynamicComponent, importManager } = state ;
40+ if ( ! experimentalDynamicComponent ) {
41+ // if no `experimentalDynamicComponent` config, then leave dynamic `import()`s as-is
42+ return ;
43+ }
44+ if ( experimentalDynamicComponent . strictSpecifier ) {
45+ if ( ! is . literal ( path . node ?. source ) || typeof path . node . source . value !== 'string' ) {
46+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
47+ throw new Error ( 'todo - LWCClassErrors.INVALID_DYNAMIC_IMPORT_SOURCE_STRICT' ) ;
48+ }
49+ }
50+ const loader = experimentalDynamicComponent . loader ;
51+ if ( ! loader ) {
52+ // if no `loader` defined, then leave dynamic `import()`s as-is
53+ return ;
54+ }
55+ const source = path . node ! . source ! ;
56+ // 1. insert `import { load as __load } from '${loader}'` at top of program
57+ importManager . add ( { load : '__load' } , loader ) ;
58+ // 2. replace this import with `__load(${source})`
59+ path . replaceWith ( b . callExpression ( b . identifier ( '__load' ) , [ structuredClone ( source ) ] ) ) ;
4360 } ,
4461 ClassDeclaration ( path , state ) {
4562 const { node } = path ;
@@ -171,12 +188,22 @@ const visitors: Visitors = {
171188 path . parentPath . node . arguments = [ b . identifier ( 'propsAvailableAtConstruction' ) ] ;
172189 }
173190 } ,
191+ Program : {
192+ leave ( path , state ) {
193+ // After parsing the whole tree, insert needed imports
194+ const importDeclarations = state . importManager . getImportDeclarations ( ) ;
195+ if ( importDeclarations . length > 0 ) {
196+ path . node ?. body . unshift ( ...importDeclarations ) ;
197+ }
198+ } ,
199+ } ,
174200} ;
175201
176202export default function compileJS (
177203 src : string ,
178204 filename : string ,
179205 tagName : string ,
206+ options : ComponentTransformOptions ,
180207 compilationMode : CompilationMode
181208) {
182209 let ast = parseModule ( src , {
@@ -200,6 +227,8 @@ export default function compileJS(
200227 publicFields : [ ] ,
201228 privateFields : [ ] ,
202229 wireAdapters : [ ] ,
230+ experimentalDynamicComponent : options . experimentalDynamicComponent ,
231+ importManager : new ImportManager ( ) ,
203232 } ;
204233
205234 traverse ( ast , visitors , state ) ;
0 commit comments