diff --git a/.github/workflows/assistant-to-the-branch-manager.yml b/.github/workflows/assistant-to-the-branch-manager.yml
index 29e6de006939..3055c0110d81 100644
--- a/.github/workflows/assistant-to-the-branch-manager.yml
+++ b/.github/workflows/assistant-to-the-branch-manager.yml
@@ -16,6 +16,6 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- - uses: angular/dev-infra/github-actions/branch-manager@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ - uses: angular/dev-infra/github-actions/branch-manager@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 246717c86bea..06e036f588ab 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Generate JSON schema types
@@ -42,11 +42,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/setup@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Build release targets
@@ -56,11 +56,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/setup@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Run module and package tests
@@ -90,13 +90,13 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/setup@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Run CLI E2E tests
run: yarn bazel test --define=E2E_SHARD_TOTAL=6 --define=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests/legacy-cli:e2e.${{ matrix.subset }}_node${{ matrix.node }}
@@ -111,13 +111,13 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/setup@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Run CLI E2E tests
run: yarn bazel test --define=E2E_SHARD_TOTAL=3 --define=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests/legacy-cli:e2e.${{ matrix.subset }}_node${{ matrix.node }}
@@ -132,13 +132,13 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/setup@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Run CLI E2E tests
run: yarn bazel test --define=E2E_SHARD_TOTAL=6 --define=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests/legacy-cli:e2e.snapshots.${{ matrix.subset }}_node${{ matrix.node }}
@@ -149,13 +149,13 @@ jobs:
SAUCE_TUNNEL_IDENTIFIER: angular-cli-${{ github.workflow }}-${{ github.run_number }}
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/setup@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Run E2E Browser tests
env:
SAUCE_USERNAME: ${{ vars.SAUCE_USERNAME }}
@@ -182,11 +182,11 @@ jobs:
CIRCLE_BRANCH: ${{ github.ref_name }}
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/setup@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- run: yarn admin snapshots --verbose
env:
SNAPSHOT_BUILDS_GITHUB_TOKEN: ${{ secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN }}
diff --git a/.github/workflows/dev-infra.yml b/.github/workflows/dev-infra.yml
index 453ce0f4e046..6c3ae6858ebd 100644
--- a/.github/workflows/dev-infra.yml
+++ b/.github/workflows/dev-infra.yml
@@ -13,13 +13,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- - uses: angular/dev-infra/github-actions/commit-message-based-labels@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ - uses: angular/dev-infra/github-actions/commit-message-based-labels@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
post_approval_changes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- - uses: angular/dev-infra/github-actions/post-approval-changes@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ - uses: angular/dev-infra/github-actions/post-approval-changes@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
diff --git a/.github/workflows/feature-requests.yml b/.github/workflows/feature-requests.yml
index abc0ac2342c1..3852df5a0944 100644
--- a/.github/workflows/feature-requests.yml
+++ b/.github/workflows/feature-requests.yml
@@ -16,6 +16,6 @@ jobs:
if: github.repository == 'angular/angular-cli'
runs-on: ubuntu-latest
steps:
- - uses: angular/dev-infra/github-actions/feature-request@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ - uses: angular/dev-infra/github-actions/feature-request@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 507ad62ac402..cf7f1a4623f8 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -34,7 +34,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup ESLint Caching
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2
with:
@@ -54,7 +54,7 @@ jobs:
- name: Run Validation
run: yarn admin validate
- name: Check Package Licenses
- uses: angular/dev-infra/github-actions/linting/licenses@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/linting/licenses@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Check tooling setup
run: yarn check-tooling-setup
- name: Check commit message
@@ -70,11 +70,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/setup@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Build release targets
@@ -90,11 +90,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/setup@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Run module and package tests
@@ -111,13 +111,13 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/setup@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Run CLI E2E tests
run: yarn bazel test --define=E2E_SHARD_TOTAL=6 --define=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests/legacy-cli:e2e.${{ matrix.subset }}_node${{ matrix.node }}
@@ -125,13 +125,13 @@ jobs:
runs-on: windows-latest
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/setup@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Run CLI E2E tests
run: yarn bazel test --config=e2e //tests/legacy-cli:e2e_node22 --test_filter="tests/basic/{build,rebuild}.ts" --test_arg="--esbuild"
@@ -146,13 +146,13 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/setup@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Run CLI E2E tests
run: yarn bazel test --define=E2E_SHARD_TOTAL=3 --define=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests/legacy-cli:e2e.${{ matrix.subset }}_node${{ matrix.node }}
@@ -169,12 +169,12 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Initialize environment
- uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Install node modules
run: yarn install --immutable
- name: Setup Bazel
- uses: angular/dev-infra/github-actions/bazel/setup@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/setup@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Setup Bazel RBE
- uses: angular/dev-infra/github-actions/bazel/configure-remote@910c72bbcc1bf1ae2b22c48d41b2f0e8eeda520d
+ uses: angular/dev-infra/github-actions/bazel/configure-remote@40b2cbdbcc40f36f125d721c4e8decd3bb607ea4
- name: Run CLI E2E tests
run: yarn bazel test --define=E2E_SHARD_TOTAL=6 --define=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests/legacy-cli:e2e.snapshots.${{ matrix.subset }}_node${{ matrix.node }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index da2956126e41..b76036b7062d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,22 @@
+
+
+# 19.0.4 (2024-12-05)
+
+### @angular-devkit/build-angular
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------ |
+| [23667ed4a](https://github.com/angular/angular-cli/commit/23667ed4aa0bedbb591dc0284116402dc42ed95c) | fix | handle windows spec collisions |
+
+### @angular/build
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------ |
+| [fc41f50b5](https://github.com/angular/angular-cli/commit/fc41f50b53bbffead017b420105eed5bd8573ac1) | fix | show error when Node.js built-ins are used during `ng serve` |
+| [14451e275](https://github.com/angular/angular-cli/commit/14451e2754caff2c9800cca17e11ffa452575f09) | perf | reuse TS package.json cache when rebuilding |
+
+
+
# 19.0.3 (2024-12-04)
diff --git a/package.json b/package.json
index 8cbc0d2f8232..dab9a724d525 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@angular/devkit-repo",
- "version": "19.0.3",
+ "version": "19.0.4",
"private": true,
"description": "Software Development Kit for Angular",
"keywords": [
diff --git a/packages/angular/build/src/builders/dev-server/vite-server.ts b/packages/angular/build/src/builders/dev-server/vite-server.ts
index dfbbc8454b53..832002953fc1 100644
--- a/packages/angular/build/src/builders/dev-server/vite-server.ts
+++ b/packages/angular/build/src/builders/dev-server/vite-server.ts
@@ -819,6 +819,26 @@ function getDepOptimizationConfig({
thirdPartySourcemaps: boolean;
}): DepOptimizationConfig {
const plugins: ViteEsBuildPlugin[] = [
+ {
+ name: 'angular-browser-node-built-in',
+ setup(build) {
+ // This namespace is configured by vite.
+ // @see: https://github.com/vitejs/vite/blob/a1dd396da856401a12c921d0cd2c4e97cb63f1b5/packages/vite/src/node/optimizer/esbuildDepPlugin.ts#L109
+ build.onLoad({ filter: /.*/, namespace: 'browser-external' }, (args) => {
+ if (!isBuiltin(args.path)) {
+ return;
+ }
+
+ return {
+ errors: [
+ {
+ text: `The package "${args.path}" wasn't found on the file system but is built into node.`,
+ },
+ ],
+ };
+ });
+ },
+ },
{
name: `angular-vite-optimize-deps${ssr ? '-ssr' : ''}${
thirdPartySourcemaps ? '-vendor-sourcemap' : ''
diff --git a/packages/angular/build/src/tools/angular/angular-host.ts b/packages/angular/build/src/tools/angular/angular-host.ts
index 1750002f1cdd..103b3e37ac68 100644
--- a/packages/angular/build/src/tools/angular/angular-host.ts
+++ b/packages/angular/build/src/tools/angular/angular-host.ts
@@ -164,6 +164,7 @@ export function createAngularCompilerHost(
typescript: typeof ts,
compilerOptions: AngularCompilerOptions,
hostOptions: AngularHostOptions,
+ packageJsonCache: ts.PackageJsonInfoCache | undefined,
): AngularCompilerHost {
// Create TypeScript compiler host
const host: AngularCompilerHost = typescript.createIncrementalCompilerHost(compilerOptions);
@@ -229,16 +230,17 @@ export function createAngularCompilerHost(
return hostOptions.modifiedFiles;
};
+ // Provide a resolution cache to ensure package.json lookups are cached
+ const resolutionCache = typescript.createModuleResolutionCache(
+ host.getCurrentDirectory(),
+ host.getCanonicalFileName.bind(host),
+ compilerOptions,
+ packageJsonCache,
+ );
+ host.getModuleResolutionCache = () => resolutionCache;
+
// Augment TypeScript Host for file replacements option
if (hostOptions.fileReplacements) {
- // Provide a resolution cache since overriding resolution prevents automatic creation
- const resolutionCache = typescript.createModuleResolutionCache(
- host.getCurrentDirectory(),
- host.getCanonicalFileName.bind(host),
- compilerOptions,
- );
- host.getModuleResolutionCache = () => resolutionCache;
-
augmentHostWithReplacements(typescript, host, hostOptions.fileReplacements, resolutionCache);
}
diff --git a/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts b/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts
index 787c82b4127e..71077b87ab99 100644
--- a/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts
+++ b/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts
@@ -66,20 +66,36 @@ export class AotCompilation extends AngularCompilation {
hostOptions.externalStylesheets ??= new Map();
}
- // Collect stale source files for HMR analysis of inline component resources
+ // Reuse the package.json cache from the previous compilation
+ const packageJsonCache = this.#state?.compilerHost
+ .getModuleResolutionCache?.()
+ ?.getPackageJsonInfoCache();
+
+ const useHmr = compilerOptions['_enableHmr'];
+
let staleSourceFiles;
- if (compilerOptions['_enableHmr'] && hostOptions.modifiedFiles && this.#state) {
+ let clearPackageJsonCache = false;
+ if (hostOptions.modifiedFiles && this.#state) {
for (const modifiedFile of hostOptions.modifiedFiles) {
- const sourceFile = this.#state.typeScriptProgram.getSourceFile(modifiedFile);
- if (sourceFile) {
- staleSourceFiles ??= new Map();
- staleSourceFiles.set(modifiedFile, sourceFile);
+ // Clear package.json cache if a node modules file was modified
+ if (!clearPackageJsonCache && modifiedFile.includes('node_modules')) {
+ clearPackageJsonCache = true;
+ packageJsonCache?.clear();
+ }
+
+ // Collect stale source files for HMR analysis of inline component resources
+ if (useHmr) {
+ const sourceFile = this.#state.typeScriptProgram.getSourceFile(modifiedFile);
+ if (sourceFile) {
+ staleSourceFiles ??= new Map();
+ staleSourceFiles.set(modifiedFile, sourceFile);
+ }
}
}
}
// Create Angular compiler host
- const host = createAngularCompilerHost(ts, compilerOptions, hostOptions);
+ const host = createAngularCompilerHost(ts, compilerOptions, hostOptions, packageJsonCache);
// Create the Angular specific program that contains the Angular compiler
const angularProgram = profileSync(
diff --git a/packages/angular/build/src/tools/angular/compilation/jit-compilation.ts b/packages/angular/build/src/tools/angular/compilation/jit-compilation.ts
index eab21a8608c5..db2de81b4ae7 100644
--- a/packages/angular/build/src/tools/angular/compilation/jit-compilation.ts
+++ b/packages/angular/build/src/tools/angular/compilation/jit-compilation.ts
@@ -53,7 +53,7 @@ export class JitCompilation extends AngularCompilation {
compilerOptionsTransformer?.(originalCompilerOptions) ?? originalCompilerOptions;
// Create Angular compiler host
- const host = createAngularCompilerHost(ts, compilerOptions, hostOptions);
+ const host = createAngularCompilerHost(ts, compilerOptions, hostOptions, undefined);
// Create the TypeScript Program
const typeScriptProgram = profileSync('TS_CREATE_PROGRAM', () =>
diff --git a/packages/angular/ssr/src/routes/route-config.ts b/packages/angular/ssr/src/routes/route-config.ts
index c6e651aa43f4..a60a3ed3619a 100644
--- a/packages/angular/ssr/src/routes/route-config.ts
+++ b/packages/angular/ssr/src/routes/route-config.ts
@@ -203,8 +203,6 @@ export const SERVER_ROUTES_CONFIG = new InjectionToken('SERV
* @param options - (Optional) An object containing additional configuration options for server routes.
* @returns An `EnvironmentProviders` instance with the server routes configuration.
*
- * @returns An `EnvironmentProviders` object that contains the server routes configuration.
- *
* @see {@link ServerRoute}
* @see {@link ServerRoutesConfigOptions}
* @developerPreview
diff --git a/packages/angular_devkit/build_angular/src/builders/karma/application_builder.ts b/packages/angular_devkit/build_angular/src/builders/karma/application_builder.ts
index 4560d0cff952..ff4604c7c91e 100644
--- a/packages/angular_devkit/build_angular/src/builders/karma/application_builder.ts
+++ b/packages/angular_devkit/build_angular/src/builders/karma/application_builder.ts
@@ -26,7 +26,7 @@ import { Observable, Subscriber, catchError, defaultIfEmpty, from, of, switchMap
import { Configuration } from 'webpack';
import { ExecutionTransformer } from '../../transforms';
import { OutputHashing } from '../browser-esbuild/schema';
-import { findTests } from './find-tests';
+import { findTests, getTestEntrypoints } from './find-tests';
import { Schema as KarmaBuilderOptions } from './schema';
interface BuildOptions extends ApplicationBuilderInternalOptions {
@@ -268,28 +268,7 @@ async function collectEntrypoints(
projectSourceRoot,
);
- const seen = new Set();
-
- return new Map(
- Array.from(testFiles, (testFile) => {
- const relativePath = path
- .relative(
- testFile.startsWith(projectSourceRoot) ? projectSourceRoot : context.workspaceRoot,
- testFile,
- )
- .replace(/^[./]+/, '_')
- .replace(/\//g, '-');
- let uniqueName = `spec-${path.basename(relativePath, path.extname(relativePath))}`;
- let suffix = 2;
- while (seen.has(uniqueName)) {
- uniqueName = `${relativePath}-${suffix}`;
- ++suffix;
- }
- seen.add(uniqueName);
-
- return [uniqueName, testFile];
- }),
- );
+ return getTestEntrypoints(testFiles, { projectSourceRoot, workspaceRoot: context.workspaceRoot });
}
async function initializeApplication(
diff --git a/packages/angular_devkit/build_angular/src/builders/karma/find-tests.ts b/packages/angular_devkit/build_angular/src/builders/karma/find-tests.ts
index 80571870e3b2..077a938e0df5 100644
--- a/packages/angular_devkit/build_angular/src/builders/karma/find-tests.ts
+++ b/packages/angular_devkit/build_angular/src/builders/karma/find-tests.ts
@@ -26,6 +26,39 @@ export async function findTests(
return [...new Set(files.flat())];
}
+interface TestEntrypointsOptions {
+ projectSourceRoot: string;
+ workspaceRoot: string;
+}
+
+/** Generate unique bundle names for a set of test files. */
+export function getTestEntrypoints(
+ testFiles: string[],
+ { projectSourceRoot, workspaceRoot }: TestEntrypointsOptions,
+): Map {
+ const seen = new Set();
+
+ return new Map(
+ Array.from(testFiles, (testFile) => {
+ const relativePath = removeRoots(testFile, [projectSourceRoot, workspaceRoot])
+ // Strip leading dots and path separators.
+ .replace(/^[./\\]+/, '')
+ // Replace any path separators with dashes.
+ .replace(/[/\\]/g, '-');
+ const baseName = `spec-${basename(relativePath, extname(relativePath))}`;
+ let uniqueName = baseName;
+ let suffix = 2;
+ while (seen.has(uniqueName)) {
+ uniqueName = `${baseName}-${suffix}`.replace(/([^\w](?:spec|test))-([\d]+)$/, '-$2$1');
+ ++suffix;
+ }
+ seen.add(uniqueName);
+
+ return [uniqueName, testFile];
+ }),
+ );
+}
+
const normalizePath = (path: string): string => path.replace(/\\/g, '/');
const removeLeadingSlash = (pattern: string): string => {
@@ -44,6 +77,16 @@ const removeRelativeRoot = (path: string, root: string): string => {
return path;
};
+function removeRoots(path: string, roots: string[]): string {
+ for (const root of roots) {
+ if (path.startsWith(root)) {
+ return path.substring(root.length);
+ }
+ }
+
+ return basename(path);
+}
+
async function findMatchingTests(
pattern: string,
ignore: string[],
diff --git a/packages/angular_devkit/build_angular/src/builders/karma/find-tests_spec.ts b/packages/angular_devkit/build_angular/src/builders/karma/find-tests_spec.ts
new file mode 100644
index 000000000000..8264539ae9dd
--- /dev/null
+++ b/packages/angular_devkit/build_angular/src/builders/karma/find-tests_spec.ts
@@ -0,0 +1,67 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.dev/license
+ */
+
+import { getTestEntrypoints } from './find-tests';
+
+const UNIX_ENTRYPOINTS_OPTIONS = {
+ pathSeparator: '/',
+ workspaceRoot: '/my/workspace/root',
+ projectSourceRoot: '/my/workspace/root/src-root',
+};
+
+const WINDOWS_ENTRYPOINTS_OPTIONS = {
+ pathSeparator: '\\',
+ workspaceRoot: 'C:\\my\\workspace\\root',
+ projectSourceRoot: 'C:\\my\\workspace\\root\\src-root',
+};
+
+describe('getTestEntrypoints', () => {
+ for (const options of [UNIX_ENTRYPOINTS_OPTIONS, WINDOWS_ENTRYPOINTS_OPTIONS]) {
+ describe(`with path separator "${options.pathSeparator}"`, () => {
+ function joinWithSeparator(base: string, rel: string) {
+ return `${base}${options.pathSeparator}${rel.replace(/\//g, options.pathSeparator)}`;
+ }
+
+ function getEntrypoints(workspaceRelative: string[], sourceRootRelative: string[] = []) {
+ return getTestEntrypoints(
+ [
+ ...workspaceRelative.map((p) => joinWithSeparator(options.workspaceRoot, p)),
+ ...sourceRootRelative.map((p) => joinWithSeparator(options.projectSourceRoot, p)),
+ ],
+ options,
+ );
+ }
+
+ it('returns an empty map without test files', () => {
+ expect(getEntrypoints([])).toEqual(new Map());
+ });
+
+ it('strips workspace root and/or project source root', () => {
+ expect(getEntrypoints(['a/b.spec.js'], ['c/d.spec.js'])).toEqual(
+ new Map([
+ ['spec-a-b.spec', joinWithSeparator(options.workspaceRoot, 'a/b.spec.js')],
+ ['spec-c-d.spec', joinWithSeparator(options.projectSourceRoot, 'c/d.spec.js')],
+ ]),
+ );
+ });
+
+ it('adds unique prefixes to distinguish between similar names', () => {
+ expect(getEntrypoints(['a/b/c/d.spec.js', 'a-b/c/d.spec.js'], ['a/b-c/d.spec.js'])).toEqual(
+ new Map([
+ ['spec-a-b-c-d.spec', joinWithSeparator(options.workspaceRoot, 'a/b/c/d.spec.js')],
+ ['spec-a-b-c-d-2.spec', joinWithSeparator(options.workspaceRoot, 'a-b/c/d.spec.js')],
+ [
+ 'spec-a-b-c-d-3.spec',
+ joinWithSeparator(options.projectSourceRoot, 'a/b-c/d.spec.js'),
+ ],
+ ]),
+ );
+ });
+ });
+ }
+});
diff --git a/packages/angular_devkit/build_angular/src/builders/karma/tests/behavior/specs_spec.ts b/packages/angular_devkit/build_angular/src/builders/karma/tests/behavior/specs_spec.ts
index 773f113bec83..5cb56abe9b9d 100644
--- a/packages/angular_devkit/build_angular/src/builders/karma/tests/behavior/specs_spec.ts
+++ b/packages/angular_devkit/build_angular/src/builders/karma/tests/behavior/specs_spec.ts
@@ -24,7 +24,9 @@ describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget, isApp)
// src/app/app.component.spec.ts conflicts with this one:
await harness.writeFiles({
- [`src/app/a/${collidingBasename}`]: `/** Success! */`,
+ [`src/app/a/foo-bar/${collidingBasename}`]: `/** Success! */`,
+ [`src/app/a-foo/bar/${collidingBasename}`]: `/** Success! */`,
+ [`src/app/a-foo-bar/${collidingBasename}`]: `/** Success! */`,
[`src/app/b/${collidingBasename}`]: `/** Success! */`,
});
@@ -36,7 +38,9 @@ describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget, isApp)
const bundleLog = logs.find((log) =>
log.message.includes('Application bundle generation complete.'),
);
- expect(bundleLog?.message).toContain('spec-app-a-collision.spec.js');
+ expect(bundleLog?.message).toContain('spec-app-a-foo-bar-collision.spec.js');
+ expect(bundleLog?.message).toContain('spec-app-a-foo-bar-collision-2.spec.js');
+ expect(bundleLog?.message).toContain('spec-app-a-foo-bar-collision-3.spec.js');
expect(bundleLog?.message).toContain('spec-app-b-collision.spec.js');
}
});
diff --git a/tests/legacy-cli/e2e/tests/vite/browser-node-module-dep-error.ts b/tests/legacy-cli/e2e/tests/vite/browser-node-module-dep-error.ts
new file mode 100644
index 000000000000..7d2f45198c7c
--- /dev/null
+++ b/tests/legacy-cli/e2e/tests/vite/browser-node-module-dep-error.ts
@@ -0,0 +1,26 @@
+import assert from 'node:assert';
+import { execAndWaitForOutputToMatch, ng } from '../../utils/process';
+import { writeFile } from '../../utils/fs';
+import { getGlobalVariable } from '../../utils/env';
+
+export default async function () {
+ assert(
+ getGlobalVariable('argv')['esbuild'],
+ 'This test should not be called in the Webpack suite.',
+ );
+
+ await ng('cache', 'clean');
+ await ng('cache', 'on');
+
+ await writeFile('src/main.ts', `import '@angular-devkit/core/node';`);
+
+ const { stderr } = await execAndWaitForOutputToMatch('ng', ['serve'], /ERROR.+node:path/, {
+ CI: '0',
+ NO_COLOR: 'true',
+ });
+
+ assert.match(
+ stderr,
+ /The package "node:path" wasn't found on the file system but is built into node/,
+ );
+}
diff --git a/tests/legacy-cli/e2e/tests/vite/reuse-dep-optimization-cache.ts b/tests/legacy-cli/e2e/tests/vite/reuse-dep-optimization-cache.ts
index f4b93ccfcd2f..c7c03be87e2c 100644
--- a/tests/legacy-cli/e2e/tests/vite/reuse-dep-optimization-cache.ts
+++ b/tests/legacy-cli/e2e/tests/vite/reuse-dep-optimization-cache.ts
@@ -1,11 +1,7 @@
import assert from 'node:assert';
+import { setTimeout } from 'node:timers/promises';
import { findFreePort } from '../../utils/network';
-import {
- execAndWaitForOutputToMatch,
- killAllProcesses,
- ng,
- waitForAnyProcessOutputToMatch,
-} from '../../utils/process';
+import { execAndWaitForOutputToMatch, killAllProcesses, ng } from '../../utils/process';
export default async function () {
await ng('cache', 'clean');
@@ -13,31 +9,27 @@ export default async function () {
const port = await findFreePort();
- // Make sure serve is consistent with build
- await execAndWaitForOutputToMatch(
- 'ng',
- ['serve', '--port', `${port}`],
- /Dependencies bundled/,
- // Use CI:0 to force caching
- { DEBUG: 'vite:deps', CI: '0' },
- );
+ const [, response] = await Promise.all([
+ execAndWaitForOutputToMatch(
+ 'ng',
+ ['serve', '--port', `${port}`],
+ /dependencies optimized/,
+ // Use CI:0 to force caching
+ { DEBUG: 'vite:deps', CI: '0', NO_COLOR: 'true' },
+ ),
+ setTimeout(4_000).then(() => fetch(`http://localhost:${port}/main.js`)),
+ ]);
- // Make request so that vite writes the cache.
- const response = await fetch(`http://localhost:${port}/main.js`);
assert(response.ok, `Expected 'response.ok' to be 'true'.`);
- // Wait for vite to write to FS and stablize.
- await waitForAnyProcessOutputToMatch(/dependencies optimized/, 5000);
-
// Terminate the dev-server
await killAllProcesses();
- // The Node.js specific module should not be found
await execAndWaitForOutputToMatch(
'ng',
['serve', '--port=0'],
/Hash is consistent\. Skipping/,
// Use CI:0 to force caching
- { DEBUG: 'vite:deps', CI: '0' },
+ { DEBUG: 'vite:deps', CI: '0', NO_COLOR: 'true' },
);
}