diff --git a/.github/actions/deploy-docs-site/main.js b/.github/actions/deploy-docs-site/main.js index dab247303828..a234b30dfd08 100644 --- a/.github/actions/deploy-docs-site/main.js +++ b/.github/actions/deploy-docs-site/main.js @@ -40126,7 +40126,7 @@ function paginateRest(octokit) { paginateRest.VERSION = VERSION6; // -var VERSION7 = "16.1.0"; +var VERSION7 = "16.1.1"; // var Endpoints = { diff --git a/.github/actions/saucelabs-legacy/action.yml b/.github/actions/saucelabs-legacy/action.yml index 20389e64729f..5dcd170b6ae1 100644 --- a/.github/actions/saucelabs-legacy/action.yml +++ b/.github/actions/saucelabs-legacy/action.yml @@ -5,9 +5,9 @@ runs: using: 'composite' steps: - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Saucelabs Variables - uses: angular/dev-infra/github-actions/saucelabs@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/saucelabs@4425eed914bab0e311066d4b930c35576b7d200e - name: Starting Saucelabs tunnel service shell: bash run: ./tools/saucelabs/sauce-service.sh run & diff --git a/.github/workflows/adev-preview-build.yml b/.github/workflows/adev-preview-build.yml index da99afe85559..069c458e57a0 100644 --- a/.github/workflows/adev-preview-build.yml +++ b/.github/workflows/adev-preview-build.yml @@ -21,16 +21,16 @@ jobs: (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'adev: preview')) steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e - name: Install node modules run: pnpm install --frozen-lockfile - name: Build adev run: pnpm bazel build //adev:build.production - - uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + - uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@4425eed914bab0e311066d4b930c35576b7d200e with: workflow-artifact-name: 'adev-preview' pull-number: '${{github.event.pull_request.number}}' diff --git a/.github/workflows/adev-preview-deploy.yml b/.github/workflows/adev-preview-deploy.yml index 304dc6a78882..778c987d1d2e 100644 --- a/.github/workflows/adev-preview-deploy.yml +++ b/.github/workflows/adev-preview-deploy.yml @@ -40,7 +40,7 @@ jobs: npx -y firebase-tools@latest target:clear --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs npx -y firebase-tools@latest target:apply --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs ${{env.PREVIEW_SITE}} - - uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + - uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@4425eed914bab0e311066d4b930c35576b7d200e with: github-token: '${{secrets.GITHUB_TOKEN}}' workflow-artifact-name: 'adev-preview' diff --git a/.github/workflows/assistant-to-the-branch-manager.yml b/.github/workflows/assistant-to-the-branch-manager.yml index 4b9a6d5e67fb..07118beb0160 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - - uses: angular/dev-infra/github-actions/branch-manager@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + - uses: angular/dev-infra/github-actions/branch-manager@4425eed914bab0e311066d4b930c35576b7d200e with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/benchmark-compare.yml b/.github/workflows/benchmark-compare.yml index 0c66860dced9..219f1ae237e8 100644 --- a/.github/workflows/benchmark-compare.yml +++ b/.github/workflows/benchmark-compare.yml @@ -38,7 +38,7 @@ jobs: - run: pnpm install --frozen-lockfile - - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + - uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e with: bazelrc: ./.bazelrc.user diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c7ff951cb4d8..7d3d06f2ca8c 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@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Install node modules run: pnpm install --frozen-lockfile - name: Check code lint @@ -39,13 +39,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e with: disable-package-manager-cache: true - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Cache downloaded Cypress binary @@ -72,11 +72,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel Remote Caching - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -88,11 +88,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel Remote Caching - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -105,11 +105,11 @@ jobs: labels: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -124,11 +124,11 @@ jobs: labels: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e - name: Install node modules run: pnpm install --frozen-lockfile - run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials @@ -140,11 +140,11 @@ jobs: labels: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -194,11 +194,11 @@ jobs: runs-on: ubuntu-latest-8core steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e - name: Install node modules run: pnpm install --frozen-lockfile - name: Build adev diff --git a/.github/workflows/dev-infra.yml b/.github/workflows/dev-infra.yml index c0463d526f35..a0e91fad87aa 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: angular/dev-infra/github-actions/pull-request-labeling@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + - uses: angular/dev-infra/github-actions/pull-request-labeling@4425eed914bab0e311066d4b930c35576b7d200e with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} post_approval_changes: runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: angular/dev-infra/github-actions/post-approval-changes@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + - uses: angular/dev-infra/github-actions/post-approval-changes@4425eed914bab0e311066d4b930c35576b7d200e with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/google-internal-tests.yml b/.github/workflows/google-internal-tests.yml index 3720ca9609db..461a67efac91 100644 --- a/.github/workflows/google-internal-tests.yml +++ b/.github/workflows/google-internal-tests.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: angular/dev-infra/github-actions/google-internal-tests@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + - uses: angular/dev-infra/github-actions/google-internal-tests@4425eed914bab0e311066d4b930c35576b7d200e with: run-tests-guide-url: http://go/angular-g3sync-start github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/manual.yml b/.github/workflows/manual.yml index ca284ff07abe..25ef18aba3a3 100644 --- a/.github/workflows/manual.yml +++ b/.github/workflows/manual.yml @@ -13,15 +13,15 @@ jobs: JOBS: 2 steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel Remote Caching - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Saucelabs Variables - uses: angular/dev-infra/github-actions/saucelabs@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/saucelabs@4425eed914bab0e311066d4b930c35576b7d200e - name: Set up Sauce Tunnel Daemon run: pnpm bazel run //tools/saucelabs-daemon/background-service -- $JOBS & env: diff --git a/.github/workflows/merge-ready-status.yml b/.github/workflows/merge-ready-status.yml index 89b099d12539..73abf350a132 100644 --- a/.github/workflows/merge-ready-status.yml +++ b/.github/workflows/merge-ready-status.yml @@ -9,6 +9,6 @@ jobs: status: runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/unified-status-check@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + - uses: angular/dev-infra/github-actions/unified-status-check@4425eed914bab0e311066d4b930c35576b7d200e with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/perf.yml b/.github/workflows/perf.yml index ac49299efc16..878ff5dc3aeb 100644 --- a/.github/workflows/perf.yml +++ b/.github/workflows/perf.yml @@ -21,7 +21,7 @@ jobs: workflows: ${{ steps.workflows.outputs.workflows }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Install node modules run: pnpm install --frozen-lockfile - id: workflows @@ -36,9 +36,9 @@ jobs: workflow: ${{ fromJSON(needs.list.outputs.workflows) }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Install node modules run: pnpm install --frozen-lockfile # We utilize the google-github-actions/auth action to allow us to get an active credential using workflow diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index deea7ca1f970..c62b93b36d79 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Install node modules run: pnpm install --frozen-lockfile - name: Check code lint @@ -37,7 +37,7 @@ jobs: - name: Check code format run: pnpm ng-dev format changed --check ${{ github.event.pull_request.base.sha }} - name: Check Package Licenses - uses: angular/dev-infra/github-actions/linting/licenses@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/linting/licenses@4425eed914bab0e311066d4b930c35576b7d200e with: allow-dependencies-licenses: 'pkg:npm/google-protobuf@' @@ -45,13 +45,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e with: disable-package-manager-cache: true - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e - name: Cache downloaded Cypress binary uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: @@ -76,11 +76,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel Remote Caching - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e - name: Install node modules run: pnpm install --frozen-lockfile - name: Run CI tests for framework @@ -100,11 +100,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel Remote Caching - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e - name: Install node modules run: pnpm install --frozen-lockfile - name: Run integration CI tests for framework @@ -115,11 +115,11 @@ jobs: labels: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e - name: Install node modules run: pnpm install --frozen-lockfile - name: Run tests @@ -132,11 +132,11 @@ jobs: labels: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/setup@4425eed914bab0e311066d4b930c35576b7d200e - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@aa7eafce1e85690dadfd8019d44ceadfb94851b8 + uses: angular/dev-infra/github-actions/bazel/configure-remote@4425eed914bab0e311066d4b930c35576b7d200e - name: Install node modules run: pnpm install --frozen-lockfile - run: | diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 0ad1f871dff6..c70180ee9bd5 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -47,6 +47,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@755f44910c12a3d7ca0d8c6e42c048b3362f7cec # v3.30.8 + uses: github/codeql-action/upload-sarif@42213152a85ae7569bdb6bec7bcd74cd691bfe41 # v3.30.9 with: sarif_file: results.sarif diff --git a/.nvmrc b/.nvmrc index 442c7587a99a..aa50a62f2194 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -22.20.0 +22.21.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 27a687d2865a..3d43b97a7edd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,30 @@ + +# 20.3.7 (2025-10-22) +### animations +| Commit | Type | Description | +| -- | -- | -- | +| [bd38cd45a5](https://github.com/angular/angular/commit/bd38cd45a5fb81e92b91e582d7b13aa3b21f3839) | fix | account for `Element.animate` exceptions ([#64506](https://github.com/angular/angular/pull/64506)) | +### compiler +| Commit | Type | Description | +| -- | -- | -- | +| [891f180262](https://github.com/angular/angular/commit/891f18026243bcf8c8b82881a73dffa283d0dd11) | fix | correctly compile long numeric HTML entities ([#64297](https://github.com/angular/angular/pull/64297)) | +### compiler-cli +| Commit | Type | Description | +| -- | -- | -- | +| [371274bfc6](https://github.com/angular/angular/commit/371274bfc6d5690390f90161106b60d80939fe75) | fix | missingStructuralDirective diagnostic produces false negatives ([#64470](https://github.com/angular/angular/pull/64470)) | +### core +| Commit | Type | Description | +| -- | -- | -- | +| [4c89a267c3](https://github.com/angular/angular/commit/4c89a267c3b49e928332232ec2a3023f6fb4046d) | fix | pass element removal property through in all locations ([#64565](https://github.com/angular/angular/pull/64565)) | +| [2fad4d4ab6](https://github.com/angular/angular/commit/2fad4d4ab63a2a8326af02b0f2f7d285c7f42e0d) | fix | prevent duplicate nodes from being retained with fast `animate.leave`` calls ([#64592](https://github.com/angular/angular/pull/64592)) | +### router +| Commit | Type | Description | +| -- | -- | -- | +| [cfd8ed3fff](https://github.com/angular/angular/commit/cfd8ed3fff02af93b3fbd2e3f3a47128bd3582bf) | fix | Fix outlet serialization and parsing with no primary children ([#64505](https://github.com/angular/angular/pull/64505)) | +| [182fe78f91](https://github.com/angular/angular/commit/182fe78f91d04ac8d25a32bce0ea180a6fe557ce) | fix | Surface parse errors in Router.parseUrl ([#64503](https://github.com/angular/angular/pull/64503)) | + + + # 20.3.6 (2025-10-16) ### core diff --git a/MODULE.bazel b/MODULE.bazel index d37ef00eb082..3a7b9e6e8014 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -5,7 +5,7 @@ module( ) bazel_dep(name = "rules_pkg", version = "1.1.0") -bazel_dep(name = "rules_nodejs", version = "6.5.2") +bazel_dep(name = "rules_nodejs", version = "6.6.0") bazel_dep(name = "aspect_rules_ts", version = "3.7.0") bazel_dep(name = "aspect_rules_js", version = "2.6.2") bazel_dep(name = "aspect_rules_esbuild", version = "0.23.0") @@ -25,7 +25,7 @@ git_override( bazel_dep(name = "devinfra") git_override( module_name = "devinfra", - commit = "aa7eafce1e85690dadfd8019d44ceadfb94851b8", + commit = "4425eed914bab0e311066d4b930c35576b7d200e", remote = "https://github.com/angular/dev-infra.git", ) @@ -39,7 +39,7 @@ git_override( bazel_dep(name = "rules_browsers") git_override( module_name = "rules_browsers", - commit = "0e04a5443e783ef983c84314e311e68410dd82e1", + commit = "6a699bf3e896690e2923cf3ade29fbd4e492e366", remote = "https://github.com/devversion/rules_browsers.git", ) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index d12ac3efaeef..1e42a0ee0537 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -155,7 +155,8 @@ "https://bcr.bazel.build/modules/rules_nodejs/6.3.0/MODULE.bazel": "45345e4aba35dd6e4701c1eebf5a4e67af4ed708def9ebcdc6027585b34ee52d", "https://bcr.bazel.build/modules/rules_nodejs/6.5.0/MODULE.bazel": "546d0cf79f36f9f6e080816045f97234b071c205f4542e3351bd4424282a8810", "https://bcr.bazel.build/modules/rules_nodejs/6.5.2/MODULE.bazel": "7f9ea68a0ce6d82905ce9f74e76ab8a8b4531ed4c747018c9d76424ad0b3370d", - "https://bcr.bazel.build/modules/rules_nodejs/6.5.2/source.json": "6a6ca0940914d55c550d1417cad13a56c9900e23f651a762d8ccc5a64adcf661", + "https://bcr.bazel.build/modules/rules_nodejs/6.6.0/MODULE.bazel": "49ef4cccc17a5a13c9beca2d0b3f7dea1d97381df8cb6ba4dea03943f6a81b0a", + "https://bcr.bazel.build/modules/rules_nodejs/6.6.0/source.json": "cbd156fa2db33707275de138110b78eb86a4cf510b979df7c4b6a8e7127484de", "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", "https://bcr.bazel.build/modules/rules_pkg/1.1.0/MODULE.bazel": "9db8031e71b6ef32d1846106e10dd0ee2deac042bd9a2de22b4761b0c3036453", @@ -702,7 +703,7 @@ }, "@@rules_browsers~//browsers:extensions.bzl%browsers": { "general": { - "bzlTransitiveDigest": "wG3lfivSBp6/w6pp9XxmrFKs0j4BJ1G7oDv4DpFa62g=", + "bzlTransitiveDigest": "6QMCx97Hwh2hyQPqZEA9AKAxbpygF41+K8xJfeqJYm8=", "usagesDigest": "1PlExi+b77pSr2tAxFCVbpCtFoA7oixHabaL3dmas4Y=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -712,9 +713,9 @@ "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", "ruleClassName": "browser_repo", "attributes": { - "sha256": "79a3a4d3a5f9efae04dbb7c2164393ff8fee5f352ec73e36900848c75f4f906f", + "sha256": "4bc6d611d55dc96b213c8605cb8ac27d3c21973bf8b663df4cbf756c989e6745", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7459.0/linux64/chrome-headless-shell-linux64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/linux64/chrome-headless-shell-linux64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-linux64/chrome-headless-shell" @@ -731,9 +732,9 @@ "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", "ruleClassName": "browser_repo", "attributes": { - "sha256": "cdba96e69a423adc1f2647f35643a10e33260b4dfcc233977f3724f28bffd8f2", + "sha256": "830cc2aafedbe7c9fe671c9898046f8900c06da89d12653ddc3ef26084d2f516", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7459.0/mac-x64/chrome-headless-shell-mac-x64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/mac-x64/chrome-headless-shell-mac-x64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-x64/chrome-headless-shell" @@ -750,9 +751,9 @@ "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", "ruleClassName": "browser_repo", "attributes": { - "sha256": "56eb0c57958b50dc6c0de810ea9fcf1ff800baf2a4b14ae0fea536e633806098", + "sha256": "5b5792f5c2d05c3f1f782346910869b61a37b9003f212315b19f4e46710cf8b9", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7459.0/mac-arm64/chrome-headless-shell-mac-arm64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/mac-arm64/chrome-headless-shell-mac-arm64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-arm64/chrome-headless-shell" @@ -769,9 +770,9 @@ "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", "ruleClassName": "browser_repo", "attributes": { - "sha256": "506b23250323f3eb4cdfe298cfd599571e428f6f3a64e86818ee975f4e585b75", + "sha256": "19bdbf6e1579b6c056b74709520ac9df573f4e80e4f026cc2360a29443cf6c0c", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7459.0/win64/chrome-headless-shell-win64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/win64/chrome-headless-shell-win64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-win64/chrome-headless-shell.exe" @@ -788,9 +789,9 @@ "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", "ruleClassName": "browser_repo", "attributes": { - "sha256": "8bf018ed7c383dfd4a4a8f26702265e58b053e71583c4b7a6f8a3eaa6e9b9e6f", + "sha256": "ea41e7a217d878c00e9d66a0724ff54be7d02d08adb7f6458b7d8487b6fbcd84", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7459.0/linux64/chromedriver-linux64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/linux64/chromedriver-linux64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-linux64/chromedriver" @@ -805,9 +806,9 @@ "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", "ruleClassName": "browser_repo", "attributes": { - "sha256": "4eb9cc848823444374bf2d3d388eaa949cee92114a611ce850024bf6b91352d1", + "sha256": "aede9b67301b930ff9c673df28429aa82ce05c105a4ccbef7e0cd30a97ae429d", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7459.0/mac-x64/chromedriver-mac-x64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/mac-x64/chromedriver-mac-x64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-mac-x64/chromedriver" @@ -822,9 +823,9 @@ "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", "ruleClassName": "browser_repo", "attributes": { - "sha256": "13f142a6c53f38d26552ee21a874e3d11497bf6fb580b79a6b6b4b042875bef6", + "sha256": "5adf89a3e8edc6755920f4cfe2fe0515d40684878ef5201da5e02a9d491c4003", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7459.0/mac-arm64/chromedriver-mac-arm64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/mac-arm64/chromedriver-mac-arm64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-mac-arm64/chromedriver" @@ -839,9 +840,9 @@ "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", "ruleClassName": "browser_repo", "attributes": { - "sha256": "65c25dfbe56801d342ae027f365194d0d5b31602ec94e644fe21b6edb876904a", + "sha256": "a3dfe62b3e9e7a42bd324c07dcbbcc3a733a736b2a59f0e93b9250b88103ab73", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7459.0/win64/chromedriver-win64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/win64/chromedriver-win64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-win64/chromedriver.exe" @@ -856,9 +857,9 @@ "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", "ruleClassName": "browser_repo", "attributes": { - "sha256": "1c87a9de21941a15177384d4820a6aa3c7dacb38d34089c73a621734ebf1ea9a", + "sha256": "c66a48222ff67d51560240d321895c6926c9b3af345cbf688ced8517781d88d1", "urls": [ - "https://archive.mozilla.org/pub/firefox/releases/143.0/linux-x86_64/en-US/firefox-143.0.tar.xz" + "https://archive.mozilla.org/pub/firefox/releases/144.0/linux-x86_64/en-US/firefox-144.0.tar.xz" ], "named_files": { "FIREFOX": "firefox/firefox" @@ -873,9 +874,9 @@ "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", "ruleClassName": "browser_repo", "attributes": { - "sha256": "a5c570e277021b61df1295efe77446617ebd768d8ad36a20b309aa382685f6f2", + "sha256": "1e444b80921bc999d56c05a7decc1eaf88c0297cac5b90416299af2c77f5ecc9", "urls": [ - "https://archive.mozilla.org/pub/firefox/releases/143.0/mac/en-US/Firefox%20143.0.dmg" + "https://archive.mozilla.org/pub/firefox/releases/144.0/mac/en-US/Firefox%20144.0.dmg" ], "named_files": { "FIREFOX": "Firefox.app/Contents/MacOS/firefox" @@ -890,9 +891,9 @@ "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", "ruleClassName": "browser_repo", "attributes": { - "sha256": "a5c570e277021b61df1295efe77446617ebd768d8ad36a20b309aa382685f6f2", + "sha256": "1e444b80921bc999d56c05a7decc1eaf88c0297cac5b90416299af2c77f5ecc9", "urls": [ - "https://archive.mozilla.org/pub/firefox/releases/143.0/mac/en-US/Firefox%20143.0.dmg" + "https://archive.mozilla.org/pub/firefox/releases/144.0/mac/en-US/Firefox%20144.0.dmg" ], "named_files": { "FIREFOX": "Firefox.app/Contents/MacOS/firefox" @@ -907,9 +908,9 @@ "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", "ruleClassName": "browser_repo", "attributes": { - "sha256": "fbbadc9a6881aa90d266b572304a75e8814b91817a1db7fc01015d667f60318d", + "sha256": "d1e8a7c061e25a41c8dfa85e3aee8e86e9263c69104d80906c978c8d0556563a", "urls": [ - "https://archive.mozilla.org/pub/firefox/releases/143.0/win64/en-US/Firefox%20Setup%20143.0.exe" + "https://archive.mozilla.org/pub/firefox/releases/144.0/win64/en-US/Firefox%20Setup%20144.0.exe" ], "named_files": { "FIREFOX": "core/firefox.exe" @@ -1109,8 +1110,8 @@ }, "@@rules_nodejs~//nodejs:extensions.bzl%node": { "general": { - "bzlTransitiveDigest": "FmfMiNXAxRoLWw3NloQbssosE1egrSvzirbQnso7j7E=", - "usagesDigest": "gj5TARtK0gTGB1qjjp2jJe1Msc70mpF80SrnuX6OmHI=", + "bzlTransitiveDigest": "71PwVsMlLx+RWdt1SI9nSqRHX7DX/NstWwr7/XBxEMs=", + "usagesDigest": "Bi/dw+UwwqG0aBYWNMN30ePJsPsPmOR7Ap9VV8G+33w=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, diff --git a/adev/package.json b/adev/package.json index e5a70c57a881..32fe9b483003 100644 --- a/adev/package.json +++ b/adev/package.json @@ -3,7 +3,7 @@ "@angular-devkit/build-angular": "20.3.6", "@angular/animations": "workspace:*", "@angular/build": "20.3.6", - "@angular/cdk": "20.2.9", + "@angular/cdk": "20.2.10", "@angular/cli": "20.3.6", "@angular/common": "workspace:*", "@angular/compiler-cli": "workspace:*", @@ -11,7 +11,7 @@ "@angular/core": "workspace:*", "@angular/docs": "workspace:*", "@angular/forms": "workspace:*", - "@angular/material": "20.2.9", + "@angular/material": "20.2.10", "@angular/platform-browser": "workspace:*", "@angular/platform-server": "workspace:*", "@angular/router": "workspace:*", diff --git a/adev/shared-docs/components/navigation-list/navigation-list.component.scss b/adev/shared-docs/components/navigation-list/navigation-list.component.scss index 7a32850d95df..5e0b7a90acf9 100644 --- a/adev/shared-docs/components/navigation-list/navigation-list.component.scss +++ b/adev/shared-docs/components/navigation-list/navigation-list.component.scss @@ -49,6 +49,7 @@ max-width: calc(100% - 1rem); overflow: hidden; text-overflow: ellipsis; + text-wrap: balance; } .docs-nav-item-has-icon { diff --git a/adev/shared-docs/components/search-history/search-history.component.ts b/adev/shared-docs/components/search-history/search-history.component.ts index 3dd2beeb79ba..2d038b7b6178 100644 --- a/adev/shared-docs/components/search-history/search-history.component.ts +++ b/adev/shared-docs/components/search-history/search-history.component.ts @@ -8,6 +8,7 @@ import { afterNextRender, + ChangeDetectionStrategy, Component, DestroyRef, effect, @@ -33,6 +34,7 @@ import {SearchItem} from '../../directives'; '(document:keydown)': 'onKeydown($event)', '(document:mousemove)': 'onMouseMove($event)', }, + changeDetection: ChangeDetectionStrategy.OnPush, }) export class SearchHistoryComponent { protected readonly items = viewChildren(SearchItem); diff --git a/adev/shared-docs/components/viewers/example-viewer/example-viewer.component.spec.ts b/adev/shared-docs/components/viewers/example-viewer/example-viewer.component.spec.ts index 873d37e6fc91..d3c6415166aa 100644 --- a/adev/shared-docs/components/viewers/example-viewer/example-viewer.component.spec.ts +++ b/adev/shared-docs/components/viewers/example-viewer/example-viewer.component.spec.ts @@ -10,7 +10,7 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; import {ExampleViewer} from './example-viewer.component'; import {ExampleMetadata, ExampleViewerContentLoader} from '../../../interfaces'; import {EXAMPLE_VIEWER_CONTENT_LOADER} from '../../../providers'; -import {Component, provideZonelessChangeDetection, ComponentRef} from '@angular/core'; +import {Component, provideZonelessChangeDetection, ComponentRef, signal} from '@angular/core'; import {HarnessLoader} from '@angular/cdk/testing'; import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; import {Clipboard} from '@angular/cdk/clipboard'; @@ -316,6 +316,24 @@ describe('ExampleViewer', () => { codeContainer = fixture.debugElement.query(By.css('.docs-example-viewer-code-wrapper')); expect(codeContainer).not.toBeNull(); }); + + it('should render example', async () => { + exampleContentSpy.loadPreview.and.resolveTo(ExampleComponent); + componentRef.setInput( + 'metadata', + getMetadata({ + path: 'example.ts', + preview: true, + }), + ); + await component.renderExample(); + fixture.detectChanges(); + expect(component.exampleComponent).toBeDefined(); + + const previewContainer = fixture.debugElement.query(By.css('.docs-example-viewer-preview')); + expect(previewContainer.nativeElement.innerHTML).toContain('ng-component'); + expect(previewContainer.nativeElement.textContent).toContain('foobar'); + }); }); const getMetadata = (value: Partial = {}): ExampleMetadata => { @@ -332,6 +350,8 @@ const getMetadata = (value: Partial = {}): ExampleMetadata => { }; @Component({ - template: '', + template: '{{foobar}}', }) -class ExampleComponent {} +class ExampleComponent { + foobar = signal('foobar'); +} diff --git a/adev/shared-docs/components/viewers/example-viewer/example-viewer.component.ts b/adev/shared-docs/components/viewers/example-viewer/example-viewer.component.ts index 305c64e9a4f5..66acde392067 100644 --- a/adev/shared-docs/components/viewers/example-viewer/example-viewer.component.ts +++ b/adev/shared-docs/components/viewers/example-viewer/example-viewer.component.ts @@ -21,7 +21,7 @@ import { Type, viewChild, } from '@angular/core'; -import {DOCUMENT, NgTemplateOutlet} from '@angular/common'; +import {DOCUMENT, NgComponentOutlet, NgTemplateOutlet} from '@angular/common'; import {MatTabGroup, MatTabsModule} from '@angular/material/tabs'; import {Clipboard} from '@angular/cdk/clipboard'; import {CopySourceCodeButton} from '../../copy-source-code-button/copy-source-code-button.component'; @@ -43,7 +43,14 @@ export const HIDDEN_CLASS_NAME = 'hidden'; @Component({ selector: 'docs-example-viewer', - imports: [CopySourceCodeButton, MatTabsModule, MatTooltipModule, IconComponent, NgTemplateOutlet], + imports: [ + CopySourceCodeButton, + MatTabsModule, + MatTooltipModule, + IconComponent, + NgTemplateOutlet, + NgComponentOutlet, + ], templateUrl: './example-viewer.component.html', styleUrls: ['./example-viewer.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, @@ -92,10 +99,9 @@ export class ExampleViewer { async renderExample(): Promise { // Lazy load live example component - if (this.exampleMetadata()?.path && this.exampleMetadata()?.preview) { - this.exampleComponent = await this.exampleViewerContentLoader.loadPreview( - this.exampleMetadata()?.path!, - ); + const path = this.exampleMetadata()?.path; + if (path && this.exampleMetadata()?.preview) { + this.exampleComponent = await this.exampleViewerContentLoader.loadPreview(path); } this.snippetCode.set(this.exampleMetadata()?.files[0]); diff --git a/adev/shared-docs/pipeline/api-gen/rendering/entities.mts b/adev/shared-docs/pipeline/api-gen/rendering/entities.mts index d79c274efad1..ae58f7934ebd 100644 --- a/adev/shared-docs/pipeline/api-gen/rendering/entities.mts +++ b/adev/shared-docs/pipeline/api-gen/rendering/entities.mts @@ -107,10 +107,13 @@ export interface ClassEntry extends DocEntry { implements: string[]; } -// From an API doc perspective, class and interfaces are identical. - /** Documentation entity for a TypeScript interface. */ -export type InterfaceEntry = ClassEntry; +export interface InterfaceEntry extends DocEntry { + members: MemberEntry[]; + generics: GenericEntry[]; + extends: string[]; + implements: string[]; +} /** Documentation entity for a TypeScript enum. */ export interface EnumEntry extends DocEntry { diff --git a/adev/shared-docs/pipeline/api-gen/rendering/entities/renderables.mts b/adev/shared-docs/pipeline/api-gen/rendering/entities/renderables.mts index 988e5ccf41ad..2eac7bc6aa24 100644 --- a/adev/shared-docs/pipeline/api-gen/rendering/entities/renderables.mts +++ b/adev/shared-docs/pipeline/api-gen/rendering/entities/renderables.mts @@ -15,6 +15,7 @@ import { FunctionEntry, FunctionSignatureMetadata, InitializerApiFunctionEntry, + InterfaceEntry, JsDocTagEntry, MemberEntry, ParameterEntry, @@ -80,7 +81,11 @@ export type EnumEntryRenderable = EnumEntry & }; /** Documentation entity for a TypeScript interface augmented transformed content for rendering. */ -export type InterfaceEntryRenderable = ClassEntryRenderable; +export type InterfaceEntryRenderable = InterfaceEntry & + DocEntryRenderable & + HasRenderableToc & { + members: MemberEntryRenderable[]; + }; export type FunctionEntryRenderable = FunctionEntry & DocEntryRenderable & diff --git a/adev/shared-docs/pipeline/api-gen/rendering/index.mts b/adev/shared-docs/pipeline/api-gen/rendering/index.mts index 8c1aa6faf42d..7316c9ff5340 100644 --- a/adev/shared-docs/pipeline/api-gen/rendering/index.mts +++ b/adev/shared-docs/pipeline/api-gen/rendering/index.mts @@ -51,7 +51,7 @@ function parseEntryData(srcs: string[]): EntryCollection[] { const command = fileContentJson as CliCommand; return [ { - repo: 'anglar/cli', + repo: 'angular/cli', moduleName: 'unknown', normalizedModuleName: 'unknown', entries: [fileContentJson as DocEntry], diff --git a/adev/shared-docs/pipeline/api-gen/rendering/rendering.mts b/adev/shared-docs/pipeline/api-gen/rendering/rendering.mts index c40f28bfd953..d223ac0c5b5e 100644 --- a/adev/shared-docs/pipeline/api-gen/rendering/rendering.mts +++ b/adev/shared-docs/pipeline/api-gen/rendering/rendering.mts @@ -19,11 +19,7 @@ import { isInterfaceEntry, isTypeAliasEntry, } from './entities/categorization.mjs'; -import { - ClassEntryRenderable, - CliCommandRenderable, - DocEntryRenderable, -} from './entities/renderables.mjs'; +import {CliCommandRenderable, DocEntryRenderable} from './entities/renderables.mjs'; import {ClassReference} from './templates/class-reference'; import {CliCommandReference} from './templates/cli-reference'; import {ConstantReference} from './templates/constant-reference'; @@ -43,7 +39,7 @@ export function renderEntry(renderable: DocEntryRenderable | CliCommandRenderabl } if (isClassEntry(renderable) || isInterfaceEntry(renderable)) { - return render(ClassReference(renderable as ClassEntryRenderable)); + return render(ClassReference(renderable)); } if (isDecoratorEntry(renderable)) { return render(DecoratorReference(renderable)); diff --git a/adev/shared-docs/pipeline/api-gen/rendering/templates/class-reference.tsx b/adev/shared-docs/pipeline/api-gen/rendering/templates/class-reference.tsx index 1596274ae634..a0825efd7b39 100644 --- a/adev/shared-docs/pipeline/api-gen/rendering/templates/class-reference.tsx +++ b/adev/shared-docs/pipeline/api-gen/rendering/templates/class-reference.tsx @@ -8,7 +8,11 @@ import {Fragment, h} from 'preact'; import {PipeEntry} from '../entities.mjs'; -import {ClassEntryRenderable, PipeEntryRenderable} from '../entities/renderables.mjs'; +import { + ClassEntryRenderable, + InterfaceEntryRenderable, + PipeEntryRenderable, +} from '../entities/renderables.mjs'; import {ClassMemberList} from './class-member-list'; import {HeaderApi} from './header-api'; import { @@ -26,7 +30,9 @@ import {codeToHtml} from '../../../shared/shiki.mjs'; import {getHighlighterInstance} from '../shiki/shiki.mjs'; /** Component to render a class API reference document. */ -export function ClassReference(entry: ClassEntryRenderable | PipeEntryRenderable) { +export function ClassReference( + entry: ClassEntryRenderable | InterfaceEntryRenderable | PipeEntryRenderable, +) { return (
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/transforms/code-transforms.mts b/adev/shared-docs/pipeline/api-gen/rendering/transforms/code-transforms.mts index 730d8fe5b124..74ab06d93fd3 100644 --- a/adev/shared-docs/pipeline/api-gen/rendering/transforms/code-transforms.mts +++ b/adev/shared-docs/pipeline/api-gen/rendering/transforms/code-transforms.mts @@ -485,7 +485,11 @@ function appendPrefixAndSuffix(entry: DocEntry, codeTocData: CodeTableOfContents if (isClassEntry(entry) || isInterfaceEntry(entry)) { const generics = makeGenericsText(entry.generics); - const extendsStr = entry.extends ? ` extends ${entry.extends}` : ''; + const extendsStr = entry.extends + ? typeof entry.extends === 'string' + ? ` extends ${entry.extends}` + : ` extends ${entry.extends.join(', ')}` + : ''; const implementsStr = entry.implements.length > 0 ? ` implements ${entry.implements.join(' ,')}` : ''; diff --git a/adev/src/app/main.component.ts b/adev/src/app/main.component.ts index daab349e6937..da8021c36cf0 100644 --- a/adev/src/app/main.component.ts +++ b/adev/src/app/main.component.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {Component, effect, inject, model} from '@angular/core'; +import {ChangeDetectionStrategy, Component, effect, inject, model} from '@angular/core'; import {IS_SEARCH_DIALOG_OPEN, Search} from '@angular/docs'; import {RouterOutlet} from '@angular/router'; @@ -14,6 +14,7 @@ import {RouterOutlet} from '@angular/router'; selector: 'adev-main', imports: [RouterOutlet], template: ``, + changeDetection: ChangeDetectionStrategy.OnPush, }) export default class MainComponent { private readonly displaySearchDialog = inject(IS_SEARCH_DIALOG_OPEN); diff --git a/adev/src/content/guide/animations/enter-and-leave.md b/adev/src/content/guide/animations/enter-and-leave.md index 5059af9c29f2..74fc99b2e851 100644 --- a/adev/src/content/guide/animations/enter-and-leave.md +++ b/adev/src/content/guide/animations/enter-and-leave.md @@ -75,6 +75,10 @@ If you don't call `animationComplete()` when using `animate.leave`, Angular call { provide: MAX_ANIMATION_TIMEOUT, useValue: 6000 } ``` +## Compatibility with Legacy Angular Animations + +You cannot use legacy animations alongside `animate.enter` and `animate.leave` within the same component. Doing so would result in enter classes remaining on the element or leaving nodes not being removed. It is otherwise fine to use both legacy animations and the new `animate.enter` and `animate.leave` animations within the same _application_. The only caveat is content projection. If you are projecting content from one component with legacy animations into another component with `animate.enter` or `animate.leave`, or vice versa, this will result in the same behavior as if they are used together in the same component. This is not supported. + ## Testing TestBed provides built-in support for enabling or disabling animations in your test environment. CSS animations require a browser to run, and many of the APIs are not available in a test environment. By default, TestBed disables animations for you in your test environments. diff --git a/adev/src/content/guide/components/lifecycle.md b/adev/src/content/guide/components/lifecycle.md index 09ae04a4ec6a..2d8428061254 100644 --- a/adev/src/content/guide/components/lifecycle.md +++ b/adev/src/content/guide/components/lifecycle.md @@ -161,6 +161,12 @@ destroyed. You can also use `DestroyRef` to keep setup code close to cleanup code, rather than putting all cleanup code in the `ngOnDestroy` method. +##### Detecting instance destruction + +`DestroyRef` provides a `destroyed` property that allows checking whether a given instance has already been destroyed. This is useful for avoiding operations on destroyed components, especially when dealing with delayed or asynchronous logic. + +By checking `destroyRef.destroyed`, you can prevent executing code after the instance has been cleaned up, avoiding potential errors such as `NG0911: View has already been destroyed.`. + ### ngDoCheck The `ngDoCheck` method runs before every time Angular checks a component's template for changes. @@ -237,7 +243,7 @@ See [Using DOM APIs](guide/components/dom-apis) for guidance on working with the Render callbacks do not run during server-side rendering or during build-time pre-rendering. -#### after*Render phases +#### after\*Render phases When using `afterEveryRender` or `afterNextRender`, you can optionally split the work into phases. The phase gives you control over the sequencing of DOM operations, letting you sequence _write_ diff --git a/adev/src/content/guide/di/di-in-action.md b/adev/src/content/guide/di/di-in-action.md index 4d1d3b6c7caa..b44322e0864b 100644 --- a/adev/src/content/guide/di/di-in-action.md +++ b/adev/src/content/guide/di/di-in-action.md @@ -9,7 +9,7 @@ The following example uses an `InjectionToken` to provide the [localStorage](htt -import { Inject, Injectable, InjectionToken } from '@angular/core'; +import { inject, Injectable, InjectionToken } from '@angular/core'; export const BROWSER_STORAGE = new InjectionToken('Browser Storage', { providedIn: 'root', diff --git a/adev/src/content/guide/forms/reactive-forms.md b/adev/src/content/guide/forms/reactive-forms.md index 8c091c0174c4..3aecc6a2bafe 100644 --- a/adev/src/content/guide/forms/reactive-forms.md +++ b/adev/src/content/guide/forms/reactive-forms.md @@ -359,7 +359,7 @@ Use the getter syntax to create an `aliases` class property to retrieve the alia -Because the returned control is of the type `AbstractControl`, you need to provide an explicit type to access the method syntax for the form array instance. Define a method to dynamically insert an alias control into the alias's form array. The `FormArray.push()` method inserts the control as a new item in the array. +Because the returned control is of the type `AbstractControl`, you need to provide an explicit type to access the method syntax for the form array instance. Define a method to dynamically insert an alias control into the alias's form array. The `FormArray.push()` method inserts the control as a new item in the array, and you can also pass an array of controls to FormArray.push() to register multiple controls at once. diff --git a/adev/src/content/guide/forms/typed-forms.md b/adev/src/content/guide/forms/typed-forms.md index 6b6b5ed9b7ed..dd969fac87b4 100644 --- a/adev/src/content/guide/forms/typed-forms.md +++ b/adev/src/content/guide/forms/typed-forms.md @@ -8,7 +8,7 @@ As background for this guide, you should already be familiar with [Angular React -With Angular reactive forms, you explicitly specify a *form model*. As a simple example, consider this basic user login form: +With Angular reactive forms, you explicitly specify a _form model_. As a simple example, consider this basic user login form: ```ts const login = new FormGroup({ @@ -29,7 +29,7 @@ With strictly typed reactive forms, the above code does not compile, because the In addition to the added safety, the types enable a variety of other improvements, such as better autocomplete in IDEs, and an explicit way to specify form structure. -These improvements currently apply only to *reactive* forms (not [*template-driven* forms](guide/forms/template-driven-forms)). +These improvements currently apply only to _reactive_ forms (not [_template-driven_ forms](guide/forms/template-driven-forms)). ## Untyped Forms @@ -56,7 +56,7 @@ This control will be automatically inferred to have the type `FormControl`. If you want to have multiple different element types inside the array, you must use `UntypedFormArray`, because TypeScript cannot infer which element type will occur at which position. @@ -124,11 +131,11 @@ As a consequence, the type of `login.value` is `Partial<{email: string, password More specifically, the type of `login.value.email` is `string|undefined`, and TypeScript will enforce that you handle the possibly `undefined` value (if you have `strictNullChecks` enabled). -If you want to access the value *including* disabled controls, and thus bypass possible `undefined` fields, you can use `login.getRawValue()`. +If you want to access the value _including_ disabled controls, and thus bypass possible `undefined` fields, you can use `login.getRawValue()`. ### Optional Controls and Dynamic Groups -Some forms have controls that may or may not be present, which can be added and removed at runtime. You can represent these controls using *optional fields*: +Some forms have controls that may or may not be present, which can be added and removed at runtime. You can represent these controls using _optional fields_: ```ts interface LoginForm { diff --git a/adev/src/content/guide/routing/common-router-tasks.md b/adev/src/content/guide/routing/common-router-tasks.md index 1ae7d949da74..1015f9ebdbe7 100644 --- a/adev/src/content/guide/routing/common-router-tasks.md +++ b/adev/src/content/guide/routing/common-router-tasks.md @@ -11,7 +11,7 @@ To edit an item, users click an Edit button, which opens an `EditGroceryItem` co You want that component to retrieve the `id` for the grocery item so it can display the right information to the user. Use a route to pass this type of information to your application components. -To do so, you use the [`withComponentInputBinding`](api/router/withComponentInputBinding) feature with `provideRouter` or the `bindToComponentInputs` option of `RouterModule.forRoot`. +To do so, you use the `withComponentInputBinding` feature with `provideRouter` or the `bindToComponentInputs` option of `RouterModule.forRoot`. To get information from a route: @@ -104,6 +104,8 @@ Provide optional route parameters in an object, as in `{ foo: 'foo' }`: Crisis Center ``` +This syntax passes matrix parameters, which are optional parameters associated with a specific URL segment. Learn more about [matrix parameters](/guide/routing/read-route-state#matrix-parameters). + These three examples cover the needs of an application with one level of routing. However, with a child router, such as in the crisis center, you create new link array possibilities. diff --git a/adev/src/content/guide/routing/navigate-to-routes.md b/adev/src/content/guide/routing/navigate-to-routes.md index 78daed10b00e..6651cd1418a1 100644 --- a/adev/src/content/guide/routing/navigate-to-routes.md +++ b/adev/src/content/guide/routing/navigate-to-routes.md @@ -5,6 +5,7 @@ The RouterLink directive is Angular's declarative approach to navigation. It all ## How to use RouterLink Instead of using regular anchor elements `` with an `href` attribute, you add a RouterLink directive with the appropriate path in order to leverage Angular routing. + ```angular-ts import {RouterLink} from '@angular/router'; @Component({ @@ -99,6 +100,9 @@ export class AppDashboard { this.router.navigate(['/search'], { queryParams: { category: 'books', sort: 'price' } }); + + // With matrix parameters + this.router.navigate(['/products', { featured: true, onSale: true }]); } } ``` @@ -143,7 +147,7 @@ export class UserDetailComponent { The `router.navigateByUrl()` method provides a direct way to programmatically navigate using URL path strings rather than array segments. This method is ideal when you have a full URL path and need to perform absolute navigation, especially when working with externally provided URLs or deep linking scenarios. -```angular-ts +```ts // Standard route navigation router.navigateByUrl('/products); @@ -155,11 +159,14 @@ router.navigateByUrl('/products/123?view=details#reviews'); // Navigate with query parameters router.navigateByUrl('/search?category=books&sortBy=price'); + +// With matrix parameters +router.navigateByUrl('/sales-awesome;isOffer=true;showModal=false') ``` In the event you need to replace the current URL in history, `navigateByUrl` also accepts a configuration object that has a `replaceUrl` option. -```angular-ts +```ts // Replace current URL in history router.navigateByUrl('/checkout', { replaceUrl: true diff --git a/adev/src/content/guide/routing/read-route-state.md b/adev/src/content/guide/routing/read-route-state.md index 2279405ee8af..85d74aebaa7e 100644 --- a/adev/src/content/guide/routing/read-route-state.md +++ b/adev/src/content/guide/routing/read-route-state.md @@ -181,6 +181,43 @@ In this example, users can use a select element to sort the product list by name For more information, check out the [official docs on QueryParamsHandling](/api/router/QueryParamsHandling). +### Matrix Parameters + +Matrix parameters are optional parameters that belong to a specific URL segment, rather than applying to the entire route. Unlike query parameters which appear after a `?` and apply globally, matrix parameters use semicolons (`;`) and are scoped to individual path segments. + +Matrix parameters are useful when you need to pass auxiliary data to a specific route segment without affecting the route definition or matching behavior. Like query parameters, they don't need to be defined in your route configuration. + +```ts +// URL format: /path;key=value +// Multiple parameters: /path;key1=value1;key2=value2 + +// Navigate with matrix parameters +this.router.navigate(['/awesome-products', { view: 'grid', filter: 'new' }]); +// Results in URL: /awesome-products;view=grid;filter=new +``` + +**Using ActivatedRoute** + +```ts +import { Component, inject } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +@Component(/* ... */) +export class AwesomeProducts { + private route = inject(ActivatedRoute); + + constructor() { + // Access matrix parameters via params + this.route.params.subscribe((params) => { + const view = params['view']; // e.g., 'grid' + const filter = params['filter']; // e.g., 'new' + }); + } +} +``` + +NOTE: As an alternative to using `ActivatedRoute`, matrix parameters are also bound to component inputs when using the `withComponentInputBinding`. + ## Detect active current route with RouterLinkActive You can use the `RouterLinkActive` directive to dynamically style navigation elements based on the current active route. This is common in navigation elements to inform users what the active route is. diff --git a/adev/src/content/guide/security.md b/adev/src/content/guide/security.md index 212aa4fac734..83004056b3c8 100644 --- a/adev/src/content/guide/security.md +++ b/adev/src/content/guide/security.md @@ -173,7 +173,7 @@ If an attacker can predict future nonces, they can circumvent the protections of -NOTE: If you want to inline the critical CSS of your application, you can not use the `CSP_NONCE` Injection token, and should prefer the `autoCsp` option. +NOTE: If you want to [inline the critical CSS](/tools/cli/build#critical-css-inlining) of your application, you can not use the `CSP_NONCE` token, and should prefer the `autoCsp` option or set the `ngCspNonce` attribute on the root application element. If you cannot generate nonces in your project, you can allow inline styles by adding `'unsafe-inline'` to the `style-src` section of the CSP header. diff --git a/adev/src/content/guide/ssr.md b/adev/src/content/guide/ssr.md index 136cc264cce0..eeb801b16e85 100644 --- a/adev/src/content/guide/ssr.md +++ b/adev/src/content/guide/ssr.md @@ -330,20 +330,87 @@ To configure this, update your `angular.json` file as follows: ## Caching data when using HttpClient -[`HttpClient`](api/common/http/HttpClient) cached outgoing network requests when running on the server. This information is serialized and transferred to the browser as part of the initial HTML sent from the server. In the browser, `HttpClient` checks whether it has data in the cache and if so, reuses it instead of making a new HTTP request during initial application rendering. `HttpClient` stops using the cache once an application becomes [stable](api/core/ApplicationRef#isStable) while running in a browser. +`HttpClient` caches outgoing network requests when running on the server. This information is serialized and transferred to the browser as part of the initial HTML sent from the server. In the browser, `HttpClient` checks whether it has data in the cache and if so, reuses it instead of making a new HTTP request during initial application rendering. `HttpClient` stops using the cache once an application becomes [stable](api/core/ApplicationRef#isStable) while running in a browser. -By default, `HttpClient` caches all `HEAD` and `GET` requests which don't contain `Authorization` or `Proxy-Authorization` headers. You can override those settings by using [`withHttpTransferCacheOptions`](api/platform-browser/withHttpTransferCacheOptions) when providing hydration. +### Configuring the caching options + +You can customize how Angular caches HTTP responses during server‑side rendering (SSR) and reuses them during hydration by configuring `HttpTransferCacheOptions`. +This configuration is provided globally using `withHttpTransferCacheOptions` inside `provideClientHydration()`. + +By default, `HttpClient` caches all `HEAD` and `GET` requests which don't contain `Authorization` or `Proxy-Authorization` headers. You can override those settings by using `withHttpTransferCacheOptions` to the hydration configuration. + +```ts +import { bootstrapApplication } from '@angular/platform-browser'; +import { provideClientHydration, withHttpTransferCacheOptions } from '@angular/platform-browser'; -```typescript bootstrapApplication(AppComponent, { providers: [ - provideClientHydration(withHttpTransferCacheOptions({ - includePostRequests: true - })) - ] + provideClientHydration( + withHttpTransferCacheOptions({ + includeHeaders: ['ETag', 'Cache-Control'], + filter: (req) => !req.url.includes('/api/profile'), + includePostRequests: true, + includeRequestsWithAuthHeaders: false, + }), + ), + ], +}); +``` + +--- + +### `includeHeaders` + +Specifies which headers from the server response should be included in cached entries. +No headers are included by default. + +```ts +withHttpTransferCacheOptions({ + includeHeaders: ['ETag', 'Cache-Control'], +}); +``` + +IMPORTANT: Avoid including sensitive headers like authentication tokens. These can leak user‑specific data between requests. + +--- + +### `includePostRequests` + +By default, only `GET` and `HEAD` requests are cached. +You can enable caching for `POST` requests when they are used as read operations such as GraphQL queries. + +```ts +withHttpTransferCacheOptions({ + includePostRequests: true, +}); +``` + +Use this only when `POST` requests are **idempotent** and safe to reuse between server and client renders. + +--- + +### `includeRequestsWithAuthHeaders` + +Determines whether requests containing `Authorization` or `Proxy‑Authorization` headers are eligible for caching. +By default, these are excluded to prevent caching user‑specific responses. + +```ts +withHttpTransferCacheOptions({ + includeRequestsWithAuthHeaders: true, }); ``` +Enable only when authentication headers do **not** affect the response content (for example, public tokens for analytics APIs). + +### Per‑request overrides + +You can override caching behavior for a specific request using the `transferCache` request option. + +```ts +// Include specific headers for this request +http.get('/api/profile', { transferCache: { includeHeaders: ['CustomHeader'] } }); +``` + ### Disabling caching You can disable HTTP caching of requests sent from the server either globally or individually. @@ -362,6 +429,8 @@ bootstrapApplication(AppComponent, { }); ``` +#### `filter` + You can also selectively disable caching for certain requests using the [`filter`](api/common/http/HttpTransferCacheOptions) option in `withHttpTransferCacheOptions`. For example, you can disable caching for a specific API endpoint: ```ts @@ -376,6 +445,8 @@ bootstrapApplication(AppComponent, { }); ``` +Use this option to exclude endpoints with user‑specific or dynamic data (for example `/api/profile`). + #### Individually To disable caching for an individual request, you can specify the [`transferCache`](api/common/http/HttpRequest#transferCache) option in an `HttpRequest`. diff --git a/adev/src/content/reference/configs/workspace-config.md b/adev/src/content/reference/configs/workspace-config.md index e949b5fefafb..a122c85354ec 100644 --- a/adev/src/content/reference/configs/workspace-config.md +++ b/adev/src/content/reference/configs/workspace-config.md @@ -396,7 +396,7 @@ This option enables various optimizations of the build output, including: - Minification of scripts and styles - Tree-shaking - Dead-code elimination -- Inlining of critical CSS +- [Inlining of critical CSS](/tools/cli/build#critical-css-inlining) - Fonts inlining Several options can be used to fine-tune the optimization of an application. @@ -448,12 +448,13 @@ You can supply a value such as the following to apply optimization to one or the The `sourceMap` builder option can be either a boolean or an object for more fine-tune configuration to control the source maps of an application. -| Options | Details | Value type | Default value | -| :-------- | :-------------------------------------------------- | :--------- | :------------ | -| `scripts` | Output source maps for all scripts. | `boolean` | `true` | -| `styles` | Output source maps for all styles. | `boolean` | `true` | -| `vendor` | Resolve vendor packages source maps. | `boolean` | `false` | -| `hidden` | Omit link to sourcemaps from the output JavaScript. | `boolean` | `false` | +| Options | Details | Value type | Default value | +| :--------------- | :----------------------------------------------------------- | :--------- | :------------ | +| `scripts` | Output source maps for all scripts. | `boolean` | `true` | +| `styles` | Output source maps for all styles. | `boolean` | `true` | +| `vendor` | Resolve vendor packages source maps. | `boolean` | `false` | +| `hidden` | Omit link to sourcemaps from the output JavaScript. | `boolean` | `false` | +| `sourcesContent` | Output original source content for files within source maps. | `boolean` | `true` | The example below shows how to toggle one or more values to configure the source map outputs: @@ -483,6 +484,34 @@ HELPFUL: When using hidden source maps, source maps are not referenced in the bu These are useful if you only want source maps to map stack traces in error reporting tools without showing up in browser developer tools. Note that even though `hidden` prevents the source map from being linked in the output bundle, your deployment process must take care not to serve the generated sourcemaps in production, or else the information is still leaked. +#### Source maps without sources content + +You can generate source maps without the `sourcesContent` field, which contains the original source code. +This allows you to deploy source maps to production for better error reporting with original source names while protecting your source code from exposure. + +To exclude sources content from source maps, set the `sourcesContent` option to `false`: + +```json +{ + "projects": { + "my-app": { + "architect": { + "build": { + "builder": "@angular/build:application", + "options": { + "sourceMap": { + "scripts": true, + "styles": true, + "sourcesContent": false + } + } + } + } + } + } +} +``` + ### Index configuration Configures generation of the application's HTML index. diff --git a/adev/src/content/tools/cli/aot-compiler.md b/adev/src/content/tools/cli/aot-compiler.md index c331bd19dc4a..c5422c9a9572 100644 --- a/adev/src/content/tools/cli/aot-compiler.md +++ b/adev/src/content/tools/cli/aot-compiler.md @@ -42,7 +42,7 @@ The metadata tells Angular how to construct instances of your application classe In the following example, the `@Component()` metadata object and the class constructor tell Angular how to create and display an instance of `TypicalComponent`. - +```angular-ts @Component({ selector: 'app-typical', @@ -53,7 +53,7 @@ export class TypicalComponent { private someService = inject(SomeService); } - +``` The Angular compiler extracts the metadata *once* and generates a *factory* for `TypicalComponent`. When it needs to create a `TypicalComponent` instance, Angular calls the factory, which produces a new visual element, bound to a new instance of the component class with its injected dependency. @@ -125,14 +125,14 @@ The compiler later reports the error if it needs that piece of metadata to gener HELPFUL: If you want `ngc` to report syntax errors immediately rather than produce a `.metadata.json` file with errors, set the `strictMetadataEmit` option in the TypeScript configuration file. - +```json "angularCompilerOptions": { … "strictMetadataEmit" : true } - +``` Angular libraries have this option to ensure that all Angular `.metadata.json` files are clean and it is a best practice to do the same when building your own libraries. @@ -143,14 +143,14 @@ and [arrow functions](https://developer.mozilla.org/docs/Web/JavaScript/Referenc Consider the following component decorator: - +```ts @Component({ … providers: [{provide: server, useFactory: () => new Server()}] }) - +``` The AOT collector does not support the arrow function, `() => new Server()`, in a metadata expression. It generates an error node in place of the function. @@ -158,7 +158,7 @@ When the compiler later interprets this node, it reports an error that invites y You can fix the error by converting to this: - +```ts export function serverFactory() { return new Server(); @@ -169,7 +169,7 @@ export function serverFactory() { providers: [{provide: server, useFactory: serverFactory}] }) - +``` In version 5 and later, the compiler automatically performs this rewriting while emitting the `.js` file. @@ -187,7 +187,7 @@ The collector can evaluate references to module-local `const` declarations and i Consider the following component definition: - +```angular-ts const template = '
{{hero().name}}
'; @@ -199,13 +199,13 @@ export class HeroComponent { hero = input.required(); } -
+``` The compiler could not refer to the `template` constant because it isn't exported. The collector, however, can fold the `template` constant into the metadata definition by in-lining its contents. The effect is the same as if you had written: - +```angular-ts @Component({ selector: 'app-hero', @@ -215,13 +215,13 @@ export class HeroComponent { hero = input.required(); } - +``` There is no longer a reference to `template` and, therefore, nothing to trouble the compiler when it later interprets the *collector's* output in `.metadata.json`. You can take this example a step further by including the `template` constant in another expression: - +```angular-ts const template = '
{{hero().name}}
'; @@ -233,15 +233,15 @@ export class HeroComponent { hero = input.required(); } -
+``` The collector reduces this expression to its equivalent *folded* string: - +```angular-ts '
{{hero().name}}
{{hero().title}}
' -
+``` #### Foldable syntax @@ -307,37 +307,37 @@ The compiler, however, only supports macros in the form of functions or static m For example, consider the following function: - +```ts export function wrapInArray(value: T): T[] { return [value]; } - +``` You can call the `wrapInArray` in a metadata definition because it returns the value of an expression that conforms to the compiler's restrictive JavaScript subset. You might use `wrapInArray()` like this: - +```ts @NgModule({ declarations: wrapInArray(TypicalComponent) }) export class TypicalModule {} - +``` The compiler treats this usage as if you had written: - +```ts @NgModule({ declarations: [TypicalComponent] }) export class TypicalModule {} - +``` The Angular [`RouterModule`](api/router/RouterModule) exports two macro static methods, `forRoot` and `forChild`, to help declare root and child routes. Review the [source code](https://github.com/angular/angular/blob/main/packages/router/src/router_module.ts#L139 "RouterModule.forRoot source code") @@ -351,7 +351,7 @@ the compiler doesn't need to know the expression's value — it just needs to be You might write something like: - +```ts class TypicalServer { @@ -362,12 +362,12 @@ class TypicalServer { }) export class TypicalModule {} - +``` Without rewriting, this would be invalid because lambdas are not supported and `TypicalServer` is not exported. To allow this, the compiler automatically rewrites this to something like: - +```ts class TypicalServer { @@ -380,7 +380,7 @@ export const θ0 = () => new TypicalServer(); }) export class TypicalModule {} - +``` This allows the compiler to generate a reference to `θ0` in the factory without having to know what the value of `θ0` contains. @@ -402,7 +402,7 @@ file. For example, consider the following component: - +```angular-ts @Component({ selector: 'my-component', @@ -412,7 +412,7 @@ class MyComponent { person?: Person; } - +``` This produces the following error: @@ -449,7 +449,7 @@ The expression used in an `ngIf` directive is used to narrow type unions in the template compiler, the same way the `if` expression does in TypeScript. For example, to avoid `Object is possibly 'undefined'` error in the template above, modify it to only emit the interpolation if the value of `person` is initialized as shown below: - +```angular-ts @Component({ selector: 'my-component', @@ -459,7 +459,7 @@ class MyComponent { person?: Person; } - +``` Using `*ngIf` allows the TypeScript compiler to infer that the `person` used in the binding expression will never be `undefined`. @@ -472,7 +472,7 @@ Use the non-null type assertion operator to suppress the `Object is possibly 'un In the following example, the `person` and `address` properties are always set together, implying that `address` is always non-null if `person` is non-null. There is no convenient way to describe this constraint to TypeScript and the template compiler, but the error is suppressed in the example by using `address!.street`. - +```ts @Component({ selector: 'my-component', @@ -488,13 +488,13 @@ class MyComponent { } } - +``` The non-null assertion operator should be used sparingly as refactoring of the component might break this constraint. In this example it is recommended to include the checking of `address` in the `*ngIf` as shown below: - +```ts @Component({ selector: 'my-component', @@ -510,4 +510,4 @@ class MyComponent { } } - +``` diff --git a/adev/src/content/tools/cli/build-system-migration.md b/adev/src/content/tools/cli/build-system-migration.md index 6e5b238e0085..51eec62be102 100644 --- a/adev/src/content/tools/cli/build-system-migration.md +++ b/adev/src/content/tools/cli/build-system-migration.md @@ -36,11 +36,11 @@ The errors will attempt to provide solutions to the problem when possible and th When updating to Angular v18 via `ng update`, you will be asked to execute the migration. This migration is entirely optional for v18 and can also be run manually at anytime after an update via the following command: - +```shell ng update @angular/cli --name use-application-builder - +``` The migration does the following: diff --git a/adev/src/content/tools/cli/build.md b/adev/src/content/tools/cli/build.md index 8f7367e5fbdb..a7507182ad12 100644 --- a/adev/src/content/tools/cli/build.md +++ b/adev/src/content/tools/cli/build.md @@ -6,20 +6,19 @@ This will compile your TypeScript code to JavaScript, as well as optimize, bundl `ng build` only executes the builder for the `build` target in the default project as specified in `angular.json`. Angular CLI includes four builders typically used as `build` targets: -| Builder | Purpose | -| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `@angular-devkit/build-angular:application` | Builds an application with a client-side bundle, a Node server, and build-time prerendered routes with [esbuild](https://esbuild.github.io/). | +| Builder | Purpose | +| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `@angular-devkit/build-angular:application` | Builds an application with a client-side bundle, a Node server, and build-time prerendered routes with [esbuild](https://esbuild.github.io/). | | `@angular-devkit/build-angular:browser-esbuild` | Bundles a client-side application for use in a browser with [esbuild](https://esbuild.github.io/). See [`browser-esbuild` documentation](tools/cli/build-system-migration#manual-migration-to-the-compatibility-builder) for more information. | -| `@angular-devkit/build-angular:browser` | Bundles a client-side application for use in a browser with [webpack](https://webpack.js.org/). | -| `@angular-devkit/build-angular:ng-packagr` | Builds an Angular library adhering to [Angular Package Format](tools/libraries/angular-package-format). | +| `@angular-devkit/build-angular:browser` | Bundles a client-side application for use in a browser with [webpack](https://webpack.js.org/). | +| `@angular-devkit/build-angular:ng-packagr` | Builds an Angular library adhering to [Angular Package Format](tools/libraries/angular-package-format). | Applications generated by `ng new` use `@angular-devkit/build-angular:application` by default. Libraries generated by `ng generate library` use `@angular-devkit/build-angular:ng-packagr` by default. You can determine which builder is being used for a particular project by looking up the `build` target for that project. - - +```json { "projects": { "my-app": { @@ -36,8 +35,7 @@ You can determine which builder is being used for a particular project by lookin } } } - - +``` This page discusses usage and options of `@angular-devkit/build-angular:application`. @@ -52,8 +50,7 @@ The CLI lets you set size thresholds in your configuration to ensure that parts Define your size boundaries in the CLI configuration file, `angular.json`, in a `budgets` section for each [configured environment](tools/cli/environments). - - +```json { … "configurations": { @@ -69,8 +66,7 @@ Define your size boundaries in the CLI configuration file, `angular.json`, in a } } } - - +``` You can specify size budgets for the entire app, and for particular parts. Each budget entry configures a budget of a given type. @@ -87,17 +83,17 @@ When you configure a budget, the builder warns or reports an error when a given Each budget entry is a JSON object with the following properties: -| Property | Value | -| :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Property | Value | +| :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | type | The type of budget. One of:
Value Details
bundle The size of a specific bundle.
initial The size of JavaScript and CSS needed for bootstrapping the application. Defaults to warning at 500kb and erroring at 1mb.
allScript The size of all scripts.
all The size of the entire application.
anyComponentStyle This size of any one component stylesheet. Defaults to warning at 2kb and erroring at 4kb.
anyScript The size of any one script.
any The size of any file.
| -| name | The name of the bundle (for `type=bundle`). | -| baseline | The baseline size for comparison. | -| maximumWarning | The maximum threshold for warning relative to the baseline. | -| maximumError | The maximum threshold for error relative to the baseline. | -| minimumWarning | The minimum threshold for warning relative to the baseline. | -| minimumError | The minimum threshold for error relative to the baseline. | -| warning | The threshold for warning relative to the baseline (min & max). | -| error | The threshold for error relative to the baseline (min & max). | +| name | The name of the bundle (for `type=bundle`). | +| baseline | The baseline size for comparison. | +| maximumWarning | The maximum threshold for warning relative to the baseline. | +| maximumError | The maximum threshold for error relative to the baseline. | +| minimumWarning | The minimum threshold for warning relative to the baseline. | +| minimumError | The minimum threshold for error relative to the baseline. | +| warning | The threshold for warning relative to the baseline (min & max). | +| error | The threshold for error relative to the baseline (min & max). | ## Configuring CommonJS dependencies @@ -112,8 +108,7 @@ Angular CLI outputs warnings if it detects that your browser application depends When you encounter a CommonJS dependency, consider asking the maintainer to support ECMAScript modules, contributing that support yourself, or using an alternative dependency which meets your needs. If the best option is to use a CommonJS dependency, you can disable these warnings by adding the CommonJS module name to `allowedCommonJsDependencies` option in the `build` options located in `angular.json`. - - +```json "build": { "builder": "@angular-devkit/build-angular:browser", "options": { @@ -124,8 +119,7 @@ If the best option is to use a CommonJS dependency, you can disable these warnin } … }, - - +``` ## Configuring browser compatibility @@ -146,4 +140,11 @@ HELPFUL: Use [browsersl.ist](https://browsersl.ist) to display compatible browse Angular supports [Tailwind CSS](https://tailwindcss.com/), a utility-first CSS framework. -To integrate Tailwind CSS with Angular CLI, see [Using Tailwind CSS with Angular](guide/tailwind) \ No newline at end of file +To integrate Tailwind CSS with Angular CLI, see [Using Tailwind CSS with Angular](guide/tailwind) + +## Critical CSS inlining + +Angular can inline the critical CSS definitions of your application to improve [First Contentful Paint (FCP)](https://web.dev/first-contentful-paint). +This option is enabled default. You can disable this inlining in the [`styles` customization options](reference/configs/workspace-config#styles-optimization-options). + +This optimization extracts the CSS needed to render the initial viewport and inlines it directly into the generated HTML, allowing the browser to display content faster without waiting for the full stylesheets to load. The remaining CSS then loads asynchronously in the background. Angular CLI uses [Beasties](https://github.com/danielroe/beasties) to analyze your application’s HTML and styles. diff --git a/adev/src/content/tools/cli/cli-builder.md b/adev/src/content/tools/cli/cli-builder.md index 33e18ef02197..15ef01255319 100644 --- a/adev/src/content/tools/cli/cli-builder.md +++ b/adev/src/content/tools/cli/cli-builder.md @@ -1,7 +1,7 @@ # Angular CLI builders A number of Angular CLI commands run a complex process on your code, such as building, testing, or serving your application. -The commands use an internal tool called Architect to run *CLI builders*, which invoke another tool (bundler, test runner, server) to accomplish the desired task. +The commands use an internal tool called Architect to run _CLI builders_, which invoke another tool (bundler, test runner, server) to accomplish the desired task. Custom builders can perform an entirely new task, or to change which third-party tool is used by an existing command. This document explains how CLI builders integrate with the workspace configuration file, and shows how you can create your own builder. @@ -10,19 +10,19 @@ HELPFUL: Find the code from the examples used here in this [GitHub repository](h ## CLI builders -The internal Architect tool delegates work to handler functions called *builders*. +The internal Architect tool delegates work to handler functions called _builders_. A builder handler function receives two arguments: | Argument | Type | -|:--- |:--- | +| :-------- | :--------------- | | `options` | `JSONObject` | | `context` | `BuilderContext` | The separation of concerns here is the same as with [schematics](tools/cli/schematics-authoring), which are used for other CLI commands that touch your code (such as `ng generate`). -* The `options` object is provided by the CLI user's options and configuration, while the `context` object is provided by the CLI Builder API automatically. -* In addition to the contextual information, the `context` object also provides access to a scheduling method, `context.scheduleTarget()`. - The scheduler executes the builder handler function with a given target configuration. +- The `options` object is provided by the CLI user's options and configuration, while the `context` object is provided by the CLI Builder API automatically. +- In addition to the contextual information, the `context` object also provides access to a scheduling method, `context.scheduleTarget()`. + The scheduler executes the builder handler function with a given target configuration. The builder handler function can be synchronous (return a value), asynchronous (return a `Promise`), or watch and return multiple values (return an `Observable`). The return values must always be of type `BuilderOutput`. @@ -38,7 +38,7 @@ A builder resides in a "project" folder that is similar in structure to an Angul For example, your `myBuilder` folder could contain the following files. | Files | Purpose | -|:--- | :--- | +| :----------------------- | :-------------------------------------------------------------------------------------------------------- | | `src/my-builder.ts` | Main source file for the builder definition. | | `src/my-builder.spec.ts` | Source file for tests. | | `src/schema.json` | Definition of builder input options. | @@ -92,7 +92,7 @@ Pass an empty string to remove the status. ## Builder input You can invoke a builder indirectly through a CLI command such as `ng build`, or directly with the Angular CLI `ng run` command. -In either case, you must provide required inputs, but can let other inputs default to values that are pre-configured for a specific *target*, specified by a [configuration](tools/cli/environments), or set on the command line. +In either case, you must provide required inputs, but can let other inputs default to values that are pre-configured for a specific _target_, specified by a [configuration](tools/cli/environments), or set on the command line. ### Input validation @@ -107,16 +107,16 @@ You can provide the following schema for type validation of these values. { - "$schema": "http://json-schema.org/schema", - "type": "object", - "properties": { - "source": { - "type": "string" - }, - "destination": { - "type": "string" - } - } +"$schema": "http://json-schema.org/schema", +"type": "object", +"properties": { +"source": { +"type": "string" +}, +"destination": { +"type": "string" +} +} } @@ -124,7 +124,7 @@ You can provide the following schema for type validation of these values. HELPFUL: This is a minimal example, but the use of a schema for validation can be very powerful. For more information, see the [JSON schemas website](http://json-schema.org). -To link our builder implementation with its schema and name, you need to create a *builder definition* file, which you can point to in `package.json`. +To link our builder implementation with its schema and name, you need to create a _builder definition_ file, which you can point to in `package.json`. Create a file named `builders.json` that looks like this: @@ -221,14 +221,14 @@ Specify further option overrides individually on the command line. The generic `ng run` CLI command takes as its first argument a target string of the following form. - +```shell project:target[:configuration] - +``` -| | Details | -|:--- |:--- | +| | Details | +| :------------ | :-------------------------------------------------------------------------------------------------------------------- | | project | The name of the Angular CLI project that the target is associated with. | | target | A named builder configuration from the `architect` section of the `angular.json` file. | | configuration | (optional) The name of a specific configuration override for the given target, as defined in the `angular.json` file. | @@ -255,7 +255,7 @@ For more information see [Workspace Configuration](reference/configs/workspace-c HELPFUL: You can also invoke a builder directly from another builder or test by calling `context.scheduleBuilder()`. You pass an `options` object directly to the method, and those option values are validated against the schema of the builder without further adjustment. -Only the `context.scheduleTarget()` method resolves the configuration and overrides through the `angular.json` file. +Only the `context.scheduleTarget()` method resolves the configuration and overrides through the `angular.json` file. ### Default architect configuration @@ -263,11 +263,11 @@ Let's create a simple `angular.json` file that puts target configurations into c You can publish the builder to npm (see [Publishing your Library](tools/libraries/creating-libraries#publishing-your-library)), and install it using the following command: - +```shell npm install @example/copy-file - +``` If you create a new project with `ng new builder-test`, the generated `angular.json` file looks something like this, with only default builder configurations. @@ -300,7 +300,6 @@ If you create a new project with `ng new builder-test`, the generated `angular.j } } } -
### Adding a target @@ -308,13 +307,13 @@ If you create a new project with `ng new builder-test`, the generated `angular.j Add a new target that will run our builder to copy a file. This target tells the builder to copy the `package.json` file. -* We will add a new target section to the `architect` object for our project -* The target named `copy-package` uses our builder, which you published to `@example/copy-file`. -* The options object provides default values for the two inputs that you defined. - * `source` - The existing file you are copying. - * `destination` - The path you want to copy to. +- We will add a new target section to the `architect` object for our project +- The target named `copy-package` uses our builder, which you published to `@example/copy-file`. +- The options object provides default values for the two inputs that you defined. + - `source` - The existing file you are copying. + - `destination` - The path you want to copy to. - +< header="angular.json" language="json"> { "projects": { @@ -333,32 +332,31 @@ This target tells the builder to copy the `package.json` file. } } } - ### Running the builder To run our builder with the new target's default configuration, use the following CLI command. - +```shell ng run builder-test:copy-package - +``` This copies the `package.json` file to `package-copy.json`. Use command-line arguments to override the configured defaults. For example, to run with a different `destination` value, use the following CLI command. - +```shell ng run builder-test:copy-package --destination=package-other.json - +``` This copies the file to `package-other.json` instead of `package-copy.json`. -Because you did not override the *source* option, it will still copy from the default `package.json` file. +Because you did not override the _source_ option, it will still copy from the default `package.json` file. ## Testing a builder @@ -378,21 +376,21 @@ You can avoid this by renaming `my-builder.spec.ts` to `my-builder.spec.js`. Most builders to run once and return. However, this behavior is not entirely compatible with a builder that watches for changes (like a devserver, for example). Architect can support watch mode, but there are some things to look out for. -* To be used with watch mode, a builder handler function should return an `Observable`. - Architect subscribes to the `Observable` until it completes and might reuse it if the builder is scheduled again with the same arguments. +- To be used with watch mode, a builder handler function should return an `Observable`. + Architect subscribes to the `Observable` until it completes and might reuse it if the builder is scheduled again with the same arguments. -* The builder should always emit a `BuilderOutput` object after each execution. - Once it's been executed, it can enter a watch mode, to be triggered by an external event. - If an event triggers it to restart, the builder should execute the `context.reportRunning()` function to tell Architect that it is running again. - This prevents Architect from stopping the builder if another run is scheduled. +- The builder should always emit a `BuilderOutput` object after each execution. + Once it's been executed, it can enter a watch mode, to be triggered by an external event. + If an event triggers it to restart, the builder should execute the `context.reportRunning()` function to tell Architect that it is running again. + This prevents Architect from stopping the builder if another run is scheduled. When your builder calls `BuilderRun.stop()` to exit watch mode, Architect unsubscribes from the builder's `Observable` and calls the builder's teardown logic to clean up. This behavior also allows for long-running builds to be stopped and cleaned up. In general, if your builder is watching an external event, you should separate your run into three phases. -| Phases | Details | -|:--- |:--- | +| Phases | Details | +| :--------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Running | The task being performed, such as invoking a compiler. This ends when the compiler finishes and your builder emits a `BuilderOutput` object. | | Watching | Between two runs, watch an external event stream. For example, watch the file system for any changes. This ends when the compiler restarts, and `context.reportRunning()` is called. | | Completion | Either the task is fully completed, such as a compiler which needs to run a number of times, or the builder run was stopped (using `BuilderRun.stop()`). Architect executes teardown logic and unsubscribes from your builder's `Observable`. | @@ -401,7 +399,7 @@ In general, if your builder is watching an external event, you should separate y The CLI Builder API provides a means of changing the behavior of the Angular CLI by using builders to execute custom logic. -* Builders can be synchronous or asynchronous, execute once or watch for external events, and can schedule other builders or targets. -* Builders have option defaults specified in the `angular.json` configuration file, which can be overwritten by an alternate configuration for the target, and further overwritten by command line flags -* The Angular team recommends that you use integration tests to test Architect builders. Use unit tests to validate the logic that the builder executes. -* If your builder returns an `Observable`, it should clean up the builder in the teardown logic of that `Observable`. +- Builders can be synchronous or asynchronous, execute once or watch for external events, and can schedule other builders or targets. +- Builders have option defaults specified in the `angular.json` configuration file, which can be overwritten by an alternate configuration for the target, and further overwritten by command line flags +- The Angular team recommends that you use integration tests to test Architect builders. Use unit tests to validate the logic that the builder executes. +- If your builder returns an `Observable`, it should clean up the builder in the teardown logic of that `Observable`. diff --git a/adev/src/content/tools/cli/deployment.md b/adev/src/content/tools/cli/deployment.md index d69b3e1b8e96..bed7aceb79ae 100644 --- a/adev/src/content/tools/cli/deployment.md +++ b/adev/src/content/tools/cli/deployment.md @@ -13,12 +13,12 @@ You can then use the `ng deploy` command to deploy that project. For example, the following command automatically deploys a project to [Firebase](https://firebase.google.com/). - +```shell ng add @angular/fire ng deploy - +``` The command is interactive. In this case, you must have or create a Firebase account and authenticate using it. @@ -28,10 +28,10 @@ The table below lists tools which implement deployment functionality to differen The `deploy` command for each package may require different command line options. You can read more by following the links associated with the package names below: -| Deployment to | Setup Command | -|:--- |:--- | +| Deployment to | Setup Command | +| :---------------------------------------------------------------- | :------------------------------------------------------------------------------------------ | | [Firebase hosting](https://firebase.google.com/docs/hosting) | [`ng add @angular/fire`](https://npmjs.org/package/@angular/fire) | -| [Vercel](https://vercel.com/solutions/angular) | [`vercel init angular`](https://github.com/vercel/vercel/tree/main/examples/angular) | +| [Vercel](https://vercel.com/solutions/angular) | [`vercel init angular`](https://github.com/vercel/vercel/tree/main/examples/angular) | | [Netlify](https://www.netlify.com) | [`ng add @netlify-builder/deploy`](https://npmjs.org/package/@netlify-builder/deploy) | | [GitHub pages](https://pages.github.com) | [`ng add angular-cli-ghpages`](https://npmjs.org/package/angular-cli-ghpages) | | [Amazon Cloud S3](https://aws.amazon.com/s3/?nc2=h_ql_prod_st_s3) | [`ng add @jefiozie/ngx-aws-deploy`](https://www.npmjs.com/package/@jefiozie/ngx-aws-deploy) | @@ -60,17 +60,17 @@ Client-side rendered Angular applications are perfect candidates for serving wit If the application uses the Angular router, you must configure the server to return the application's host page (`index.html`) when asked for a file that it does not have. A routed application should support "deep links". -A *deep link* is a URL that specifies a path to a component inside the application. -For example, `http://my-app.test/users/42` is a *deep link* to the user detail page that displays the user with `id` 42. +A _deep link_ is a URL that specifies a path to a component inside the application. +For example, `http://my-app.test/users/42` is a _deep link_ to the user detail page that displays the user with `id` 42. There is no issue when the user initially loads the index page and then navigates to that URL from within a running client. -The Angular router performs the navigation *client-side* and does not request a new HTML page. +The Angular router performs the navigation _client-side_ and does not request a new HTML page. -But clicking a deep link in an email, entering it in the browser address bar, or even refreshing the browser while already on the deep linked page will all be handled by the browser itself, *outside* the running application. +But clicking a deep link in an email, entering it in the browser address bar, or even refreshing the browser while already on the deep linked page will all be handled by the browser itself, _outside_ the running application. The browser makes a direct request to the server for `/users/42`, bypassing Angular's router. A static server routinely returns `index.html` when it receives a request for `http://my-app.test/`. -But most servers by default will reject `http://my-app.test/users/42` and returns a `404 - Not Found` error *unless* it is configured to return `index.html` instead. +But most servers by default will reject `http://my-app.test/users/42` and returns a `404 - Not Found` error _unless_ it is configured to return `index.html` instead. Configure the fallback route or 404 page to `index.html` for your server, so Angular is served for deep links and can display the correct route. Some servers call this fallback behavior "Single-Page Application" (SPA) mode. @@ -81,25 +81,25 @@ For "real" 404 pages such as `http://my-app.test/does-not-exist`, the server doe ### Requesting data from a different server (CORS) -Web developers may encounter a [*cross-origin resource sharing*](https://developer.mozilla.org/docs/Web/HTTP/CORS "Cross-origin resource sharing") error when making a network request to a server other than the application's own host server. +Web developers may encounter a [_cross-origin resource sharing_](https://developer.mozilla.org/docs/Web/HTTP/CORS 'Cross-origin resource sharing') error when making a network request to a server other than the application's own host server. Browsers forbid such requests unless the server explicitly permits them. There isn't anything Angular or the client application can do about these errors. The _server_ must be configured to accept the application's requests. -Read about how to enable CORS for specific servers at [enable-cors.org](https://enable-cors.org/server.html "Enabling CORS server"). +Read about how to enable CORS for specific servers at [enable-cors.org](https://enable-cors.org/server.html 'Enabling CORS server'). ## Production optimizations `ng build` uses the `production` configuration unless configured otherwise. This configuration enables the following build optimization features. -| Features | Details | -|:--- |:--- | -| [Ahead-of-Time (AOT) Compilation](tools/cli/aot-compiler) | Pre-compiles Angular component templates. | +| Features | Details | +| :---------------------------------------------------------------- | :-------------------------------------------------------------------------------------------- | +| [Ahead-of-Time (AOT) Compilation](tools/cli/aot-compiler) | Pre-compiles Angular component templates. | | [Production mode](tools/cli/deployment#development-only-features) | Optimizes the application for the best runtime performance | -| Bundling | Concatenates your many application and library files into a minimum number of deployed files. | -| Minification | Removes excess whitespace, comments, and optional tokens. | -| Mangling | Renames functions, classes, and variables to use shorter, arbitrary identifiers. | -| Dead code elimination | Removes unreferenced modules and unused code. | +| Bundling | Concatenates your many application and library files into a minimum number of deployed files. | +| Minification | Removes excess whitespace, comments, and optional tokens. | +| Mangling | Renames functions, classes, and variables to use shorter, arbitrary identifiers. | +| Dead code elimination | Removes unreferenced modules and unused code. | See [`ng build`](cli/build) for more about CLI build options and their effects. @@ -108,9 +108,9 @@ See [`ng build`](cli/build) for more about CLI build options and their effects. When you run an application locally using `ng serve`, Angular uses the development configuration at runtime which enables: -* Extra safety checks such as [`expression-changed-after-checked`](errors/NG0100) detection. -* More detailed error messages. -* Additional debugging utilities such as the global `ng` variable with [debugging functions](api#core-global) and [Angular DevTools](tools/devtools) support. +- Extra safety checks such as [`expression-changed-after-checked`](errors/NG0100) detection. +- More detailed error messages. +- Additional debugging utilities such as the global `ng` variable with [debugging functions](api#core-global) and [Angular DevTools](tools/devtools) support. These features are helpful during development, but they require extra code in the app, which is undesirable in production. To ensure these features do not negatively impact bundle size for end users, Angular CLI @@ -120,13 +120,13 @@ Building your application with `ng build` by default uses the `production` confi ## `--deploy-url` -`--deploy-url` is a command line option used to specify the base path for resolving relative URLs for assets such as images, scripts, and style sheets at *compile* time. +`--deploy-url` is a command line option used to specify the base path for resolving relative URLs for assets such as images, scripts, and style sheets at _compile_ time. - +```shell ng build --deploy-url /my/assets - +``` The effect and purpose of `--deploy-url` overlaps with [``](guide/routing/common-router-tasks). Both can be used for initial scripts, stylesheets, lazy scripts, and css resources. diff --git a/adev/src/content/tools/cli/end-to-end.md b/adev/src/content/tools/cli/end-to-end.md index c1f888b49788..e763f9254f91 100644 --- a/adev/src/content/tools/cli/end-to-end.md +++ b/adev/src/content/tools/cli/end-to-end.md @@ -6,15 +6,15 @@ End-to-end or (E2E) testing is a form of testing used to assert your entire appl The Angular CLI downloads and installs everything you need to run end-to-end tests for your Angular application. - +```shell ng e2e - +``` The `ng e2e` command will first check your project for the "e2e" target. If it can't locate it, the CLI will then prompt you which e2e package you would like to use and walk you through the setup. - +```shell Cannot find "e2e" target for the specified project. You can add a package that implements these capabilities. @@ -34,7 +34,7 @@ WebdriverIO Playwright Puppeteer - +``` If you don't find the test runner you would like to use from the list above, you can manually add a package using `ng add`. @@ -42,11 +42,11 @@ If you don't find the test runner you would like to use from the list above, you Now that your application is configured for end-to-end testing we can now run the same command to execute your tests. - +```shell ng e2e - +``` Note, their isn't anything "special" about running your tests with any of the integrated e2e packages. The `ng e2e` command is really just running the `e2e` builder under the hood. You can always [create your own custom builder](tools/cli/cli-builder#creating-a-builder) named `e2e` and run it using `ng e2e`. diff --git a/adev/src/content/tools/cli/environments.md b/adev/src/content/tools/cli/environments.md index a9a667acd770..7fe7b278cec1 100644 --- a/adev/src/content/tools/cli/environments.md +++ b/adev/src/content/tools/cli/environments.md @@ -9,7 +9,7 @@ The [Angular CLI](tools/cli) `build`, `serve`, and `test` commands can then repl Angular CLI builders support a `configurations` object, which allows overwriting specific options for a builder based on the configuration provided on the command line. - +```json { "projects": { @@ -34,23 +34,23 @@ Angular CLI builders support a `configurations` object, which allows overwriting } } - +``` You can choose which configuration to use with the `--configuration` option. - +```shell ng build --configuration debug - +``` Configurations can be applied to any Angular CLI builder. Multiple configurations can be specified with a comma separator. The configurations are applied in order, with conflicting options using the value from the last configuration. - +```shell ng build --configuration debug,production,customer-facing - +``` ## Configure environment-specific defaults @@ -59,84 +59,84 @@ Using this in combination with `--configuration` provides a mechanism for config Start by [generating environments](cli/generate/environments) to create the `src/environments/` directory and configure the project to use file replacements. - +```shell ng generate environments - +``` The project's `src/environments/` directory contains the base configuration file, `environment.ts`, which provides the default configuration for production. You can override default values for additional environments, such as `development` and `staging`, in target-specific configuration files. For example: - +```text my-app/src/environments ├── environment.development.ts ├── environment.staging.ts └── environment.ts - +``` The base file `environment.ts`, contains the default environment settings. For example: - +```ts export const environment = { production: true }; - +``` The `build` command uses this as the build target when no environment is specified. You can add further variables, either as additional properties on the environment object, or as separate objects. For example, the following adds a default for a variable to the default environment: - +```ts export const environment = { production: true, apiUrl: 'http://my-prod-url' }; - +``` You can add target-specific configuration files, such as `environment.development.ts`. The following content sets default values for the development build target: - +```ts export const environment = { production: false, apiUrl: 'http://my-dev-url' }; - +``` ## Using environment-specific variables in your app To use the environment configurations you have defined, your components must import the original environments file: - +```ts import { environment } from './environments/environment'; - +``` This ensures that the build and serve commands can find the configurations for specific build targets. The following code in the component file (`app.component.ts`) uses an environment variable defined in the configuration files. - +```ts import { environment } from './../environments/environment'; // Fetches from `http://my-prod-url` in production, `http://my-dev-url` in development. fetch(environment.apiUrl); - +``` The main CLI configuration file, `angular.json`, contains a `fileReplacements` section in the configuration for each build target, which lets you replace any file in the TypeScript program with a target-specific version of that file. This is useful for including target-specific code or variables in a build that targets a specific environment, such as production or staging. @@ -144,7 +144,7 @@ This is useful for including target-specific code or variables in a build that t By default no files are replaced, however `ng generate environments` sets up this configuration automatically. You can change or add file replacements for specific build targets by editing the `angular.json` configuration directly. - +```json "configurations": { "development": { @@ -156,13 +156,13 @@ You can change or add file replacements for specific build targets by editing th ], … - +``` This means that when you build your development configuration with `ng build --configuration development`, the `src/environments/environment.ts` file is replaced with the target-specific version of the file, `src/environments/environment.development.ts`. To add a staging environment, create a copy of `src/environments/environment.ts` called `src/environments/environment.staging.ts`, then add a `staging` configuration to `angular.json`: - +```json "configurations": { "development": { … }, @@ -177,23 +177,23 @@ To add a staging environment, create a copy of `src/environments/environment.ts` } } - +``` You can add more configuration options to this target environment as well. Any option that your build supports can be overridden in a build target configuration. To build using the staging configuration, run the following command: - +```shell ng build --configuration staging - +``` By default, the `build` target includes `production` and `development` configurations and `ng serve` uses the development build of the application. You can also configure `ng serve` to use the targeted build configuration if you set the `buildTarget` option: - +```json "serve": { "builder": "@angular-devkit/build-angular:dev-server", @@ -211,7 +211,7 @@ You can also configure `ng serve` to use the targeted build configuration if you "defaultConfiguration": "development" }, - +``` The `defaultConfiguration` option specifies which configuration is used by default. When `defaultConfiguration` is not set, `options` are used directly without modification. diff --git a/adev/src/content/tools/cli/schematics-authoring.md b/adev/src/content/tools/cli/schematics-authoring.md index 06f0295fc323..221295bf7dd0 100644 --- a/adev/src/content/tools/cli/schematics-authoring.md +++ b/adev/src/content/tools/cli/schematics-authoring.md @@ -15,25 +15,25 @@ When a schematic runs, the transformations are recorded in memory, and only appl The public API for schematics defines classes that represent the basic concepts. -* The virtual file system is represented by a `Tree`. - The `Tree` data structure contains a *base* \(a set of files that already exists\) and a *staging area* \(a list of changes to be applied to the base\). - When making modifications, you don't actually change the base, but add those modifications to the staging area. +- The virtual file system is represented by a `Tree`. + The `Tree` data structure contains a _base_ \(a set of files that already exists\) and a _staging area_ \(a list of changes to be applied to the base\). + When making modifications, you don't actually change the base, but add those modifications to the staging area. -* A `Rule` object defines a function that takes a `Tree`, applies transformations, and returns a new `Tree`. - The main file for a schematic, `index.ts`, defines a set of rules that implement the schematic's logic. +- A `Rule` object defines a function that takes a `Tree`, applies transformations, and returns a new `Tree`. + The main file for a schematic, `index.ts`, defines a set of rules that implement the schematic's logic. -* A transformation is represented by an `Action`. - There are four action types: `Create`, `Rename`, `Overwrite`, and `Delete`. +- A transformation is represented by an `Action`. + There are four action types: `Create`, `Rename`, `Overwrite`, and `Delete`. -* Each schematic runs in a context, represented by a `SchematicContext` object. +- Each schematic runs in a context, represented by a `SchematicContext` object. The context object passed into a rule provides access to utility functions and metadata that the schematic might need to work with, including a logging API to help with debugging. -The context also defines a *merge strategy* that determines how changes are merged from the staged tree into the base tree. +The context also defines a _merge strategy_ that determines how changes are merged from the staged tree into the base tree. A change can be accepted or ignored, or throw an exception. ### Defining rules and actions -When you create a new blank schematic with the [Schematics CLI](#schematics-cli), the generated entry function is a *rule factory*. +When you create a new blank schematic with the [Schematics CLI](#schematics-cli), the generated entry function is a _rule factory_. A `RuleFactory` object defines a higher-order function that creates a `Rule`. @@ -99,7 +99,7 @@ See examples of schema files for the Angular CLI command schematics in [`@schema ### Schematic prompts -Schematic *prompts* introduce user interaction into schematic execution. +Schematic _prompts_ introduce user interaction into schematic execution. Configure schematic options to display a customizable question to the user. The prompts are displayed before the execution of the schematic, which then uses the response as the value for the option. This lets users direct the operation of the schematic without requiring in-depth knowledge of the full spectrum of available options. @@ -140,21 +140,21 @@ In this case, "yes" corresponds to `true` and "no" corresponds to `false`. There are three supported input types. -| Input type | Details | -|:--- |:---- | +| Input type | Details | +| :----------- | :------------------------------------------------- | | confirmation | A yes or no question; ideal for Boolean options. | | input | Textual input; ideal for string or number options. | | list | A predefined set of allowed values. | In the short form, the type is inferred from the property's type and constraints. -| Property schema | Prompt type | -|:--- |:--- | -| "type": "boolean" | confirmation \("yes"=`true`, "no"=`false`\) | -| "type": "string" | input | -| "type": "number" | input \(only valid numbers accepted\) | -| "type": "integer" | input \(only valid numbers accepted\) | -| "enum": […] | list \(enum members become list selections\) | +| Property schema | Prompt type | +| :---------------- | :------------------------------------------- | +| "type": "boolean" | confirmation \("yes"=`true`, "no"=`false`\) | +| "type": "string" | input | +| "type": "number" | input \(only valid numbers accepted\) | +| "type": "integer" | input \(only valid numbers accepted\) | +| "enum": […] | list \(enum members become list selections\) | In the following example, the property takes an enumerated value, so the schematic automatically chooses the list type, and creates a menu from the possible values. @@ -185,8 +185,8 @@ This ensures that any values passed to the schematic meet the expectations of th The `x-prompt` field syntax supports a long form for cases where you require additional customization and control over the prompt. In this form, the `x-prompt` field value is a JSON object with subfields that customize the behavior of the prompt. -| Field | Data value | -|:--- |:--- | +| Field | Data value | +| :------ | :-------------------------------------------------------------------------- | | type | `confirmation`, `input`, or `list` \(selected automatically in short form\) | | message | string \(required\) | | items | string and/or label/value object pair \(only valid with type `list`\) | @@ -266,11 +266,11 @@ The following JSON schema is a complete description of the long-form syntax for Schematics come with their own command-line tool. Using Node 6.9 or later, install the Schematics command line tool globally: - +```shell npm install -g @angular-devkit/schematics-cli - +``` This installs the `schematics` executable, which you can use to create a new schematics collection in its own project folder, add a new schematic to an existing collection, or extend an existing schematic. @@ -284,11 +284,11 @@ See [Schematics for Libraries](tools/cli/schematics-for-libraries). The following command creates a new schematic named `hello-world` in a new project folder of the same name. - +```shell schematics blank --name=hello-world - +``` The `blank` schematic is provided by the Schematics CLI. The command creates a new project folder \(the root folder for the collection\) and an initial named schematic in the collection. @@ -296,14 +296,14 @@ The command creates a new project folder \(the root folder for the collection\) Go to the collection folder, install your npm dependencies, and open your new collection in your favorite editor to see the generated files. For example, if you are using VS Code: - +```shell cd hello-world npm install npm run build code . - +``` The initial schematic gets the same name as the project folder, and is generated in `src/hello-world`. Add related schematics to this collection, and modify the generated skeleton code to define your schematic's functionality. @@ -314,31 +314,31 @@ Each schematic name must be unique within the collection. Use the `schematics` command to run a named schematic. Provide the path to the project folder, the schematic name, and any mandatory options, in the following format. - +```shell schematics : --= - +``` The path can be absolute or relative to the current working directory where the command is executed. For example, to run the schematic you just generated \(which has no required options\), use the following command. - +```shell schematics .:hello-world - +``` ### Adding a schematic to a collection To add a schematic to an existing collection, use the same command you use to start a new schematics project, but run the command inside the project folder. - +```shell cd hello-world schematics blank --name=goodbye-world - +``` The command generates the new named schematic inside your collection, with a main `index.ts` file and its associated test spec. It also adds the name, description, and factory function for the new schematic to the collection's schema in the `collection.json` file. @@ -349,7 +349,7 @@ The top level of the root project folder for a collection contains configuration The `src/` folder contains subfolders for named schematics in the collection, and a schema, `collection.json`, which describes the collected schematics. Each schematic is created with a name, description, and factory function. - +```json { "$schema": @@ -362,37 +362,37 @@ Each schematic is created with a name, description, and factory function. } } - +``` -* The `$schema` property specifies the schema that the CLI uses for validation. -* The `schematics` property lists named schematics that belong to this collection. - Each schematic has a plain-text description, and points to the generated entry function in the main file. +- The `$schema` property specifies the schema that the CLI uses for validation. +- The `schematics` property lists named schematics that belong to this collection. + Each schematic has a plain-text description, and points to the generated entry function in the main file. -* The `factory` property points to the generated entry function. - In this example, you invoke the `hello-world` schematic by calling the `helloWorld()` factory function. +- The `factory` property points to the generated entry function. + In this example, you invoke the `hello-world` schematic by calling the `helloWorld()` factory function. -* The optional `schema` property points to a JSON schema file that defines the command-line options available to the schematic. -* The optional `aliases` array specifies one or more strings that can be used to invoke the schematic. - For example, the schematic for the Angular CLI "generate" command has an alias "g", that lets you use the command `ng g`. +- The optional `schema` property points to a JSON schema file that defines the command-line options available to the schematic. +- The optional `aliases` array specifies one or more strings that can be used to invoke the schematic. + For example, the schematic for the Angular CLI "generate" command has an alias "g", that lets you use the command `ng g`. ### Named schematics When you use the Schematics CLI to create a blank schematics project, the new blank schematic is the first member of the collection, and has the same name as the collection. -When you add a new named schematic to this collection, it is automatically added to the `collection.json` schema. +When you add a new named schematic to this collection, it is automatically added to the `collection.json` schema. In addition to the name and description, each schematic has a `factory` property that identifies the schematic's entry point. -In the example, you invoke the schematic's defined functionality by calling the `helloWorld()` function in the main file, `hello-world/index.ts`. +In the example, you invoke the schematic's defined functionality by calling the `helloWorld()` function in the main file, `hello-world/index.ts`. overview Each named schematic in the collection has the following main parts. -| Parts | Details | -|:--- |:--- | -| `index.ts` | Code that defines the transformation logic for a named schematic. | -| `schema.json` | Schematic variable definition. | -| `schema.d.ts` | Schematic variables. | -| `files/` | Optional component/template files to replicate. | +| Parts | Details | +| :------------ | :---------------------------------------------------------------- | +| `index.ts` | Code that defines the transformation logic for a named schematic. | +| `schema.json` | Schematic variable definition. | +| `schema.d.ts` | Schematic variables. | +| `files/` | Optional component/template files to replicate. | It is possible for a schematic to provide all of its logic in the `index.ts` file, without additional templates. You can create dynamic schematics for Angular, however, by providing components and templates in the `files` folder, like those in standalone Angular projects. diff --git a/adev/src/content/tools/cli/schematics-for-libraries.md b/adev/src/content/tools/cli/schematics-for-libraries.md index 44764926eb74..ad0264cd890c 100644 --- a/adev/src/content/tools/cli/schematics-for-libraries.md +++ b/adev/src/content/tools/cli/schematics-for-libraries.md @@ -95,11 +95,11 @@ You can add a named schematic to your collection that lets your users use the `n We'll assume that your library defines a service, `my-service`, that requires some setup. You want your users to be able to generate it using the following CLI command. - +```shell ng generate my-lib:my-service - +``` To begin, create a new subfolder, `my-service`, in the `schematics` folder. @@ -265,20 +265,20 @@ The following steps show you how to generate a service using the schematic you c From the root of your workspace, run the `ng build` command for your library. - +```shell ng build my-lib - +``` Then, you change into your library directory to build the schematic - +```shell cd projects/my-lib npm run build - +``` ### Link the library @@ -286,21 +286,21 @@ Your library and schematics are packaged and placed in the `dist/my-lib` folder For running the schematic, you need to link the library into your `node_modules` folder. From the root of your workspace, run the `npm link` command with the path to your distributable library. - +```shell npm link dist/my-lib - +``` ### Run the schematic Now that your library is installed, run the schematic using the `ng generate` command. - +```shell ng generate my-lib:my-service --name my-data - +``` In the console, you see that the schematic was run and the `my-data.service.ts` file was created in your application folder. diff --git a/adev/src/content/tools/cli/schematics.md b/adev/src/content/tools/cli/schematics.md index 7b0800d09177..8da6981c6737 100644 --- a/adev/src/content/tools/cli/schematics.md +++ b/adev/src/content/tools/cli/schematics.md @@ -19,19 +19,19 @@ The package contains named schematics that configure the options that are availa The sub-commands for `ng generate` are shorthand for the corresponding schematic. To specify and generate a particular schematic, or a collection of schematics, using the long form: - +```shell ng generate my-schematic-collection:my-schematic-name - +``` or - +```shell ng generate my-schematic-name --collection collection-name - +``` ### Configuring CLI schematics @@ -79,18 +79,18 @@ The documented sub-commands use the default Angular generation schematics, but y Angular Material, for example, supplies generation schematics for the UI components that it defines. The following command uses one of these schematics to render an Angular Material `` that is pre-configured with a datasource for sorting and pagination. - +```shell ng generate @angular/material:table - +``` ### Update schematics The `ng update` command can be used to update your workspace's library dependencies. If you supply no options or use the help option, the command examines your workspace and suggests libraries to update. - +```shell ng update We analyzed your package.json, there are some packages to update: @@ -103,7 +103,7 @@ We analyzed your package.json, there are some packages to update: @angular/material 7.2.2 -> 7.3.1 ng update @angular/material rxjs 6.3.3 -> 6.4.0 ng update rxjs - +``` If you pass the command a set of libraries to update, it updates those libraries, their peer dependencies, and the peer dependencies that depend on them. @@ -118,9 +118,9 @@ If you create a new version of your library that introduces potential breaking c For example, suppose you want to update the Angular Material library. - +```shell ng update @angular/material - +``` This command updates both `@angular/material` and its dependency `@angular/cdk` in your workspace's `package.json`. If either package contains an update schematic that covers migration from the existing version to a new version, the command runs that schematic on your workspace. diff --git a/adev/src/content/tools/cli/serve.md b/adev/src/content/tools/cli/serve.md index 1682cff84119..fe6761cb5702 100644 --- a/adev/src/content/tools/cli/serve.md +++ b/adev/src/content/tools/cli/serve.md @@ -9,7 +9,7 @@ While any builder can be used here, the most common (and default) builder is `@a You can determine which builder is being used for a particular project by looking up the `serve` target for that project. - +```json { "projects": { @@ -27,7 +27,7 @@ You can determine which builder is being used for a particular project by lookin } } - +``` This page discusses usage and options of `@angular-devkit/build-angular:dev-server`. @@ -39,37 +39,34 @@ For example, to divert all calls for `http://localhost:4200/api` to a server run 1. Create a file `proxy.conf.json` in your project's `src/` folder. 1. Add the following content to the new proxy file: - - - { - "/api": { - "target": "http://localhost:3000", - "secure": false - } - } - - +```json +{ + "/api": { + "target": "http://localhost:3000", + "secure": false + } +} +``` 1. In the CLI configuration file, `angular.json`, add the `proxyConfig` option to the `serve` target: - - - { - "projects": { - "my-app": { - "architect": { - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "proxyConfig": "src/proxy.conf.json" - } +```json +{ + "projects": { + "my-app": { + "architect": { + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "proxyConfig": "src/proxy.conf.json" } - } } } } + } +} - +``` 1. To run the development server with this proxy configuration, call `ng serve`. diff --git a/adev/src/content/tools/cli/setup-local.md b/adev/src/content/tools/cli/setup-local.md index 5bf15e8f1e4c..28bfc238ee8f 100644 --- a/adev/src/content/tools/cli/setup-local.md +++ b/adev/src/content/tools/cli/setup-local.md @@ -66,11 +66,11 @@ To install the Angular CLI, open a terminal window and run the following command On Windows client computers, the execution of PowerShell scripts is disabled by default, so the above command may fail with an error. To allow the execution of PowerShell scripts, which is needed for npm global binaries, you must set the following execution policy: - +```sh Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned - +``` Carefully read the message displayed after executing the command and follow the instructions. Make sure you understand the implications of setting an execution policy. @@ -111,11 +111,11 @@ You develop apps in the context of an Angular **workspace**. To create a new workspace and initial starter app, run the CLI command `ng new` and provide the name `my-app`, as shown here, then answer prompts about features to include: - +```shell ng new my-app - +``` The Angular CLI installs the necessary Angular npm packages and other dependencies. This can take a few minutes. @@ -123,21 +123,21 @@ This can take a few minutes. The CLI creates a new workspace and a small welcome app in a new directory with the same name as the workspace, ready to run. Navigate to the new directory so subsequent commands use this workspace. - +```shell cd my-app - +``` ## Run the application The Angular CLI includes a development server, for you to build and serve your app locally. Run the following command: - +```shell ng serve --open - +``` The `ng serve` command launches the server, watches your files, as well as rebuilds the app and reloads the browser as you make changes to those files. diff --git a/adev/src/content/tools/cli/template-typecheck.md b/adev/src/content/tools/cli/template-typecheck.md index a563f6823774..d78148cbb9ef 100644 --- a/adev/src/content/tools/cli/template-typecheck.md +++ b/adev/src/content/tools/cli/template-typecheck.md @@ -11,16 +11,16 @@ In the most basic type-checking mode, with the `fullTemplateTypeCheck` flag set If you write ``, the compiler verifies the following: -* `user` is a property on the component class -* `user` is an object with an address property -* `user.address` is an object with a city property +- `user` is a property on the component class +- `user` is an object with an address property +- `user.address` is an object with a city property The compiler does not verify that the value of `user.address.city` is assignable to the city input of the `` component. The compiler also has some major limitations in this mode: -* Importantly, it doesn't check embedded views, such as `*ngIf`, `*ngFor`, other `` embedded view. -* It doesn't figure out the types of `#refs`, the results of pipes, or the type of `$event` in event bindings. +- Importantly, it doesn't check embedded views, such as `*ngIf`, `*ngFor`, other `` embedded view. +- It doesn't figure out the types of `#refs`, the results of pipes, or the type of `$event` in event bindings. In many cases, these things end up as type `any`, which can cause subsequent parts of the expression to go unchecked. @@ -29,15 +29,15 @@ In many cases, these things end up as type `any`, which can cause subsequent par If the `fullTemplateTypeCheck` flag is set to `true`, Angular is more aggressive in its type-checking within templates. In particular: -* Embedded views \(such as those within an `*ngIf` or `*ngFor`\) are checked -* Pipes have the correct return type -* Local references to directives and pipes have the correct type \(except for any generic parameters, which will be `any`\) +- Embedded views \(such as those within an `*ngIf` or `*ngFor`\) are checked +- Pipes have the correct return type +- Local references to directives and pipes have the correct type \(except for any generic parameters, which will be `any`\) The following still have type `any`. -* Local references to DOM elements -* The `$event` object -* Safe navigation expressions +- Local references to DOM elements +- The `$event` object +- Safe navigation expressions IMPORTANT: The `fullTemplateTypeCheck` flag has been deprecated in Angular 13. The `strictTemplates` family of compiler options should be used instead. @@ -50,12 +50,12 @@ This flag supersedes the `fullTemplateTypeCheck` flag. In addition to the full mode behavior, Angular does the following: -* Verifies that component/directive bindings are assignable to their `input()`s -* Obeys TypeScript's `strictNullChecks` flag when validating the preceding mode -* Infers the correct type of components/directives, including generics -* Infers template context types where configured \(for example, allowing correct type-checking of `NgFor`\) -* Infers the correct type of `$event` in component/directive, DOM, and animation event bindings -* Infers the correct type of local references to DOM elements, based on the tag name \(for example, the type that `document.createElement` would return for that tag\) +- Verifies that component/directive bindings are assignable to their `input()`s +- Obeys TypeScript's `strictNullChecks` flag when validating the preceding mode +- Infers the correct type of components/directives, including generics +- Infers template context types where configured \(for example, allowing correct type-checking of `NgFor`\) +- Infers the correct type of `$event` in component/directive, DOM, and animation event bindings +- Infers the correct type of local references to DOM elements, based on the tag name \(for example, the type that `document.createElement` would return for that tag\) ## Checking of `*ngFor` @@ -74,14 +74,15 @@ interface User {
- + +```html

{{config.title}}

City: {{user.address.city}}
-
+``` The `

` and the `` are in the `*ngFor` embedded view. In basic mode, Angular doesn't check either of them. @@ -96,33 +97,33 @@ If this is the case, the error message should make it clear where in the templat There can also be false positives when the typings of an Angular library are either incomplete or incorrect, or when the typings don't quite line up with expectations as in the following cases. -* When a library's typings are wrong or incomplete \(for example, missing `null | undefined` if the library was not written with `strictNullChecks` in mind\) -* When a library's input types are too narrow and the library hasn't added appropriate metadata for Angular to figure this out. - This usually occurs with disabled or other common Boolean inputs used as attributes, for example, ``. +- When a library's typings are wrong or incomplete \(for example, missing `null | undefined` if the library was not written with `strictNullChecks` in mind\) +- When a library's input types are too narrow and the library hasn't added appropriate metadata for Angular to figure this out. + This usually occurs with disabled or other common Boolean inputs used as attributes, for example, ``. -* When using `$event.target` for DOM events \(because of the possibility of event bubbling, `$event.target` in the DOM typings doesn't have the type you might expect\) +- When using `$event.target` for DOM events \(because of the possibility of event bubbling, `$event.target` in the DOM typings doesn't have the type you might expect\) In case of a false positive like these, there are a few options: -* Use the `$any()` type-cast function in certain contexts to opt out of type-checking for a part of the expression -* Disable strict checks entirely by setting `strictTemplates: false` in the application's TypeScript configuration file, `tsconfig.json` -* Disable certain type-checking operations individually, while maintaining strictness in other aspects, by setting a *strictness flag* to `false` -* If you want to use `strictTemplates` and `strictNullChecks` together, opt out of strict null type checking specifically for input bindings using `strictNullInputTypes` +- Use the `$any()` type-cast function in certain contexts to opt out of type-checking for a part of the expression +- Disable strict checks entirely by setting `strictTemplates: false` in the application's TypeScript configuration file, `tsconfig.json` +- Disable certain type-checking operations individually, while maintaining strictness in other aspects, by setting a _strictness flag_ to `false` +- If you want to use `strictTemplates` and `strictNullChecks` together, opt out of strict null type checking specifically for input bindings using `strictNullInputTypes` Unless otherwise commented, each following option is set to the value for `strictTemplates` \(`true` when `strictTemplates` is `true` and conversely, the other way around\). -| Strictness flag | Effect | -|:--- |:--- | -| `strictInputTypes` | Whether the assignability of a binding expression to the `@Input()` field is checked. Also affects the inference of directive generic types. | -| `strictInputAccessModifiers` | Whether access modifiers such as `private`/`protected`/`readonly` are honored when assigning a binding expression to an `@Input()`. If disabled, the access modifiers of the `@Input` are ignored; only the type is checked. This option is `false` by default, even with `strictTemplates` set to `true`. | -| `strictNullInputTypes` | Whether `strictNullChecks` is honored when checking `@Input()` bindings \(per `strictInputTypes`\). Turning this off can be useful when using a library that was not built with `strictNullChecks` in mind. | -| `strictAttributeTypes` | Whether to check `@Input()` bindings that are made using text attributes. For example, `` \(setting the `disabled` property to the string `'true'`\) vs `` \(setting the `disabled` property to the boolean `true`\). | -| `strictSafeNavigationTypes` | Whether the return type of safe navigation operations \(for example, `user?.name` will be correctly inferred based on the type of `user`\). If disabled, `user?.name` will be of type `any`. | -| `strictDomLocalRefTypes` | Whether local references to DOM elements will have the correct type. If disabled `ref` will be of type `any` for ``. | -| `strictOutputEventTypes` | Whether `$event` will have the correct type for event bindings to component/directive an `@Output()`, or to animation events. If disabled, it will be `any`. | -| `strictDomEventTypes` | Whether `$event` will have the correct type for event bindings to DOM events. If disabled, it will be `any`. | -| `strictContextGenerics` | Whether the type parameters of generic components will be inferred correctly \(including any generic bounds\). If disabled, any type parameters will be `any`. | -| `strictLiteralTypes` | Whether object and array literals declared in the template will have their type inferred. If disabled, the type of such literals will be `any`. This flag is `true` when *either* `fullTemplateTypeCheck` or `strictTemplates` is set to `true`. | +| Strictness flag | Effect | +| :--------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `strictInputTypes` | Whether the assignability of a binding expression to the `@Input()` field is checked. Also affects the inference of directive generic types. | +| `strictInputAccessModifiers` | Whether access modifiers such as `private`/`protected`/`readonly` are honored when assigning a binding expression to an `@Input()`. If disabled, the access modifiers of the `@Input` are ignored; only the type is checked. This option is `false` by default, even with `strictTemplates` set to `true`. | +| `strictNullInputTypes` | Whether `strictNullChecks` is honored when checking `@Input()` bindings \(per `strictInputTypes`\). Turning this off can be useful when using a library that was not built with `strictNullChecks` in mind. | +| `strictAttributeTypes` | Whether to check `@Input()` bindings that are made using text attributes. For example, `` \(setting the `disabled` property to the string `'true'`\) vs `` \(setting the `disabled` property to the boolean `true`\). | +| `strictSafeNavigationTypes` | Whether the return type of safe navigation operations \(for example, `user?.name` will be correctly inferred based on the type of `user`\). If disabled, `user?.name` will be of type `any`. | +| `strictDomLocalRefTypes` | Whether local references to DOM elements will have the correct type. If disabled `ref` will be of type `any` for ``. | +| `strictOutputEventTypes` | Whether `$event` will have the correct type for event bindings to component/directive an `@Output()`, or to animation events. If disabled, it will be `any`. | +| `strictDomEventTypes` | Whether `$event` will have the correct type for event bindings to DOM events. If disabled, it will be `any`. | +| `strictContextGenerics` | Whether the type parameters of generic components will be inferred correctly \(including any generic bounds\). If disabled, any type parameters will be `any`. | +| `strictLiteralTypes` | Whether object and array literals declared in the template will have their type inferred. If disabled, the type of such literals will be `any`. This flag is `true` when _either_ `fullTemplateTypeCheck` or `strictTemplates` is set to `true`. | If you still have issues after troubleshooting with these flags, fall back to full mode by disabling `strictTemplates`. @@ -137,7 +138,7 @@ If this happens, [file an issue](https://github.com/angular/angular/issues) so t The template type checker checks whether a binding expression's type is compatible with that of the corresponding directive input. As an example, consider the following component: - +```angular-ts export interface User { name: string; @@ -151,11 +152,11 @@ export class UserDetailComponent { user = input.required(); } - +``` The `AppComponent` template uses this component as follows: - +```angular-ts @Component({ selector: 'app-root', @@ -165,7 +166,7 @@ export class AppComponent { selectedUser: User | null = null; } - +``` Here, during type checking of the template for `AppComponent`, the `[user]="selectedUser"` binding corresponds with the `UserDetailComponent.user` input. Therefore, Angular assigns the `selectedUser` property to `UserDetailComponent.user`, which would result in an error if their types were incompatible. @@ -180,42 +181,42 @@ See [Improving template type checking for custom directives](guide/directives/st When you enable `strictTemplates` and the TypeScript flag `strictNullChecks`, typecheck errors might occur for certain situations that might not easily be avoided. For example: -* A nullable value that is bound to a directive from a library which did not have `strictNullChecks` enabled. +- A nullable value that is bound to a directive from a library which did not have `strictNullChecks` enabled. - For a library compiled without `strictNullChecks`, its declaration files will not indicate whether a field can be `null` or not. - For situations where the library handles `null` correctly, this is problematic, as the compiler will check a nullable value against the declaration files which omit the `null` type. - As such, the compiler produces a type-check error because it adheres to `strictNullChecks`. + For a library compiled without `strictNullChecks`, its declaration files will not indicate whether a field can be `null` or not. + For situations where the library handles `null` correctly, this is problematic, as the compiler will check a nullable value against the declaration files which omit the `null` type. + As such, the compiler produces a type-check error because it adheres to `strictNullChecks`. -* Using the `async` pipe with an Observable which you know will emit synchronously. +- Using the `async` pipe with an Observable which you know will emit synchronously. - The `async` pipe currently assumes that the Observable it subscribes to can be asynchronous, which means that it's possible that there is no value available yet. - In that case, it still has to return something —which is `null`. - In other words, the return type of the `async` pipe includes `null`, which might result in errors in situations where the Observable is known to emit a non-nullable value synchronously. + The `async` pipe currently assumes that the Observable it subscribes to can be asynchronous, which means that it's possible that there is no value available yet. + In that case, it still has to return something —which is `null`. + In other words, the return type of the `async` pipe includes `null`, which might result in errors in situations where the Observable is known to emit a non-nullable value synchronously. There are two potential workarounds to the preceding issues: -* In the template, include the non-null assertion operator `!` at the end of a nullable expression, such as +- In the template, include the non-null assertion operator `!` at the end of a nullable expression, such as - +```html - + - +``` - In this example, the compiler disregards type incompatibilities in nullability, just as in TypeScript code. - In the case of the `async` pipe, notice that the expression needs to be wrapped in parentheses, as in +In this example, the compiler disregards type incompatibilities in nullability, just as in TypeScript code. +In the case of the `async` pipe, notice that the expression needs to be wrapped in parentheses, as in - +```html - + - +``` -* Disable strict null checks in Angular templates completely. +- Disable strict null checks in Angular templates completely. - When `strictTemplates` is enabled, it is still possible to disable certain aspects of type checking. - Setting the option `strictNullInputTypes` to `false` disables strict null checks within Angular templates. - This flag applies for all components that are part of the application. + When `strictTemplates` is enabled, it is still possible to disable certain aspects of type checking. + Setting the option `strictNullInputTypes` to `false` disables strict null checks within Angular templates. + This flag applies for all components that are part of the application. ### Advice for library authors @@ -231,7 +232,7 @@ As an example, consider this custom button component: Consider the following directive: - +```angular-ts @Component({ selector: 'submit-button', @@ -245,36 +246,36 @@ class SubmitButton { disabled = input.required({transform: booleanAttribute }); } - +``` Here, the `disabled` input of the component is being passed on to the `