1
+ // @ts -expect-error only for types
2
+ import { ImportMap , IImportMap } from '@jspm/import-map' ;
3
+ import { pathToFileURL } from 'url' ;
4
+ import {
5
+ loadEsmModule ,
6
+ DeferredPromise ,
7
+ checkIfNodeProtocol ,
8
+ checkIfFileProtocol ,
9
+ resolveModulePath ,
10
+ asyncCustomResolve ,
11
+ } from './custom-loader-utils' ;
12
+
1
13
import { Context , DefaultLoad , NextResolve } from './types' ;
14
+ import { CACHE_FILE , IMPORT_MAP } from './constants' ;
2
15
import { join } from 'path' ;
16
+ import { PREF } from './patch-vite-dev-server' ;
17
+ import { OutputFileRecord } from '../types' ;
18
+ import { getResultImportMap , IMPORT_MAP_CONFIG_NAME } from '../helpers' ;
19
+
20
+ const fakeRootPath = pathToFileURL ( 'tmp/file/' ) . href ;
21
+ const mapUrlDeferred = new DeferredPromise < {
22
+ importMap : IImportMap ;
23
+ rootUrlHost : string ;
24
+ } > ( ) ;
25
+
26
+ const cacheFilesDeferred = new DeferredPromise < Map < string , OutputFileRecord > > ( ) ;
27
+ const importMapModulePromise = loadEsmModule < {
28
+ ImportMap : new ( ...args : any [ ] ) => ImportMap ;
29
+ } > ( '@jspm/import-map' ) . then ( ( r ) => r . ImportMap ) ;
30
+
31
+ let start = false ;
32
+ let importMap : ImportMap ;
33
+
34
+ let cacheFiles : Map < string , OutputFileRecord > = new Map <
35
+ string ,
36
+ OutputFileRecord
37
+ > ( ) ;
38
+ const packageNameToImportNameMap = new Map < string , string > ( ) ;
39
+
40
+
41
+ async function getImportMap ( ) {
42
+ if ( importMap ) return importMap ;
43
+
44
+ const ImportMap = await importMapModulePromise ;
45
+ const { importMap : importMapJson , rootUrlHost } = await mapUrlDeferred ;
46
+
47
+ importMap = new ImportMap ( {
48
+ map : importMapJson ,
49
+ mapUrl : rootUrlHost ,
50
+ } ) ;
51
+ }
52
+
53
+ async function getCacheFiles ( ) {
54
+ await cacheFilesDeferred ;
55
+ return cacheFiles ;
56
+ }
3
57
4
58
export async function initialize ( { port } : { port : MessagePort } ) {
5
- port . onmessage = async ( event ) => { } ;
59
+ port . onmessage = async ( event ) => {
60
+ switch ( event . data . kind ) {
61
+ case IMPORT_MAP :
62
+ mapUrlDeferred . resolve ( event . data . result ) ;
63
+ break ;
64
+ case CACHE_FILE :
65
+ cacheFiles = event . data . result ;
66
+ for ( const value of cacheFiles . values ( ) ) {
67
+ packageNameToImportNameMap . set ( value . packageName , value . mapName ) ;
68
+ }
69
+ cacheFilesDeferred . resolve ( event . data . result ) ;
70
+ break ;
71
+ }
72
+ } ;
6
73
}
7
74
8
75
export async function resolve (
9
- specifier : string ,
76
+ specifierInput : string ,
10
77
context : Context ,
11
78
nextResolve : NextResolve
12
79
) {
13
80
const { parentURL } = context ;
81
+ const specifier = specifierInput . replace ( PREF , '' ) ;
14
82
if (
15
83
specifier . startsWith ( 'vite' ) &&
16
- parentURL . indexOf ( '@angular/build' ) > - 1
84
+ ( parentURL . indexOf ( '@angular/build' ) > - 1 ||
85
+ parentURL . indexOf ( 'custom-loader-utils' ) > - 1 )
17
86
) {
18
87
return nextResolve (
19
88
join ( __dirname , 'patch-vite-dev-server.js' ) ,
@@ -22,13 +91,113 @@ export async function resolve(
22
91
) ;
23
92
}
24
93
25
- return nextResolve ( specifier , context , nextResolve ) ;
94
+ if ( ! start && parentURL . indexOf ( 'vite/dist/node' ) > - 1 ) {
95
+ start = true ;
96
+ }
97
+
98
+ if ( ! start ) return nextResolve ( specifier , context , nextResolve ) ;
99
+
100
+ if (
101
+ parentURL . indexOf ( '@angular/compiler-cli' ) > - 1 ||
102
+ parentURL . indexOf ( '@angular/build' ) > - 1
103
+ ) {
104
+ return nextResolve ( specifier , context , nextResolve ) ;
105
+ }
106
+
107
+ const importMap = await getImportMap ( ) ;
108
+ const importMapName = packageNameToImportNameMap . get ( specifier ) ;
109
+ const resolveUrl = resolveModulePath ( importMap , specifier , parentURL ) ;
110
+
111
+ if ( checkIfNodeProtocol ( resolveUrl ) || checkIfFileProtocol ( resolveUrl ) ) {
112
+ return nextResolve ( specifier , context , nextResolve ) ;
113
+ }
114
+
115
+ if ( ! importMapName && ! resolveUrl ) {
116
+ try {
117
+ const fileUrl = await asyncCustomResolve ( specifier ) ;
118
+ const pathToFile = pathToFileURL ( fileUrl ) ;
119
+ const pathName = new URL ( parentURL ) . pathname ;
120
+ const resultFromImport = Object . entries ( importMap . toJSON ( ) . imports ) . find (
121
+ ( [ key , val ] ) => val . endsWith ( pathName )
122
+ ) ;
123
+ if ( resultFromImport ) {
124
+ context . parentURL = resultFromImport [ 0 ] . replace ( PREF , '' ) ;
125
+ }
126
+ return nextResolve ( pathToFile . toString ( ) , context , nextResolve ) ;
127
+ } catch ( e ) {
128
+ return nextResolve ( specifier , context , nextResolve ) ;
129
+ }
130
+ }
131
+
132
+ const specifierUrl = new URL ( specifier , fakeRootPath ) ;
133
+
134
+ return {
135
+ url : specifierUrl . toString ( ) ,
136
+ shortCircuit : true ,
137
+ } ;
26
138
}
27
139
28
140
export async function load (
29
141
url : string ,
30
142
context : Context ,
31
143
defaultLoad : DefaultLoad
32
144
) {
145
+ url = url . split ( '?' ) . at ( 0 ) ;
146
+
147
+ const specifier = url . replace ( fakeRootPath , '' ) ;
148
+
149
+ const importMapName = packageNameToImportNameMap . get ( specifier ) ;
150
+ const { parentURL } = context ;
151
+
152
+ if ( importMapName ) {
153
+ const cacheFiles = await getCacheFiles ( ) ;
154
+ const hasCache = cacheFiles . get ( importMapName ) ;
155
+ if ( hasCache ) {
156
+ const content = `
157
+ var ngServerMode = true;
158
+ ${ new TextDecoder ( ) . decode ( hasCache . contents ) }
159
+ ` ;
160
+
161
+ return {
162
+ format : 'module' ,
163
+ source : content ,
164
+ shortCircuit : true ,
165
+ } ;
166
+ }
167
+ }
168
+ const importMap = await getImportMap ( ) ;
169
+ const resolveUrl = resolveModulePath ( importMap , specifier , parentURL ) ;
170
+ if ( ! resolveUrl ) return defaultLoad ( url , context , defaultLoad ) ;
171
+ const originalUrl = new URL ( resolveUrl ) ;
172
+ if ( importMap . scopes [ originalUrl . origin + '/' ] ) {
173
+ try {
174
+ const importJson = await fetch (
175
+ new URL ( IMPORT_MAP_CONFIG_NAME , originalUrl . origin ) . toString ( )
176
+ ) . then ( ( r ) => r . json ( ) ) ;
177
+ const importMapScope = await getResultImportMap ( importJson ) ;
178
+ for ( const [ key , value ] of Object . entries < string > (
179
+ importMapScope . imports
180
+ ) ) {
181
+ if ( ! value . endsWith ( importMap . imports [ key ] ) ) {
182
+ importMap . set ( key , `${ value } ` , originalUrl . origin ) ;
183
+ }
184
+ }
185
+ const response = await fetch ( originalUrl ) . then ( ( r ) => r . text ( ) ) ;
186
+ const content = `
187
+ var ngServerMode = true;
188
+ ${ response }
189
+ ` ;
190
+
191
+ return {
192
+ format : 'module' ,
193
+ source : content ,
194
+ shortCircuit : true ,
195
+ } ;
196
+ } catch ( e ) {
197
+ console . error ( 'Load scope dep' , e ) ;
198
+ return defaultLoad ( url , context , defaultLoad ) ;
199
+ }
200
+ }
201
+
33
202
return defaultLoad ( url , context , defaultLoad ) ;
34
203
}
0 commit comments