@@ -558,89 +558,23 @@ export class Application implements ServerApplication {
558
558
]
559
559
}
560
560
561
- /** fetch module content */
562
- async fetchModule ( url : string ) : Promise < { content : Uint8Array , contentType : string | null } > {
563
- if ( ! util . isLikelyHttpURL ( url ) ) {
564
- const filepath = path . join ( this . srcDir , util . trimPrefix ( url , 'file://' ) )
565
- const content = await Deno . readFile ( filepath )
566
- return { content, contentType : null }
567
- }
568
-
569
- const u = new URL ( url )
570
- if ( url . startsWith ( 'https://esm.sh/' ) ) {
571
- if ( this . isDev && ! u . searchParams . has ( 'dev' ) ) {
572
- u . searchParams . set ( 'dev' , '' )
573
- u . search = u . search . replace ( 'dev=' , 'dev' )
574
- }
575
- }
576
-
577
- const { protocol, hostname, port, pathname, search } = u
578
- const versioned = reFullVersion . test ( pathname )
579
- const reload = this . #reloading || ! versioned
580
- const isLocalhost = url . startsWith ( 'http://localhost:' )
581
- const cacheDir = path . join (
582
- await getDenoDir ( ) ,
583
- 'deps' ,
584
- util . trimSuffix ( protocol , ':' ) ,
585
- hostname + ( port ? '_PORT' + port : '' )
586
- )
587
- const hash = createHash ( 'sha256' ) . update ( pathname + search ) . toString ( )
588
- const contentFile = path . join ( cacheDir , hash )
589
- const metaFile = path . join ( cacheDir , hash + '.metadata.json' )
590
-
591
- if ( ! reload && ! isLocalhost && existsFileSync ( contentFile ) && existsFileSync ( metaFile ) ) {
592
- const [ content , meta ] = await Promise . all ( [
593
- Deno . readFile ( contentFile ) ,
594
- Deno . readTextFile ( metaFile ) ,
595
- ] )
596
- try {
597
- const { headers } = JSON . parse ( meta )
598
- return {
599
- content,
600
- contentType : headers [ 'content-type' ] || null
601
- }
602
- } catch ( e ) { }
561
+ async resolveModule ( url : string ) {
562
+ const { content, contentType } = await this . fetchModule ( url )
563
+ const source = await this . precompile ( url , content , contentType )
564
+ if ( source === null ) {
565
+ throw new Error ( `Unsupported module '${ url } '` )
603
566
}
567
+ return source
568
+ }
604
569
605
- // download dep when deno cache failed
606
- let err = new Error ( 'Unknown' )
607
- for ( let i = 0 ; i < 15 ; i ++ ) {
608
- if ( i === 0 ) {
609
- if ( ! isLocalhost ) {
610
- log . info ( 'Download' , url )
611
- }
612
- } else {
613
- log . debug ( 'Download error:' , err )
614
- log . warn ( `Download ${ url } failed, retrying...` )
615
- }
616
- try {
617
- const resp = await fetch ( u . toString ( ) )
618
- if ( resp . status >= 400 ) {
619
- return Promise . reject ( new Error ( resp . statusText ) )
620
- }
621
- const buffer = await resp . arrayBuffer ( )
622
- const content = await Deno . readAll ( new Deno . Buffer ( buffer ) )
623
- if ( ! isLocalhost ) {
624
- await ensureDir ( cacheDir )
625
- Deno . writeFile ( contentFile , content )
626
- Deno . writeTextFile ( metaFile , JSON . stringify ( {
627
- headers : Array . from ( resp . headers . entries ( ) ) . reduce ( ( m , [ k , v ] ) => {
628
- m [ k ] = v
629
- return m
630
- } , { } as Record < string , string > ) ,
631
- url
632
- } , undefined , 2 ) )
633
- }
634
- return {
635
- content,
636
- contentType : resp . headers . get ( 'content-type' )
637
- }
638
- } catch ( e ) {
639
- err = e
640
- }
570
+ /** default compiler options */
571
+ private get defaultCompileOptions ( ) : TransformOptions {
572
+ return {
573
+ importMap : this . importMap ,
574
+ alephPkgUri : getAlephPkgUri ( ) ,
575
+ reactVersion : defaultReactVersion ,
576
+ isDev : this . isDev ,
641
577
}
642
-
643
- return Promise . reject ( err )
644
578
}
645
579
646
580
/** build the application to a static site(SSG) */
@@ -731,17 +665,107 @@ export class Application implements ServerApplication {
731
665
return { code, map }
732
666
}
733
667
734
- /** default compiler options */
735
- private get defaultCompileOptions ( ) : TransformOptions {
736
- return {
737
- importMap : this . importMap ,
738
- alephPkgUri : getAlephPkgUri ( ) ,
739
- reactVersion : defaultReactVersion ,
740
- isDev : this . isDev ,
668
+ /** fetch module content */
669
+ private async fetchModule ( url : string ) : Promise < { content : Uint8Array , contentType : string | null } > {
670
+ for ( const plugin of this . config . plugins ) {
671
+ if ( plugin . type === 'loader' && plugin . test . test ( url ) && plugin . resolve !== undefined ) {
672
+ const ret = plugin . resolve ( url )
673
+ let content : Uint8Array
674
+ if ( ret instanceof Promise ) {
675
+ content = ( await ret ) . content
676
+ } else {
677
+ content = ret . content
678
+ }
679
+ if ( content instanceof Uint8Array ) {
680
+ return { content, contentType : null }
681
+ }
682
+ }
683
+ }
684
+
685
+ if ( ! util . isLikelyHttpURL ( url ) ) {
686
+ const filepath = path . join ( this . srcDir , util . trimPrefix ( url , 'file://' ) )
687
+ const content = await Deno . readFile ( filepath )
688
+ return { content, contentType : null }
689
+ }
690
+
691
+ const u = new URL ( url )
692
+ if ( url . startsWith ( 'https://esm.sh/' ) ) {
693
+ if ( this . isDev && ! u . searchParams . has ( 'dev' ) ) {
694
+ u . searchParams . set ( 'dev' , '' )
695
+ u . search = u . search . replace ( 'dev=' , 'dev' )
696
+ }
741
697
}
698
+
699
+ const { protocol, hostname, port, pathname, search } = u
700
+ const versioned = reFullVersion . test ( pathname )
701
+ const reload = this . #reloading || ! versioned
702
+ const isLocalhost = url . startsWith ( 'http://localhost:' )
703
+ const cacheDir = path . join (
704
+ await getDenoDir ( ) ,
705
+ 'deps' ,
706
+ util . trimSuffix ( protocol , ':' ) ,
707
+ hostname + ( port ? '_PORT' + port : '' )
708
+ )
709
+ const hash = createHash ( 'sha256' ) . update ( pathname + search ) . toString ( )
710
+ const contentFile = path . join ( cacheDir , hash )
711
+ const metaFile = path . join ( cacheDir , hash + '.metadata.json' )
712
+
713
+ if ( ! reload && ! isLocalhost && existsFileSync ( contentFile ) && existsFileSync ( metaFile ) ) {
714
+ const [ content , meta ] = await Promise . all ( [
715
+ Deno . readFile ( contentFile ) ,
716
+ Deno . readTextFile ( metaFile ) ,
717
+ ] )
718
+ try {
719
+ const { headers } = JSON . parse ( meta )
720
+ return {
721
+ content,
722
+ contentType : headers [ 'content-type' ] || null
723
+ }
724
+ } catch ( e ) { }
725
+ }
726
+
727
+ // download dep when deno cache failed
728
+ let err = new Error ( 'Unknown' )
729
+ for ( let i = 0 ; i < 15 ; i ++ ) {
730
+ if ( i === 0 ) {
731
+ if ( ! isLocalhost ) {
732
+ log . info ( 'Download' , url )
733
+ }
734
+ } else {
735
+ log . debug ( 'Download error:' , err )
736
+ log . warn ( `Download ${ url } failed, retrying...` )
737
+ }
738
+ try {
739
+ const resp = await fetch ( u . toString ( ) )
740
+ if ( resp . status >= 400 ) {
741
+ return Promise . reject ( new Error ( resp . statusText ) )
742
+ }
743
+ const buffer = await resp . arrayBuffer ( )
744
+ const content = await Deno . readAll ( new Deno . Buffer ( buffer ) )
745
+ if ( ! isLocalhost ) {
746
+ await ensureDir ( cacheDir )
747
+ Deno . writeFile ( contentFile , content )
748
+ Deno . writeTextFile ( metaFile , JSON . stringify ( {
749
+ headers : Array . from ( resp . headers . entries ( ) ) . reduce ( ( m , [ k , v ] ) => {
750
+ m [ k ] = v
751
+ return m
752
+ } , { } as Record < string , string > ) ,
753
+ url
754
+ } , undefined , 2 ) )
755
+ }
756
+ return {
757
+ content,
758
+ contentType : resp . headers . get ( 'content-type' )
759
+ }
760
+ } catch ( e ) {
761
+ err = e
762
+ }
763
+ }
764
+
765
+ return Promise . reject ( err )
742
766
}
743
767
744
- async precompile (
768
+ private async precompile (
745
769
url : string ,
746
770
sourceContent : Uint8Array ,
747
771
contentType : string | null
@@ -1009,16 +1033,6 @@ export class Application implements ServerApplication {
1009
1033
}
1010
1034
}
1011
1035
1012
- private replaceDepHash ( jsContent : string , dep : DependencyDescriptor ) {
1013
- const s = `.js#${ dep . url } @`
1014
- return jsContent . split ( s ) . map ( ( p , i ) => {
1015
- if ( i > 0 && p . charAt ( 6 ) === '"' ) {
1016
- return dep . hash . slice ( 0 , 6 ) + p . slice ( 6 )
1017
- }
1018
- return p
1019
- } ) . join ( s )
1020
- }
1021
-
1022
1036
/** create bundle chunks for production. */
1023
1037
private async bundle ( ) {
1024
1038
const sharedEntryMods = new Set < string > ( )
@@ -1176,6 +1190,16 @@ export class Application implements ServerApplication {
1176
1190
return ssr
1177
1191
}
1178
1192
1193
+ private replaceDepHash ( jsContent : string , dep : DependencyDescriptor ) {
1194
+ const s = `.js#${ dep . url } @`
1195
+ return jsContent . split ( s ) . map ( ( p , i ) => {
1196
+ if ( i > 0 && p . charAt ( 6 ) === '"' ) {
1197
+ return dep . hash . slice ( 0 , 6 ) + p . slice ( 6 )
1198
+ }
1199
+ return p
1200
+ } ) . join ( s )
1201
+ }
1202
+
1179
1203
/** lookup deps recurively. */
1180
1204
private lookupDeps (
1181
1205
url : string ,
0 commit comments