@@ -14,7 +14,7 @@ import cssPlugin, { cssLoader, isCSS } 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 , ImportMap , LoadInput , LoadOutput , RouterURL , ResolveResult , TransformOutput , TransformInput } from '../types.d.ts'
17
+ import type { Aleph as IAleph , DependencyDescriptor , ImportMap , LoadInput , LoadOutput , Module , RouterURL , ResolveResult , TransformOutput , TransformInput , SSRData , SSRInput , SSROutput } 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'
@@ -25,44 +25,20 @@ import {
25
25
getAlephPkgUri , getSourceType , isLocalUrl , moduleExclude , toLocalPath , toRelativePath
26
26
} from './helper.ts'
27
27
import { getContentType } from './mime.ts'
28
- import type { SSRData } from './renderer.ts'
29
28
import { createHtml , Renderer } from './renderer.ts'
30
29
31
- /** A module includes the compilation details. */
32
- export type Module = {
33
- specifier : string
34
- deps : DependencyDescriptor [ ]
35
- external ?: boolean
36
- isStyle ?: boolean
37
- externalRemoteDeps ?: boolean
38
- ssrPropsFn ?: string
39
- ssgPathsFn ?: boolean
40
- denoHooks ?: string [ ]
41
- hash ?: string
42
- sourceHash : string
43
- jsFile : string
44
- jsBuffer ?: Uint8Array
45
- ready : Promise < void >
46
- }
47
-
48
30
type ModuleSource = {
49
31
code : string
50
32
type : SourceType
51
33
isStyle : boolean
52
34
map ?: string
53
35
}
54
36
55
- type DependencyDescriptor = {
56
- specifier : string
57
- isDynamic ?: boolean
58
- hashLoc ?: number
59
- }
60
-
61
37
type CompileOptions = {
62
38
source ?: ModuleSource ,
63
39
forceRefresh ?: boolean ,
64
40
ignoreDeps ?: boolean ,
65
- externalRemoteDeps ?: boolean
41
+ httpExternal ?: boolean
66
42
}
67
43
68
44
type ResolveListener = {
@@ -80,9 +56,9 @@ type TransformListener = {
80
56
transform ( input : TransformInput ) : TransformOutput ,
81
57
}
82
58
83
- type SsrListener = ( path : string , html : string ) => { html : string }
59
+ type SsrListener = ( input : SSRInput ) => SSROutput
84
60
85
- /** The Aleph class for aleph runtime. */
61
+ /** The class for Aleph server runtime. */
86
62
export class Aleph implements IAleph {
87
63
#config: RequiredConfig
88
64
#importMap: ImportMap
@@ -135,7 +111,7 @@ export class Aleph implements IAleph {
135
111
}
136
112
if ( configFile ) {
137
113
if ( ! configFile . endsWith ( '.json' ) ) {
138
- const mod = await this . compile ( `/${ basename ( configFile ) } ` , { externalRemoteDeps : true } )
114
+ const mod = await this . compile ( `/${ basename ( configFile ) } ` , { httpExternal : true } )
139
115
configFile = join ( this . #buildDir, mod . jsFile )
140
116
}
141
117
Object . assign ( this . #config, await loadConfig ( configFile ) )
@@ -217,7 +193,7 @@ export class Aleph implements IAleph {
217
193
218
194
const mwFile = await findFile ( this . #workingDir, [ 'ts' , 'js' , 'mjs' ] . map ( ext => `${ this . #config. srcDir } /api/_middlewares.${ ext } ` ) )
219
195
if ( mwFile ) {
220
- const mwMod = await this . compile ( `/api/${ basename ( mwFile ) } ` , { externalRemoteDeps : true } )
196
+ const mwMod = await this . compile ( `/api/${ basename ( mwFile ) } ` , { httpExternal : true } )
221
197
const { default : _middlewares } = await import ( 'file://' + join ( this . #buildDir, mwMod . jsFile ) )
222
198
const middlewares = Array . isArray ( _middlewares ) ? _middlewares . filter ( fn => util . isFunction ( fn ) ) : [ ]
223
199
this . #config. server . middlewares . push ( ...middlewares )
@@ -326,7 +302,7 @@ export class Aleph implements IAleph {
326
302
const module = await this . compile ( specifier , {
327
303
forceRefresh : true ,
328
304
ignoreDeps : true ,
329
- externalRemoteDeps : specifier . startsWith ( '/api/' )
305
+ httpExternal : specifier . startsWith ( '/api/' )
330
306
} )
331
307
const refreshPage = (
332
308
this . #config. ssr &&
@@ -500,7 +476,7 @@ export class Aleph implements IAleph {
500
476
if ( this . #modules. has ( specifier ) ) {
501
477
return [ url , this . #modules. get ( specifier ) ! ]
502
478
}
503
- const module = await this . compile ( specifier , { externalRemoteDeps : true } )
479
+ const module = await this . compile ( specifier , { httpExternal : true } )
504
480
return [ url , module ]
505
481
}
506
482
}
@@ -519,7 +495,7 @@ export class Aleph implements IAleph {
519
495
this . #transformListeners. push ( { test, transform : callback } )
520
496
}
521
497
522
- onSSR ( callback : ( path : string , html : string ) => { html : string } ) : void {
498
+ onSSR ( callback : ( input : SSRInput ) => SSROutput ) : void {
523
499
this . #ssrListeners. push ( callback )
524
500
}
525
501
@@ -638,8 +614,13 @@ export class Aleph implements IAleph {
638
614
async #renderPage( url : RouterURL , nestedModules : string [ ] ) : Promise < [ string , Record < string , SSRData > | null ] > {
639
615
let [ html , data ] = await this . #renderer. renderPage ( url , nestedModules )
640
616
for ( const callback of this . #ssrListeners) {
641
- const ret = callback ( url . toString ( ) , html )
642
- html = ret . html
617
+ const ret = callback ( { path : url . toString ( ) , html, data } )
618
+ if ( util . isFilledString ( ret . html ) ) {
619
+ html = ret . html
620
+ }
621
+ if ( util . isPlainObject ( ret . data ) ) {
622
+ data = ret . data
623
+ }
643
624
}
644
625
return [ html , data ]
645
626
}
@@ -676,22 +657,31 @@ export class Aleph implements IAleph {
676
657
rewrites : this . #config. server . rewrites ,
677
658
}
678
659
660
+ let code : string
679
661
if ( bundleMode ) {
680
- return [
662
+ code = [
681
663
`__ALEPH__.basePath = ${ JSON . stringify ( basePath ) } ;` ,
682
664
`__ALEPH__.pack["${ alephPkgUri } /framework/${ framework } /bootstrap.ts"].default(${ JSON . stringify ( config ) } );`
683
665
] . join ( '' )
666
+ } else {
667
+ code = [
668
+ `import bootstrap from "./-/${ alephPkgPath } /framework/${ framework } /bootstrap.js";` ,
669
+ this . isDev && `import { connect } from "./-/${ alephPkgPath } /framework/core/hmr.js";` ,
670
+ this . isDev && `connect(${ JSON . stringify ( basePath ) } );` ,
671
+ `bootstrap(${ JSON . stringify ( config , undefined , this . isDev ? 2 : undefined ) } );`
672
+ ] . filter ( Boolean ) . join ( '\n' )
684
673
}
685
-
686
- let code = [
687
- `import bootstrap from "./-/${ alephPkgPath } /framework/${ framework } /bootstrap.js";` ,
688
- this . isDev && `import { connect } from "./-/${ alephPkgPath } /framework/core/hmr.js";` ,
689
- this . isDev && `connect(${ JSON . stringify ( basePath ) } );` ,
690
- `bootstrap(${ JSON . stringify ( config , undefined , this . isDev ? 2 : undefined ) } );`
691
- ] . filter ( Boolean ) . join ( '\n' )
692
674
this . #transformListeners. forEach ( ( { test, transform } ) => {
693
675
if ( test === 'main' ) {
694
- const ret = transform ( { specifier : '/main.js' , code } )
676
+ const ret = transform ( {
677
+ module : {
678
+ specifier : '/main.js' ,
679
+ deps : [ ] ,
680
+ sourceHash : '' ,
681
+ jsFile : '' ,
682
+ } ,
683
+ code,
684
+ } )
695
685
code = ret . code
696
686
}
697
687
} )
@@ -929,7 +919,8 @@ export class Aleph implements IAleph {
929
919
}
930
920
this . #transformListeners. forEach ( ( { test, transform } ) => {
931
921
if ( test === 'hmr' ) {
932
- const ret = transform ( { specifier, code } )
922
+ const { jsBuffer, ready, ...rest } = module
923
+ const ret = transform ( { module : structuredClone ( rest ) , code } )
933
924
code = ret . code
934
925
// todo: merge source map
935
926
}
@@ -1034,7 +1025,7 @@ export class Aleph implements IAleph {
1034
1025
return module
1035
1026
}
1036
1027
1037
- private async initModule ( specifier : string , { source : customSource , forceRefresh, externalRemoteDeps } : CompileOptions = { } ) : Promise < [ Module , ModuleSource | null ] > {
1028
+ private async initModule ( specifier : string , { source : customSource , forceRefresh, httpExternal } : CompileOptions = { } ) : Promise < [ Module , ModuleSource | null ] > {
1038
1029
let external = false
1039
1030
let data : any = null
1040
1031
@@ -1064,7 +1055,7 @@ export class Aleph implements IAleph {
1064
1055
}
1065
1056
1066
1057
let mod = this . #modules. get ( specifier )
1067
- if ( mod && ! forceRefresh && ! ( ! externalRemoteDeps && mod . externalRemoteDeps ) ) {
1058
+ if ( mod && ! forceRefresh && ! ( ! httpExternal && mod . httpExternal ) ) {
1068
1059
await mod . ready
1069
1060
return [ mod , null ]
1070
1061
}
@@ -1082,7 +1073,7 @@ export class Aleph implements IAleph {
1082
1073
specifier,
1083
1074
deps : [ ] ,
1084
1075
sourceHash : '' ,
1085
- externalRemoteDeps ,
1076
+ httpExternal ,
1086
1077
jsFile,
1087
1078
ready : new Promise ( ( resolve ) => {
1088
1079
defer = ( err ?: Error ) => {
@@ -1146,7 +1137,7 @@ export class Aleph implements IAleph {
1146
1137
ignoreDeps = false ,
1147
1138
__tracing : Set < string > = new Set ( )
1148
1139
) : Promise < void > {
1149
- const { specifier, jsFile, externalRemoteDeps } = module
1140
+ const { specifier, jsFile, httpExternal } = module
1150
1141
1151
1142
// ensure the module only be transppiled once in current compilation context,
1152
1143
// to avoid dead-loop caused by cicular imports
@@ -1163,13 +1154,13 @@ export class Aleph implements IAleph {
1163
1154
1164
1155
const ms = new Measure ( )
1165
1156
const encoder = new TextEncoder ( )
1166
- const { code, deps, denoHooks, ssrPropsFn, ssgPathsFn, starExports, map } = await transform ( specifier , source . code , {
1157
+ const { code, deps, denoHooks, ssrPropsFn, ssgPathsFn, starExports, jsxStaticClassNames , map } = await transform ( specifier , source . code , {
1167
1158
...this . commonCompilerOptions ,
1168
1159
sourceMap : this . isDev ,
1169
1160
swcOptions : {
1170
1161
sourceType : source . type
1171
1162
} ,
1172
- externalRemoteDeps
1163
+ httpExternal
1173
1164
} )
1174
1165
1175
1166
let jsCode = code
@@ -1213,9 +1204,18 @@ export class Aleph implements IAleph {
1213
1204
} )
1214
1205
}
1215
1206
1207
+ Object . assign ( module , { ssrPropsFn, ssgPathsFn, jsxStaticClassNames } )
1208
+ if ( util . isFilledArray ( denoHooks ) ) {
1209
+ module . denoHooks = denoHooks . map ( id => util . trimPrefix ( id , 'useDeno-' ) )
1210
+ if ( ! this . #config. ssr ) {
1211
+ log . error ( `'useDeno' hook in SPA mode is illegal: ${ specifier } ` )
1212
+ }
1213
+ }
1214
+
1216
1215
this . #transformListeners. forEach ( ( { test, transform } ) => {
1217
1216
if ( test instanceof RegExp && test . test ( specifier ) ) {
1218
- const { code, map } = transform ( { specifier, code : jsCode , map : sourceMap } )
1217
+ const { jsBuffer, ready, ...rest } = module
1218
+ const { code, map } = transform ( { module : structuredClone ( rest ) , code : jsCode , map : sourceMap } )
1219
1219
jsCode = code
1220
1220
if ( map ) {
1221
1221
sourceMap = map
@@ -1244,15 +1244,6 @@ export class Aleph implements IAleph {
1244
1244
return dep
1245
1245
} ) || [ ]
1246
1246
1247
- module . ssrPropsFn = ssrPropsFn
1248
- module . ssgPathsFn = ssgPathsFn
1249
- if ( util . isFilledArray ( denoHooks ) ) {
1250
- module . denoHooks = denoHooks . map ( id => util . trimPrefix ( id , 'useDeno-' ) )
1251
- if ( ! this . #config. ssr ) {
1252
- log . error ( `'useDeno' hook in SPA mode is illegal: ${ specifier } ` )
1253
- }
1254
- }
1255
-
1256
1247
ms . stop ( `transpile '${ specifier } '` )
1257
1248
1258
1249
const cacheFp = join ( this . #buildDir, jsFile )
@@ -1282,7 +1273,7 @@ export class Aleph implements IAleph {
1282
1273
if ( ignoreDeps ) {
1283
1274
depModule = this . getModule ( specifier )
1284
1275
} else {
1285
- const [ mod , src ] = await this . initModule ( specifier , { externalRemoteDeps } )
1276
+ const [ mod , src ] = await this . initModule ( specifier , { httpExternal } )
1286
1277
if ( ! mod . external ) {
1287
1278
await this . transpileModule ( mod , src , false , __tracing )
1288
1279
}
0 commit comments