@@ -16,7 +16,9 @@ import { readFile } from 'node:fs/promises';
1616import type { AddressInfo } from 'node:net' ;
1717import path from 'node:path' ;
1818import { 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' ;
2022import type { Schema as BrowserBuilderOptions } from '../browser-esbuild/schema' ;
2123import { loadProxyConfiguration , normalizeProxyConfiguration } from './load-proxy-config' ;
2224import type { NormalizedDevServerOptions } from './options' ;
@@ -52,7 +54,9 @@ export async function* serveWithVite(
5254 verbose : serverOptions . verbose ,
5355 } as json . JsonObject & BrowserBuilderOptions ,
5456 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 ;
5660
5761 if ( serverOptions . servePath === undefined && browserOptions . baseHref !== undefined ) {
5862 serverOptions . servePath = browserOptions . baseHref ;
@@ -63,7 +67,9 @@ export async function* serveWithVite(
6367 const generatedFiles = new Map < string , OutputFileRecord > ( ) ;
6468 const assetFiles = new Map < string , string > ( ) ;
6569 // 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+ } ) ) {
6773 assert ( result . outputFiles , 'Builder did not provide result files.' ) ;
6874
6975 // Analyze result files for changes
@@ -96,7 +102,13 @@ export async function* serveWithVite(
96102 }
97103 } else {
98104 // 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+ ) ;
100112 server = await createServer ( serverConfiguration ) ;
101113
102114 await server . listen ( ) ;
@@ -173,10 +185,13 @@ function analyzeResultFiles(
173185 }
174186}
175187
188+ // eslint-disable-next-line max-lines-per-function
176189export async function setupServer (
177190 serverOptions : NormalizedDevServerOptions ,
178191 outputFiles : Map < string , OutputFileRecord > ,
179192 assets : Map < string , string > ,
193+ preserveSymlinks : boolean | undefined ,
194+ prebundleExclude : string [ ] | undefined ,
180195) : Promise < InlineConfig > {
181196 const proxy = await loadProxyConfiguration (
182197 serverOptions . workspaceRoot ,
@@ -199,6 +214,10 @@ export async function setupServer(
199214 devSourcemap : true ,
200215 } ,
201216 base : serverOptions . servePath ,
217+ resolve : {
218+ mainFields : [ 'es2020' , 'browser' , 'module' , 'main' ] ,
219+ preserveSymlinks,
220+ } ,
202221 server : {
203222 port : serverOptions . port ,
204223 strictPort : true ,
@@ -236,12 +255,13 @@ export async function setupServer(
236255 return ;
237256 }
238257
258+ const code = Buffer . from ( codeContents ) . toString ( 'utf-8' ) ;
239259 const mapContents = outputFiles . get ( file + '.map' ) ?. contents ;
240260
241261 return {
242262 // Remove source map URL comments from the code if a sourcemap is present.
243263 // 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 ,
245265 map : mapContents && Buffer . from ( mapContents ) . toString ( 'utf-8' ) ,
246266 } ;
247267 } ,
@@ -276,7 +296,7 @@ export async function setupServer(
276296 // Resource files are handled directly.
277297 // Global stylesheets (CSS files) are currently considered resources to workaround
278298 // dev server sourcemap issues with stylesheets.
279- if ( extension !== '.html' ) {
299+ if ( extension !== '.js' && extension !== '. html') {
280300 const outputFile = outputFiles . get ( pathname ) ;
281301 if ( outputFile ) {
282302 const mimeType = lookupMimeType ( extension ) ;
@@ -345,8 +365,34 @@ export async function setupServer(
345365 } ,
346366 ] ,
347367 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+ } ,
350396 } ,
351397 } ;
352398
0 commit comments