@@ -32,7 +32,7 @@ import type {
32
32
Config ,
33
33
DependencyDescriptor ,
34
34
LoaderPlugin ,
35
- LoaderTransformResult ,
35
+ LoaderTransformOutput ,
36
36
Module ,
37
37
RouterURL ,
38
38
ServerApplication ,
@@ -221,7 +221,7 @@ export class Application implements ServerApplication {
221
221
}
222
222
if ( validated ) {
223
223
await this . compile ( url )
224
- this . #pageRouting. update ( this . createRouteModule ( url ) )
224
+ this . #pageRouting. update ( ... this . createRouteUpdate ( url ) )
225
225
}
226
226
}
227
227
}
@@ -232,7 +232,7 @@ export class Application implements ServerApplication {
232
232
for await ( const { path : p } of walk ( apiDir , { ...walkOptions , exts : moduleExts } ) ) {
233
233
const url = util . cleanPath ( '/api/' + util . trimPrefix ( p , apiDir ) )
234
234
await this . compile ( url )
235
- this . #apiRouting. update ( this . createRouteModule ( url ) )
235
+ this . #apiRouting. update ( ... this . createRouteUpdate ( url ) )
236
236
}
237
237
}
238
238
@@ -274,17 +274,39 @@ export class Application implements ServerApplication {
274
274
if ( trimModuleExt ( url ) === '/app' ) {
275
275
this . #renderer. clearCache ( )
276
276
} else if ( url . startsWith ( '/pages/' ) ) {
277
- this . #renderer. clearCache ( url )
278
- this . #pageRouting. update ( this . createRouteModule ( url ) )
277
+ this . #renderer. clearCache ( toPagePath ( url ) )
278
+ this . #pageRouting. update ( ... this . createRouteUpdate ( url ) )
279
279
} else if ( url . startsWith ( '/api/' ) ) {
280
- this . #apiRouting. update ( this . createRouteModule ( url ) )
280
+ this . #apiRouting. update ( ... this . createRouteUpdate ( url ) )
281
281
}
282
282
}
283
283
if ( hmrable ) {
284
+ let pagePath : string | undefined = undefined
285
+ let useDeno : boolean | undefined = undefined
286
+ let isIndexModule : boolean | undefined = undefined
287
+ if ( mod . url . startsWith ( '/pages/' ) ) {
288
+ const [ path , _ , options ] = this . createRouteUpdate ( mod . url )
289
+ pagePath = path
290
+ useDeno = options . useDeno
291
+ isIndexModule = options . isIndexModule
292
+ } else {
293
+ if ( [ '/app' , '/404' ] . includes ( trimModuleExt ( mod . url ) ) ) {
294
+ this . lookupDeps ( mod . url , dep => {
295
+ if ( dep . url . startsWith ( '#useDeno-' ) ) {
296
+ useDeno = true
297
+ return false
298
+ }
299
+ } )
300
+ }
301
+ }
284
302
if ( type === 'add' ) {
285
- this . #fsWatchListeners. forEach ( e => e . emit ( 'add' , { url : mod . url } ) )
303
+ this . #fsWatchListeners. forEach ( e => {
304
+ e . emit ( 'add' , { url : mod . url , pagePath, isIndexModule, useDeno } )
305
+ } )
286
306
} else {
287
- this . #fsWatchListeners. forEach ( e => e . emit ( 'modify-' + mod . url ) )
307
+ this . #fsWatchListeners. forEach ( e => {
308
+ e . emit ( 'modify-' + mod . url , { useDeno } )
309
+ } )
288
310
}
289
311
}
290
312
update ( mod )
@@ -396,12 +418,12 @@ export class Application implements ServerApplication {
396
418
}
397
419
398
420
/** add a new page module by given path and source code. */
399
- async addModule ( url : string , options : { code ?: string , once ?: boolean } = { } ) : Promise < Module > {
421
+ async addModule ( url : string , options : { code ?: string } = { } ) : Promise < Module > {
400
422
const mod = await this . compile ( url , { sourceCode : options . code } )
401
423
if ( url . startsWith ( '/pages/' ) ) {
402
- this . #pageRouting. update ( this . createRouteModule ( url ) )
424
+ this . #pageRouting. update ( ... this . createRouteUpdate ( url ) )
403
425
} else if ( url . startsWith ( '/api/' ) ) {
404
- this . #apiRouting. update ( this . createRouteModule ( url ) )
426
+ this . #apiRouting. update ( ... this . createRouteUpdate ( url ) )
405
427
}
406
428
return mod
407
429
}
@@ -536,14 +558,19 @@ export class Application implements ServerApplication {
536
558
routes : this . #pageRouting. routes ,
537
559
rewrites : this . config . rewrites ,
538
560
sharedModules : Array . from ( this . #modules. values ( ) ) . filter ( ( { url } ) => {
539
- switch ( trimModuleExt ( url ) ) {
540
- case '/404' :
541
- case '/app' :
542
- return true
543
- default :
544
- return false
561
+ return [ '/app' , '/404' ] . includes ( trimModuleExt ( url ) )
562
+ } ) . map ( ( { url } ) => {
563
+ let useDeno : boolean | undefined = undefined
564
+ if ( this . config . ssr !== false ) {
565
+ this . lookupDeps ( url , dep => {
566
+ if ( dep . url . startsWith ( '#useDeno-' ) ) {
567
+ useDeno = true
568
+ return false
569
+ }
570
+ } )
545
571
}
546
- } ) . map ( ( { url } ) => this . createRouteModule ( url ) ) ,
572
+ return { url, useDeno }
573
+ } ) ,
547
574
renderMode : this . config . ssr ? 'ssr' : 'spa'
548
575
}
549
576
@@ -686,8 +713,10 @@ export class Application implements ServerApplication {
686
713
return dir
687
714
}
688
715
689
- private createRouteModule ( url : string ) : RouteModule {
690
- let useDeno : true | undefined = undefined
716
+ private createRouteUpdate ( url : string ) : [ string , string , { isIndexModule ?: boolean , useDeno ?: boolean } ] {
717
+ let pathPath = toPagePath ( url )
718
+ let useDeno : boolean | undefined = undefined
719
+ let isIndexModule : boolean | undefined = undefined
691
720
if ( this . config . ssr !== false ) {
692
721
this . lookupDeps ( url , dep => {
693
722
if ( dep . url . startsWith ( '#useDeno-' ) ) {
@@ -696,14 +725,30 @@ export class Application implements ServerApplication {
696
725
}
697
726
} )
698
727
}
699
- return { url, useDeno }
728
+ if ( pathPath !== '/' ) {
729
+ for ( const ext of moduleExts ) {
730
+ if ( url . endsWith ( '/index.' + ext ) ) {
731
+ isIndexModule = true
732
+ break
733
+ }
734
+ }
735
+ }
736
+ return [ pathPath , url , { isIndexModule, useDeno } ]
700
737
}
701
738
702
739
/** apply loaders recurively. */
703
740
private async applyLoader (
704
741
loader : LoaderPlugin ,
705
742
input : { url : string , content : Uint8Array , map ?: Uint8Array }
706
- ) : Promise < Omit < LoaderTransformResult , 'loader' > > {
743
+ ) : Promise < LoaderTransformOutput > {
744
+ if ( ! loader . transform ) {
745
+ const decoder = new TextDecoder ( )
746
+ return {
747
+ code : decoder . decode ( input . content ) ,
748
+ map : input . map ? decoder . decode ( input . map ) : undefined
749
+ }
750
+ }
751
+
707
752
const { code, map, type } = await loader . transform ( input )
708
753
if ( type ) {
709
754
for ( const plugin of this . config . plugins ) {
@@ -724,12 +769,12 @@ export class Application implements ServerApplication {
724
769
private async fetchModule ( url : string ) : Promise < { content : Uint8Array , contentType : string | null } > {
725
770
for ( const plugin of this . config . plugins ) {
726
771
if ( plugin . type === 'loader' && plugin . test . test ( url ) && plugin . resolve !== undefined ) {
727
- const ret = plugin . resolve ( url )
772
+ const v = plugin . resolve ( url )
728
773
let content : Uint8Array
729
- if ( ret instanceof Promise ) {
730
- content = ( await ret ) . content
774
+ if ( v instanceof Promise ) {
775
+ content = ( await v )
731
776
} else {
732
- content = ret . content
777
+ content = v
733
778
}
734
779
if ( content instanceof Uint8Array ) {
735
780
return { content, contentType : null }
@@ -824,9 +869,9 @@ export class Application implements ServerApplication {
824
869
url : string ,
825
870
sourceContent : Uint8Array ,
826
871
contentType : string | null
827
- ) : Promise < [ string , SourceType ] | null > {
872
+ ) : Promise < { code : string , type : SourceType } | null > {
828
873
let sourceCode = ( new TextDecoder ) . decode ( sourceContent )
829
- let sourceType : SourceType = SourceType . Unknown
874
+ let sourceType : SourceType | null = null
830
875
831
876
if ( contentType !== null ) {
832
877
switch ( contentType . split ( ';' ) [ 0 ] . trim ( ) ) {
@@ -866,12 +911,15 @@ export class Application implements ServerApplication {
866
911
case 'tsx' :
867
912
sourceType = SourceType . TSX
868
913
break
914
+ default :
915
+ sourceType = SourceType . Unknown
916
+ break
869
917
}
870
918
break
871
919
}
872
920
}
873
921
874
- if ( sourceType === SourceType . Unknown ) {
922
+ if ( sourceType === null ) {
875
923
switch ( extname ( url ) . slice ( 1 ) . toLowerCase ( ) ) {
876
924
case 'mjs' :
877
925
case 'js' :
@@ -891,7 +939,7 @@ export class Application implements ServerApplication {
891
939
}
892
940
}
893
941
894
- return [ sourceCode , sourceType ]
942
+ return { code : sourceCode , type : sourceType }
895
943
}
896
944
897
945
/** compile a moudle by given url, then cache on the disk. */
@@ -925,7 +973,7 @@ export class Application implements ServerApplication {
925
973
deps : [ ] ,
926
974
sourceHash : '' ,
927
975
hash : '' ,
928
- jsFile : '' ,
976
+ jsFile : util . cleanPath ( ` ${ saveDir } / ${ name } .js` ) ,
929
977
}
930
978
if ( ! once ) {
931
979
this . #modules. set ( url , mod )
@@ -993,12 +1041,12 @@ export class Application implements ServerApplication {
993
1041
}
994
1042
995
1043
const t = performance . now ( )
996
- const [ sourceCode , sourceType ] = source
997
- const { code, deps, starExports, map } = await transform ( url , sourceCode , {
1044
+
1045
+ const { code, deps, starExports, map } = await transform ( url , source . code , {
998
1046
...this . defaultCompileOptions ,
999
1047
swcOptions : {
1000
1048
target : 'es2020' ,
1001
- sourceType
1049
+ sourceType : source . type
1002
1050
} ,
1003
1051
// workaround for https://github.com/denoland/deno/issues/9849
1004
1052
resolveStarExports : ! this . isDev && Deno . version . deno . replace ( / \. \d + $ / , '' ) === '1.8' ,
@@ -1016,8 +1064,8 @@ export class Application implements ServerApplication {
1016
1064
if ( starExports && starExports . length > 0 ) {
1017
1065
for ( let index = 0 ; index < starExports . length ; index ++ ) {
1018
1066
const url = starExports [ index ]
1019
- const [ sourceCode , sourceType ] = await this . resolveModule ( url )
1020
- const names = await parseExportNames ( url , sourceCode , { sourceType } )
1067
+ const source = await this . resolveModule ( url )
1068
+ const names = await parseExportNames ( url , source . code , { sourceType : source . type } )
1021
1069
jsContent = jsContent . replace ( `export * from "${ url } :` , `export {${ names . filter ( name => name !== 'default' ) . join ( ',' ) } } from "` )
1022
1070
}
1023
1071
}
@@ -1036,8 +1084,6 @@ export class Application implements ServerApplication {
1036
1084
log . debug ( `compile '${ url } ' in ${ Math . round ( performance . now ( ) - t ) } ms` )
1037
1085
}
1038
1086
1039
- mod . jsFile = util . cleanPath ( `${ saveDir } /${ name } .js` )
1040
-
1041
1087
// compile deps
1042
1088
for ( const dep of mod . deps ) {
1043
1089
if ( ! dep . url . startsWith ( '#' ) ) {
0 commit comments