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' }, ); }