-
Notifications
You must be signed in to change notification settings - Fork 12k
Description
Command
serve
Is this a regression?
- Yes, this behavior used to work in the previous version
The previous version in which this bug was not present was
No response
Description
In a monorepo, node_modules may be located outside the Angular project root folder.
If a library from such outside node_modules tries to load any asset, e.g. a font file from a CSS file, the import is blocked by Vite's dev server with a 403 error.
Minimal Reproduction
-
Clone this repo
git clone https://github.com/maxpatiiuk/angular-monorepo-asset-serve-error cd angular-monorepo-asset-serve-error
-
Install dependencies
# To keep reproduction size minimal, I hardcoded a minimal root-level node_modules # So, install Angular dependencies only in the app folder: cd app npm install
-
Start the development server in the app folder
npm start
See this error in the browser console:
(index):14 GET http://localhost:4200/@fs/Users/.../angular-monorepo-asset-serve-error/node_modules/external-library/NotoSans.woff2 net::ERR_ABORTED 403 (Forbidden)
Exception or Error
(index):14 GET http://localhost:4200/@fs/Users/.../angular-monorepo-asset-serve-error/node_modules/external-library/NotoSans.woff2 net::ERR_ABORTED 403 (Forbidden)
Your Environment
Angular CLI: 20.2.0
Node: 22.16.0
Package Manager: npm 10.9.2
OS: darwin arm64
Angular: 20.2.1
... compiler-cli, core, platform-browser
Package Version
------------------------------------
@angular-devkit/architect 0.2002.0
@angular-devkit/core 20.2.0
@angular-devkit/schematics 20.2.0
@angular/build 20.2.0
@angular/cli 20.2.0
@schematics/angular 20.2.0
rxjs 7.8.2
typescript 5.9.2
Anything else relevant?
Explanation & Solution
If you run the dev server with Vite config logging (DEBUG=vite:config npx ng serve
), you will see that the dev server was allowed to serve only the package-level node_modules folder:
vite:config server: {
vite:config ...
vite:config fs: {
vite:config allow: [
vite:config '/Users/mak13180/site/esri/angular-monorepo-asset-serve-error/app/.angular/cache/20.2.0/reproduction/vite',
vite:config '/Users/mak13180/site/esri/angular-monorepo-asset-serve-error/app/node_modules'
vite:config ]
vite:config }
vite:config },
By default, Vite correctly detects that it is being run in a monorepo and allows serving from any monorepo node_modules, but Angular incorrectly overrides this behavior here:
fs: { | |
// Ensure cache directory, node modules, and all assets are accessible by the client. | |
// The first two are required for Vite to function in prebundling mode (the default) and to load | |
// the Vite client-side code for browser reloading. These would be available by default but when | |
// the `allow` option is explicitly configured, they must be included manually. | |
allow: [ | |
cacheDir, | |
join(serverOptions.workspaceRoot, 'node_modules'), | |
...[...assets.values()].map(({ source }) => source), | |
], | |
}, |
The code comment states These would be available by default but when the 'allow' option is explicitly configured, they must be included manually.
. However, Angular does not include things manually correctly.
Fortunately, the Vite's default behavior is easy to get back:
Their default calls searchForWorkspaceRoot()
, which is exposed by Vite and can be called manually as documented in https://vite.dev/config/server-options.html#server-fs-allow.
I confirmed that updating the Angular code to the following fixes the issue:
- join(serverOptions.workspaceRoot, 'node_modules'),
+ searchForWorkspaceRoot(serverOptions.workspaceRoot),