Skip to content

Commit 26c67f9

Browse files
clydinangular-robot[bot]
authored andcommitted
fix(@angular-devkit/build-angular): ensure all build resources are served in esbuild dev server
Previously when using the esbuild-based browser application builder with the new dev server, resource files referenced via stylesheets may not have been served by the development server. The development server has now been adjusted to properly prioritize and serve files that were generated during the build process. Global stylesheets are also currently considered resource files as well to workaround issues with development sourcemaps within the development server itself. Global stylesheets are already fully processed by the build system prior to being passed to the development server.
1 parent 587c4d0 commit 26c67f9

File tree

5 files changed

+62
-15
lines changed

5 files changed

+62
-15
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@
172172
"loader-utils": "3.2.1",
173173
"magic-string": "0.30.0",
174174
"mini-css-extract-plugin": "2.7.5",
175+
"mrmime": "1.0.1",
175176
"ng-packagr": "16.0.0-next.2",
176177
"node-fetch": "^2.2.0",
177178
"npm": "^8.11.0",

packages/angular_devkit/build_angular/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ ts_library(
157157
"@npm//loader-utils",
158158
"@npm//magic-string",
159159
"@npm//mini-css-extract-plugin",
160+
"@npm//mrmime",
160161
"@npm//ng-packagr",
161162
"@npm//open",
162163
"@npm//ora",

packages/angular_devkit/build_angular/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"loader-utils": "3.2.1",
4646
"magic-string": "0.30.0",
4747
"mini-css-extract-plugin": "2.7.5",
48+
"mrmime": "1.0.1",
4849
"open": "8.4.2",
4950
"ora": "5.4.1",
5051
"parse5-html-rewriting-stream": "7.0.0",

packages/angular_devkit/build_angular/src/builders/dev-server/vite-server.ts

+54-15
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import type { BuilderContext } from '@angular-devkit/architect';
1010
import type { json } from '@angular-devkit/core';
11+
import { lookup as lookupMimeType } from 'mrmime';
1112
import assert from 'node:assert';
1213
import { BinaryLike, createHash } from 'node:crypto';
1314
import { readFile } from 'node:fs/promises';
@@ -21,7 +22,7 @@ import type { NormalizedDevServerOptions } from './options';
2122
import type { DevServerBuilderOutput } from './webpack-server';
2223

2324
interface OutputFileRecord {
24-
text: string;
25+
contents: Uint8Array;
2526
size: number;
2627
hash?: Buffer;
2728
updated: boolean;
@@ -69,7 +70,7 @@ export async function* serveWithVite(
6970
// Skip analysis of sourcemaps
7071
if (filePath.endsWith('.map')) {
7172
outputFiles.set(filePath, {
72-
text: file.text,
73+
contents: file.contents,
7374
size: file.contents.byteLength,
7475
updated: false,
7576
});
@@ -82,7 +83,7 @@ export async function* serveWithVite(
8283
if (existingRecord && existingRecord.size === file.contents.byteLength) {
8384
// Only hash existing file when needed
8485
if (existingRecord.hash === undefined) {
85-
existingRecord.hash = hashContent(existingRecord.text);
86+
existingRecord.hash = hashContent(existingRecord.contents);
8687
}
8788

8889
// Compare against latest result output
@@ -95,7 +96,7 @@ export async function* serveWithVite(
9596
}
9697

9798
outputFiles.set(filePath, {
98-
text: file.text,
99+
contents: file.contents,
99100
size: file.contents.byteLength,
100101
hash: fileHash,
101102
updated: true,
@@ -213,25 +214,59 @@ async function setupServer(
213214
},
214215
load(id) {
215216
const [file] = id.split('?', 1);
216-
const code = outputFiles.get(file)?.text;
217+
const code = outputFiles.get(file)?.contents;
218+
const map = outputFiles.get(file + '.map')?.contents;
217219

218220
return (
219221
code && {
220-
code,
221-
map: outputFiles.get(file + '.map')?.text,
222+
code: code && Buffer.from(code).toString('utf-8'),
223+
map: map && Buffer.from(map).toString('utf-8'),
222224
}
223225
);
224226
},
225227
configureServer(server) {
226-
// Assets get handled first
228+
// Assets and resources get handled first
227229
server.middlewares.use(function angularAssetsMiddleware(req, res, next) {
228-
if (req.url) {
229-
// Rewrite all build assets to a vite raw fs URL
230-
const assetSource = assets.get(req.url);
231-
if (assetSource !== undefined) {
232-
req.url = `/@fs/${assetSource}`;
230+
if (req.url === undefined || res.writableEnded) {
231+
return;
232+
}
233+
234+
// Parse the incoming request.
235+
// The base of the URL is unused but required to parse the URL.
236+
const parsedUrl = new URL(req.url, 'http://localhost');
237+
const extension = path.extname(parsedUrl.pathname);
238+
239+
// Rewrite all build assets to a vite raw fs URL
240+
const assetSourcePath = assets.get(parsedUrl.pathname);
241+
if (assetSourcePath !== undefined) {
242+
req.url = `/@fs/${assetSourcePath}`;
243+
next();
244+
245+
return;
246+
}
247+
248+
// Resource files are handled directly.
249+
// Global stylesheets (CSS files) are currently considered resources to workaround
250+
// dev server sourcemap issues with stylesheets.
251+
if (extension !== '.js' && extension !== '.html') {
252+
const outputFile = outputFiles.get(parsedUrl.pathname);
253+
if (outputFile) {
254+
const mimeType = lookupMimeType(extension);
255+
if (mimeType) {
256+
res.setHeader('Content-Type', mimeType);
257+
}
258+
res.setHeader('Cache-Control', 'no-cache');
259+
if (serverOptions.headers) {
260+
Object.entries(serverOptions.headers).forEach(([name, value]) =>
261+
res.setHeader(name, value),
262+
);
263+
}
264+
res.end(outputFile.contents);
265+
266+
return;
233267
}
234268
}
269+
235270
next();
236271
});
237272

@@ -240,10 +275,14 @@ async function setupServer(
240275
return () =>
241276
server.middlewares.use(function angularIndexMiddleware(req, res, next) {
242277
if (req.url === '/' || req.url === `/index.html`) {
243-
const rawHtml = outputFiles.get('/index.html')?.text;
278+
const rawHtml = outputFiles.get('/index.html')?.contents;
244279
if (rawHtml) {
245280
server
246-
.transformIndexHtml(req.url, rawHtml, req.originalUrl)
281+
.transformIndexHtml(
282+
req.url,
283+
Buffer.from(rawHtml).toString('utf-8'),
284+
req.originalUrl,
285+
)
247286
.then((processedHtml) => {
248287
res.setHeader('Content-Type', 'text/html');
249288
res.setHeader('Cache-Control', 'no-cache');

yarn.lock

+5
Original file line numberDiff line numberDiff line change
@@ -8617,6 +8617,11 @@ mkdirp@^0.5.1, mkdirp@^0.5.5, mkdirp@~0.5.1:
86178617
dependencies:
86188618
minimist "^1.2.6"
86198619

8620+
8621+
version "1.0.1"
8622+
resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27"
8623+
integrity sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==
8624+
86208625
86218626
version "2.0.0"
86228627
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"

0 commit comments

Comments
 (0)