@@ -14,7 +14,7 @@ import cssPlugin, { cssLoader } from '../plugins/css.ts'
14
14
import { ensureTextFile , existsDir , existsFile , lazyRemove } from '../shared/fs.ts'
15
15
import log , { Measure } from '../shared/log.ts'
16
16
import util from '../shared/util.ts'
17
- import type { Aleph as IAleph , DependencyDescriptor , ImportMap , LoadInput , LoadOutput , Module , HtmlDescriptor , RouterURL , ResolveResult , TransformOutput , SSRData , RenderOutput } from '../types.d.ts'
17
+ import type { Aleph as IAleph , DependencyDescriptor , ImportMap , LoadInput , LoadOutput , Module , RouterURL , ResolveResult , TransformInput , TransformOutput , SSRData , RenderOutput } from '../types.d.ts'
18
18
import { VERSION } from '../version.ts'
19
19
import { Analyzer } from './analyzer.ts'
20
20
import { cache } from './cache.ts'
@@ -38,6 +38,7 @@ type CompileOptions = {
38
38
forceRefresh ?: boolean ,
39
39
ignoreDeps ?: boolean ,
40
40
httpExternal ?: boolean
41
+ virtual ?: boolean
41
42
}
42
43
43
44
type ResolveListener = {
@@ -52,7 +53,7 @@ type LoadListener = {
52
53
53
54
type TransformListener = {
54
55
test : RegExp | 'hmr' | 'main' ,
55
- transform ( input : TransformOutput & { module : Module } ) : TransformOutput | void | Promise < TransformOutput > | Promise < void > ,
56
+ transform ( input : TransformInput ) : TransformOutput | void | Promise < TransformOutput | void > ,
56
57
}
57
58
58
59
type RenderListener = ( input : RenderOutput & { path : string } ) => void | Promise < void >
@@ -318,7 +319,7 @@ export class Aleph implements IAleph {
318
319
const module = await this . compile ( specifier , {
319
320
forceRefresh : true ,
320
321
ignoreDeps : true ,
321
- httpExternal : specifier . startsWith ( '/api/' )
322
+ httpExternal : prevModule . httpExternal
322
323
} )
323
324
const refreshPage = (
324
325
this . #config. ssr &&
@@ -526,7 +527,7 @@ export class Aleph implements IAleph {
526
527
}
527
528
528
529
/** add a module by given path and optional source code. */
529
- async addModule ( specifier : string , sourceCode : string ) : Promise < Module > {
530
+ async addModule ( specifier : string , sourceCode : string , forceRefresh ?: boolean ) : Promise < Module > {
530
531
let sourceType = getSourceType ( specifier )
531
532
if ( sourceType === SourceType . Unknown ) {
532
533
throw new Error ( "addModule: unknown souce type" )
@@ -535,7 +536,8 @@ export class Aleph implements IAleph {
535
536
source : {
536
537
code : sourceCode ,
537
538
type : sourceType ,
538
- }
539
+ } ,
540
+ forceRefresh,
539
541
} )
540
542
if ( specifier . startsWith ( 'pages/' ) || specifier . startsWith ( 'api/' ) ) {
541
543
specifier = '/' + specifier
@@ -707,8 +709,7 @@ export class Aleph implements IAleph {
707
709
specifier : '/main.js' ,
708
710
deps : [ ] ,
709
711
sourceHash : '' ,
710
- jsFile : '' ,
711
- ready : Promise . resolve ( )
712
+ jsFile : ''
712
713
} ,
713
714
code,
714
715
} )
@@ -775,7 +776,7 @@ export class Aleph implements IAleph {
775
776
]
776
777
}
777
778
778
- gteModuleHash ( module : Module ) {
779
+ computeModuleHash ( module : Module ) {
779
780
const hasher = createHash ( 'md5' ) . update ( module . sourceHash )
780
781
this . lookupDeps ( module . specifier , dep => {
781
782
const depMod = this . getModule ( dep . specifier )
@@ -939,7 +940,7 @@ export class Aleph implements IAleph {
939
940
940
941
async importModule < T = any > ( module : Module ) : Promise < T > {
941
942
const path = join ( this . #buildDir, module . jsFile )
942
- const hash = this . gteModuleHash ( module )
943
+ const hash = this . computeModuleHash ( module )
943
944
if ( existsFile ( path ) ) {
944
945
return await import ( `file://${ path } #${ ( hash ) . slice ( 0 , 6 ) } ` )
945
946
}
@@ -979,7 +980,8 @@ export class Aleph implements IAleph {
979
980
}
980
981
for ( const { test, transform } of this . #transformListeners) {
981
982
if ( test === 'hmr' ) {
982
- const ret = await transform ( { module : { ...module } , code } )
983
+ const { jsBuffer, ready, ...rest } = module
984
+ const ret = await transform ( { module : structuredClone ( rest ) , code } )
983
985
if ( util . isFilledString ( ret ?. code ) ) {
984
986
code = ret ! . code
985
987
}
@@ -1077,7 +1079,7 @@ export class Aleph implements IAleph {
1077
1079
/** init the module by given specifier, don't transpile the code when the returned `source` is equal to null */
1078
1080
private async initModule (
1079
1081
specifier : string ,
1080
- { source : customSource , forceRefresh, httpExternal } : CompileOptions = { }
1082
+ { source : customSource , forceRefresh, httpExternal, virtual } : CompileOptions = { }
1081
1083
) : Promise < [ Module , ModuleSource | null ] > {
1082
1084
let external = false
1083
1085
let data : any = null
@@ -1148,7 +1150,7 @@ export class Aleph implements IAleph {
1148
1150
this . #appModule = mod
1149
1151
}
1150
1152
1151
- if ( await existsFile ( metaFp ) ) {
1153
+ if ( ! forceRefresh && await existsFile ( metaFp ) ) {
1152
1154
try {
1153
1155
const { specifier : _specifier , sourceHash, deps, isStyle, ssrPropsFn, ssgPathsFn, denoHooks } = JSON . parse ( await Deno . readTextFile ( metaFp ) )
1154
1156
if ( _specifier === specifier && util . isFilledString ( sourceHash ) && util . isArray ( deps ) ) {
@@ -1165,6 +1167,11 @@ export class Aleph implements IAleph {
1165
1167
} catch ( e ) { }
1166
1168
}
1167
1169
1170
+ if ( virtual ) {
1171
+ defer ( )
1172
+ return [ mod , null ]
1173
+ }
1174
+
1168
1175
if ( ! isRemote || this . #reloading || mod . sourceHash === '' || ! await existsFile ( cacheFp ) ) {
1169
1176
try {
1170
1177
const src = customSource || await this . resolveModuleSource ( specifier , data )
@@ -1272,15 +1279,20 @@ export class Aleph implements IAleph {
1272
1279
}
1273
1280
}
1274
1281
1282
+ let extraDeps : DependencyDescriptor [ ] = [ ]
1275
1283
for ( const { test, transform } of this . #transformListeners) {
1276
1284
if ( test instanceof RegExp && test . test ( specifier ) ) {
1277
- const ret = await transform ( { module : { ...module } , code : jsCode , map : sourceMap } )
1285
+ const { jsBuffer, ready, ...rest } = module
1286
+ const ret = await transform ( { module : { ...structuredClone ( rest ) } , code : jsCode , map : sourceMap } )
1278
1287
if ( util . isFilledString ( ret ?. code ) ) {
1279
1288
jsCode = ret ! . code
1280
1289
}
1281
1290
if ( util . isFilledString ( ret ?. map ) ) {
1282
1291
sourceMap = ret ! . map
1283
1292
}
1293
+ if ( Array . isArray ( ret ?. extraDeps ) ) {
1294
+ extraDeps . push ( ...ret ! . extraDeps )
1295
+ }
1284
1296
}
1285
1297
}
1286
1298
@@ -1291,7 +1303,7 @@ export class Aleph implements IAleph {
1291
1303
1292
1304
module . jsBuffer = encoder . encode ( jsCode )
1293
1305
module . deps = deps . filter ( ( { specifier } ) => specifier !== module . specifier ) . map ( ( { specifier, resolved, isDynamic } ) => {
1294
- const dep : DependencyDescriptor = { specifier }
1306
+ const dep : DependencyDescriptor = { specifier, }
1295
1307
if ( isDynamic ) {
1296
1308
dep . isDynamic = true
1297
1309
}
@@ -1303,7 +1315,7 @@ export class Aleph implements IAleph {
1303
1315
}
1304
1316
}
1305
1317
return dep
1306
- } )
1318
+ } ) . concat ( extraDeps )
1307
1319
1308
1320
ms . stop ( `transpile '${ specifier } '` )
1309
1321
@@ -1312,11 +1324,16 @@ export class Aleph implements IAleph {
1312
1324
1313
1325
if ( module . deps . length > 0 ) {
1314
1326
let fsync = false
1315
- await Promise . all ( module . deps . map ( async ( { specifier, hashLoc } ) => {
1316
- let depModule : Module | null
1317
- if ( ignoreDeps ) {
1327
+ await Promise . all ( module . deps . map ( async ( { specifier, hashLoc, virtual } ) => {
1328
+ let depModule : Module | null = null
1329
+ if ( ignoreDeps || virtual ) {
1318
1330
depModule = this . getModule ( specifier )
1319
- } else {
1331
+ if ( depModule == null && virtual ) {
1332
+ const [ mod ] = await this . initModule ( specifier , { virtual : true } )
1333
+ depModule = mod
1334
+ }
1335
+ }
1336
+ if ( depModule === null ) {
1320
1337
const [ mod , src ] = await this . initModule ( specifier , { httpExternal } )
1321
1338
if ( ! mod . external ) {
1322
1339
await this . transpileModule ( mod , src , false , __tracing )
@@ -1325,7 +1342,7 @@ export class Aleph implements IAleph {
1325
1342
}
1326
1343
if ( depModule ) {
1327
1344
if ( hashLoc !== undefined ) {
1328
- const hash = this . gteModuleHash ( depModule )
1345
+ const hash = this . computeModuleHash ( depModule )
1329
1346
if ( await this . replaceDepHash ( module , hashLoc , hash ) ) {
1330
1347
fsync = true
1331
1348
}
@@ -1356,7 +1373,7 @@ export class Aleph implements IAleph {
1356
1373
const { specifier, hashLoc } = dep
1357
1374
if ( specifier === by . specifier && hashLoc !== undefined ) {
1358
1375
if ( hash == null ) {
1359
- hash = this . gteModuleHash ( by )
1376
+ hash = this . computeModuleHash ( by )
1360
1377
}
1361
1378
if ( await this . replaceDepHash ( mod , hashLoc , hash ) ) {
1362
1379
fsync = true
0 commit comments