@@ -16,7 +16,9 @@ import { readFile } from 'node:fs/promises';
16
16
import type { AddressInfo } from 'node:net' ;
17
17
import path from 'node:path' ;
18
18
import { InlineConfig , ViteDevServer , createServer , normalizePath } from 'vite' ;
19
- import { buildEsbuildBrowser } from '../browser-esbuild' ;
19
+ import { buildEsbuildBrowserInternal } from '../browser-esbuild' ;
20
+ import { JavaScriptTransformer } from '../browser-esbuild/javascript-transformer' ;
21
+ import { BrowserEsbuildOptions } from '../browser-esbuild/options' ;
20
22
import type { Schema as BrowserBuilderOptions } from '../browser-esbuild/schema' ;
21
23
import { loadProxyConfiguration , normalizeProxyConfiguration } from './load-proxy-config' ;
22
24
import type { NormalizedDevServerOptions } from './options' ;
@@ -52,7 +54,9 @@ export async function* serveWithVite(
52
54
verbose : serverOptions . verbose ,
53
55
} as json . JsonObject & BrowserBuilderOptions ,
54
56
builderName ,
55
- ) ) as json . JsonObject & BrowserBuilderOptions ;
57
+ ) ) as json . JsonObject & BrowserEsbuildOptions ;
58
+ // Set all packages as external to support Vite's prebundle caching
59
+ browserOptions . externalPackages = serverOptions . cacheOptions . enabled ;
56
60
57
61
if ( serverOptions . servePath === undefined && browserOptions . baseHref !== undefined ) {
58
62
serverOptions . servePath = browserOptions . baseHref ;
@@ -63,7 +67,9 @@ export async function* serveWithVite(
63
67
const generatedFiles = new Map < string , OutputFileRecord > ( ) ;
64
68
const assetFiles = new Map < string , string > ( ) ;
65
69
// TODO: Switch this to an architect schedule call when infrastructure settings are supported
66
- for await ( const result of buildEsbuildBrowser ( browserOptions , context , { write : false } ) ) {
70
+ for await ( const result of buildEsbuildBrowserInternal ( browserOptions , context , {
71
+ write : false ,
72
+ } ) ) {
67
73
assert ( result . outputFiles , 'Builder did not provide result files.' ) ;
68
74
69
75
// Analyze result files for changes
@@ -96,7 +102,13 @@ export async function* serveWithVite(
96
102
}
97
103
} else {
98
104
// Setup server and start listening
99
- const serverConfiguration = await setupServer ( serverOptions , generatedFiles , assetFiles ) ;
105
+ const serverConfiguration = await setupServer (
106
+ serverOptions ,
107
+ generatedFiles ,
108
+ assetFiles ,
109
+ browserOptions . preserveSymlinks ,
110
+ browserOptions . externalDependencies ,
111
+ ) ;
100
112
server = await createServer ( serverConfiguration ) ;
101
113
102
114
await server . listen ( ) ;
@@ -173,10 +185,13 @@ function analyzeResultFiles(
173
185
}
174
186
}
175
187
188
+ // eslint-disable-next-line max-lines-per-function
176
189
export async function setupServer (
177
190
serverOptions : NormalizedDevServerOptions ,
178
191
outputFiles : Map < string , OutputFileRecord > ,
179
192
assets : Map < string , string > ,
193
+ preserveSymlinks : boolean | undefined ,
194
+ prebundleExclude : string [ ] | undefined ,
180
195
) : Promise < InlineConfig > {
181
196
const proxy = await loadProxyConfiguration (
182
197
serverOptions . workspaceRoot ,
@@ -199,6 +214,10 @@ export async function setupServer(
199
214
devSourcemap : true ,
200
215
} ,
201
216
base : serverOptions . servePath ,
217
+ resolve : {
218
+ mainFields : [ 'es2020' , 'browser' , 'module' , 'main' ] ,
219
+ preserveSymlinks,
220
+ } ,
202
221
server : {
203
222
port : serverOptions . port ,
204
223
strictPort : true ,
@@ -236,12 +255,13 @@ export async function setupServer(
236
255
return ;
237
256
}
238
257
258
+ const code = Buffer . from ( codeContents ) . toString ( 'utf-8' ) ;
239
259
const mapContents = outputFiles . get ( file + '.map' ) ?. contents ;
240
260
241
261
return {
242
262
// Remove source map URL comments from the code if a sourcemap is present.
243
263
// Vite will inline and add an additional sourcemap URL for the sourcemap.
244
- code : Buffer . from ( codeContents ) . toString ( 'utf-8' ) ,
264
+ code : mapContents ? code . replace ( / ^ \/ \/ # s o u r c e M a p p i n g U R L = [ ^ \r \n ] * / gm , '' ) : code ,
245
265
map : mapContents && Buffer . from ( mapContents ) . toString ( 'utf-8' ) ,
246
266
} ;
247
267
} ,
@@ -276,7 +296,7 @@ export async function setupServer(
276
296
// Resource files are handled directly.
277
297
// Global stylesheets (CSS files) are currently considered resources to workaround
278
298
// dev server sourcemap issues with stylesheets.
279
- if ( extension !== '.html' ) {
299
+ if ( extension !== '.js' && extension !== '. html') {
280
300
const outputFile = outputFiles . get ( pathname ) ;
281
301
if ( outputFile ) {
282
302
const mimeType = lookupMimeType ( extension ) ;
@@ -345,8 +365,34 @@ export async function setupServer(
345
365
} ,
346
366
] ,
347
367
optimizeDeps : {
348
- // TODO: Consider enabling for known safe dependencies (@angular/* ?)
349
- disabled : true ,
368
+ // Only enable with caching since it causes prebundle dependencies to be cached
369
+ disabled : ! serverOptions . cacheOptions . enabled ,
370
+ // Exclude any provided dependencies (currently build defined externals)
371
+ exclude : prebundleExclude ,
372
+ // Skip automatic file-based entry point discovery
373
+ include : [ ] ,
374
+ // Add an esbuild plugin to run the Angular linker on dependencies
375
+ esbuildOptions : {
376
+ plugins : [
377
+ {
378
+ name : 'angular-vite-optimize-deps' ,
379
+ setup ( build ) {
380
+ const transformer = new JavaScriptTransformer (
381
+ { sourcemap : ! ! build . initialOptions . sourcemap } ,
382
+ 1 ,
383
+ ) ;
384
+
385
+ build . onLoad ( { filter : / \. [ c m ] ? j s $ / } , async ( args ) => {
386
+ return {
387
+ contents : await transformer . transformFile ( args . path ) ,
388
+ loader : 'js' ,
389
+ } ;
390
+ } ) ;
391
+ build . onEnd ( ( ) => transformer . close ( ) ) ;
392
+ } ,
393
+ } ,
394
+ ] ,
395
+ } ,
350
396
} ,
351
397
} ;
352
398
0 commit comments