Skip to content

Commit 7eabe7d

Browse files
committed
refactor(@angular/build): avoid need to pre-import angular compiler package in dev server
Within the development server, the external stylesheet encapsulation logic has been adjusted to avoid needing to asynchronously import the `@angular/compiler` package within the request execution. This removes the need to pre-import the package at the start of the development server which was previously used to avoid a delay in stylesheet response on first use. The external stylesheet response execution is also now fully synchronous.
1 parent 5efcf88 commit 7eabe7d

File tree

3 files changed

+30
-23
lines changed

3 files changed

+30
-23
lines changed

packages/angular/build/src/builders/dev-server/vite-server.ts

-5
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,6 @@ export async function* serveWithVite(
139139

140140
// Enable to support component style hot reloading (`NG_HMR_CSTYLES=0` can be used to disable)
141141
browserOptions.externalRuntimeStyles = !!serverOptions.liveReload && useComponentStyleHmr;
142-
if (browserOptions.externalRuntimeStyles) {
143-
// Preload the @angular/compiler package to avoid first stylesheet request delays.
144-
// Once @angular/build is native ESM, this should be re-evaluated.
145-
void loadEsmModule('@angular/compiler');
146-
}
147142

148143
// Enable to support component template hot replacement (`NG_HMR_TEMPLATE=1` can be used to enable)
149144
browserOptions.templateUpdates = !!serverOptions.liveReload && useComponentTemplateHmr;

packages/angular/build/src/tools/vite/middlewares/assets-middleware.ts

+9-16
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
import { lookup as lookupMimeType } from 'mrmime';
1010
import { extname } from 'node:path';
1111
import type { Connect, ViteDevServer } from 'vite';
12-
import { loadEsmModule } from '../../../utils/load-esm';
1312
import { AngularMemoryOutputFiles, pathnameWithoutBasePath } from '../utils';
1413

1514
export function createAngularAssetsMiddleware(
1615
server: ViteDevServer,
1716
assets: Map<string, string>,
1817
outputFiles: AngularMemoryOutputFiles,
1918
usedComponentStyles: Map<string, Set<string>>,
19+
encapsulateStyle: (style: Uint8Array, componentId: string) => string,
2020
): Connect.NextHandleFunction {
2121
return function angularAssetsMiddleware(req, res, next) {
2222
if (req.url === undefined || res.writableEnded) {
@@ -73,7 +73,7 @@ export function createAngularAssetsMiddleware(
7373
if (extension !== '.js' && extension !== '.html') {
7474
const outputFile = outputFiles.get(pathname);
7575
if (outputFile?.servable) {
76-
const data = outputFile.contents;
76+
let data: Uint8Array | string = outputFile.contents;
7777
if (extension === '.css') {
7878
// Inject component ID for view encapsulation if requested
7979
const componentId = new URL(req.url, 'http://localhost').searchParams.get('ngcomp');
@@ -108,22 +108,15 @@ export function createAngularAssetsMiddleware(
108108
return;
109109
}
110110

111-
loadEsmModule<typeof import('@angular/compiler')>('@angular/compiler')
112-
.then((compilerModule) => {
113-
const encapsulatedData = compilerModule.encapsulateStyle(
114-
new TextDecoder().decode(data),
115-
componentId,
116-
);
111+
data = encapsulateStyle(data, componentId);
112+
}
117113

118-
res.setHeader('Content-Type', 'text/css');
119-
res.setHeader('Cache-Control', 'no-cache');
120-
res.setHeader('ETag', etag);
121-
res.end(encapsulatedData);
122-
})
123-
.catch((e) => next(e));
114+
res.setHeader('Content-Type', 'text/css');
115+
res.setHeader('Cache-Control', 'no-cache');
116+
res.setHeader('ETag', etag);
117+
res.end(data);
124118

125-
return;
126-
}
119+
return;
127120
}
128121
}
129122

packages/angular/build/src/tools/vite/plugins/setup-middlewares-plugin.ts

+21-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
import type { Connect, Plugin } from 'vite';
10+
import { loadEsmModule } from '../../../utils/load-esm';
1011
import {
1112
angularHtmlFallbackMiddleware,
1213
createAngularAssetsMiddleware,
@@ -53,13 +54,25 @@ interface AngularSetupMiddlewaresPluginOptions {
5354
ssrMode: ServerSsrMode;
5455
}
5556

57+
async function createEncapsulateStyle(): Promise<
58+
(style: Uint8Array, componentId: string) => string
59+
> {
60+
const { encapsulateStyle } =
61+
await loadEsmModule<typeof import('@angular/compiler')>('@angular/compiler');
62+
const decoder = new TextDecoder('utf-8');
63+
64+
return (style, componentId) => {
65+
return encapsulateStyle(decoder.decode(style), componentId);
66+
};
67+
}
68+
5669
export function createAngularSetupMiddlewaresPlugin(
5770
options: AngularSetupMiddlewaresPluginOptions,
5871
): Plugin {
5972
return {
6073
name: 'vite:angular-setup-middlewares',
6174
enforce: 'pre',
62-
configureServer(server) {
75+
async configureServer(server) {
6376
const {
6477
indexHtmlTransformer,
6578
outputFiles,
@@ -74,7 +87,13 @@ export function createAngularSetupMiddlewaresPlugin(
7487
server.middlewares.use(createAngularHeadersMiddleware(server));
7588
server.middlewares.use(createAngularComponentMiddleware(templateUpdates));
7689
server.middlewares.use(
77-
createAngularAssetsMiddleware(server, assets, outputFiles, usedComponentStyles),
90+
createAngularAssetsMiddleware(
91+
server,
92+
assets,
93+
outputFiles,
94+
usedComponentStyles,
95+
await createEncapsulateStyle(),
96+
),
7897
);
7998

8099
extensionMiddleware?.forEach((middleware) => server.middlewares.use(middleware));

0 commit comments

Comments
 (0)