Skip to content

Commit fc41f50

Browse files
committed
fix(@angular/build): show error when Node.js built-ins are used during ng serve
This commit ensures consistent behavior between `ng build` and `ng serve`. Previously, `ng serve` did not display an error message when Node.js built-in modules were included in browser bundles. By default, Vite replaces Node.js built-ins with empty modules, which can lead to unexpected runtime issues. This update addresses the problem by surfacing clear error messages, providing better developer feedback and alignment between the two commands. Closes: #27425 (cherry picked from commit 06f478b)
1 parent 14451e2 commit fc41f50

File tree

3 files changed

+59
-21
lines changed

3 files changed

+59
-21
lines changed

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

+20
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,26 @@ function getDepOptimizationConfig({
819819
thirdPartySourcemaps: boolean;
820820
}): DepOptimizationConfig {
821821
const plugins: ViteEsBuildPlugin[] = [
822+
{
823+
name: 'angular-browser-node-built-in',
824+
setup(build) {
825+
// This namespace is configured by vite.
826+
// @see: https://github.com/vitejs/vite/blob/a1dd396da856401a12c921d0cd2c4e97cb63f1b5/packages/vite/src/node/optimizer/esbuildDepPlugin.ts#L109
827+
build.onLoad({ filter: /.*/, namespace: 'browser-external' }, (args) => {
828+
if (!isBuiltin(args.path)) {
829+
return;
830+
}
831+
832+
return {
833+
errors: [
834+
{
835+
text: `The package "${args.path}" wasn't found on the file system but is built into node.`,
836+
},
837+
],
838+
};
839+
});
840+
},
841+
},
822842
{
823843
name: `angular-vite-optimize-deps${ssr ? '-ssr' : ''}${
824844
thirdPartySourcemaps ? '-vendor-sourcemap' : ''
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import assert from 'node:assert';
2+
import { execAndWaitForOutputToMatch, ng } from '../../utils/process';
3+
import { writeFile } from '../../utils/fs';
4+
import { getGlobalVariable } from '../../utils/env';
5+
6+
export default async function () {
7+
assert(
8+
getGlobalVariable('argv')['esbuild'],
9+
'This test should not be called in the Webpack suite.',
10+
);
11+
12+
await ng('cache', 'clean');
13+
await ng('cache', 'on');
14+
15+
await writeFile('src/main.ts', `import '@angular-devkit/core/node';`);
16+
17+
const { stderr } = await execAndWaitForOutputToMatch('ng', ['serve'], /ERROR.+node:path/, {
18+
CI: '0',
19+
NO_COLOR: 'true',
20+
});
21+
22+
assert.match(
23+
stderr,
24+
/The package "node:path" wasn't found on the file system but is built into node/,
25+
);
26+
}
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,35 @@
11
import assert from 'node:assert';
2+
import { setTimeout } from 'node:timers/promises';
23
import { findFreePort } from '../../utils/network';
3-
import {
4-
execAndWaitForOutputToMatch,
5-
killAllProcesses,
6-
ng,
7-
waitForAnyProcessOutputToMatch,
8-
} from '../../utils/process';
4+
import { execAndWaitForOutputToMatch, killAllProcesses, ng } from '../../utils/process';
95

106
export default async function () {
117
await ng('cache', 'clean');
128
await ng('cache', 'on');
139

1410
const port = await findFreePort();
1511

16-
// Make sure serve is consistent with build
17-
await execAndWaitForOutputToMatch(
18-
'ng',
19-
['serve', '--port', `${port}`],
20-
/Dependencies bundled/,
21-
// Use CI:0 to force caching
22-
{ DEBUG: 'vite:deps', CI: '0' },
23-
);
12+
const [, response] = await Promise.all([
13+
execAndWaitForOutputToMatch(
14+
'ng',
15+
['serve', '--port', `${port}`],
16+
/dependencies optimized/,
17+
// Use CI:0 to force caching
18+
{ DEBUG: 'vite:deps', CI: '0', NO_COLOR: 'true' },
19+
),
20+
setTimeout(4_000).then(() => fetch(`http://localhost:${port}/main.js`)),
21+
]);
2422

25-
// Make request so that vite writes the cache.
26-
const response = await fetch(`http://localhost:${port}/main.js`);
2723
assert(response.ok, `Expected 'response.ok' to be 'true'.`);
2824

29-
// Wait for vite to write to FS and stablize.
30-
await waitForAnyProcessOutputToMatch(/dependencies optimized/, 5000);
31-
3225
// Terminate the dev-server
3326
await killAllProcesses();
3427

35-
// The Node.js specific module should not be found
3628
await execAndWaitForOutputToMatch(
3729
'ng',
3830
['serve', '--port=0'],
3931
/Hash is consistent\. Skipping/,
4032
// Use CI:0 to force caching
41-
{ DEBUG: 'vite:deps', CI: '0' },
33+
{ DEBUG: 'vite:deps', CI: '0', NO_COLOR: 'true' },
4234
);
4335
}

0 commit comments

Comments
 (0)