Skip to content

fix(@angular/build): allow serving node_modules assets in monorepo setups#32939

Open
maruthang wants to merge 1 commit intoangular:mainfrom
maruthang:fix-31016-monorepo-assets
Open

fix(@angular/build): allow serving node_modules assets in monorepo setups#32939
maruthang wants to merge 1 commit intoangular:mainfrom
maruthang:fix-31016-monorepo-assets

Conversation

@maruthang
Copy link
Copy Markdown
Contributor

PR Checklist

PR Type

  • Bugfix

What is the current behavior?

In monorepo setups where node_modules are hoisted to a parent directory above the Angular workspace root, assets loaded from those packages (e.g., font files referenced in CSS from a library in root node_modules) are blocked by Vite's dev server with a 403 Forbidden error.

This happens because Angular explicitly sets server.fs.allow, which overrides Vite's default package root auto-detection. The explicit list only includes {workspaceRoot}/node_modules, missing the monorepo root's node_modules.

Issue Number: #31016

What is the new behavior?

Uses Vite's built-in searchForPackageRoot() to find the actual package installation root (which traverses up from the workspace root to find the nearest directory with package.json + node_modules). This directory is added to fs.allow, allowing access to hoisted node_modules in monorepo setups.

From Vite docs:

When server.fs.allow is set, the auto workspace root detection will be disabled. To extend the original behavior, a utility searchForPackageRoot is exposed.

Does this PR introduce a breaking change?

  • Yes
  • No

…tups

In monorepo setups where node_modules are hoisted to a parent directory
above the Angular workspace root, assets loaded from those packages
(e.g., fonts from CSS files) were blocked by Vite's dev server with a
403 error.

This was caused by the explicit `server.fs.allow` configuration only
including the workspace root's `node_modules`, which overrides Vite's
default package root detection. By adding `searchForPackageRoot()` to
the allow list, the monorepo root directory is included, allowing access
to hoisted node_modules.

Fixes angular#31016
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the Vite dev server configuration to include the package root in the allowed file system paths, improving support for monorepo setups where dependencies might be hoisted. The review feedback recommends maintaining the project's lazy-loading pattern by using dynamic imports for Vite runtime utilities instead of a top-level import and identifies a redundant path entry that can be removed.

import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
import type { Connect, InlineConfig, SSROptions, ServerOptions } from 'vite';
import { type Connect, type InlineConfig, type SSROptions, type ServerOptions, searchForPackageRoot } from 'vite';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This change introduces a top-level runtime import of vite. The existing code in this file follows a pattern of using dynamic imports for Vite's runtime utilities (see line 152) to avoid eagerly loading the vite package when the module is first evaluated. To maintain this pattern, searchForPackageRoot should be imported dynamically where it is used, keeping this import as type-only.

Suggested change
import { type Connect, type InlineConfig, type SSROptions, type ServerOptions, searchForPackageRoot } from 'vite';
import type { Connect, InlineConfig, SSROptions, ServerOptions } from 'vite';

Comment on lines 82 to +83
join(serverOptions.workspaceRoot, 'node_modules'),
searchForPackageRoot(serverOptions.workspaceRoot),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The entry join(serverOptions.workspaceRoot, 'node_modules') is redundant because searchForPackageRoot(serverOptions.workspaceRoot) will always return either the workspaceRoot itself or one of its parent directories. In either case, the local node_modules directory will be covered by the allowed package root. Additionally, using a dynamic import here maintains the lazy-loading pattern for Vite runtime dependencies used elsewhere in this file.

Suggested change
join(serverOptions.workspaceRoot, 'node_modules'),
searchForPackageRoot(serverOptions.workspaceRoot),
(await import('vite')).searchForPackageRoot(serverOptions.workspaceRoot),

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant