Community builders for Angular CLI's build facade -- extend Angular's build, test, and serve tooling without ejecting.
yarn # Install dependencies (Yarn 3 with workspaces)
yarn build:packages:all # Build all packages (TypeScript + schema merge)
yarn test:local # Run integration tests locally (parallel)AGENTS.md files at semantic boundaries provide AI agents with context. Start here, then drill into child nodes.
| Area | Node | Type |
|---|---|---|
| Packages (all builders) | packages/AGENTS.md |
Architectural Layer |
| Common utilities | packages/common/AGENTS.md |
Shared Kernel |
| Custom ESBuild builders | packages/custom-esbuild/AGENTS.md |
Self-contained Package |
| Custom Webpack builders | packages/custom-webpack/AGENTS.md |
Self-contained Package |
| Jest builder | packages/jest/AGENTS.md |
Self-contained Package |
| Bazel builder | packages/bazel/AGENTS.md |
Self-contained Package |
| Timestamp builder | packages/timestamp/AGENTS.md |
Self-contained Package |
| Example apps / test fixtures | examples/AGENTS.md |
Test Fixtures Boundary |
| Build & test scripts | scripts/AGENTS.md |
Capability Domain |
| CI & workflows | .github/AGENTS.md |
Capability Domain |
Keep Intent Nodes in sync with code changes. See MAINTENANCE.md for sync instructions and update procedures.
This is a Yarn 3 monorepo managed by Turbo (builds) and Lerna-Lite (publishing). It publishes six @angular-builders/* npm packages that extend Angular CLI's Architect build system. Builders' major versions track Angular's major version (currently 21).
The two primary packages -- custom-esbuild and custom-webpack -- wrap Angular's two build systems respectively: @angular/build (esbuild/Vite) and @angular-devkit/build-angular (Webpack). They allow users to inject custom build configuration without ejecting from the CLI. The jest package replaces Karma with Jest for ng test. bazel and timestamp are thinner wrappers.
custom-esbuild ──> common ──> ts-node, tsconfig-paths
custom-webpack ──> common, @angular/build (IndexHtmlTransform type)
jest ──────────> common
bazel (standalone -- no common dependency)
timestamp (standalone -- no common dependency)
custom-esbuild and custom-webpack extend Angular's base builder schemas with custom properties. During build:
- TypeScript compiles to
dist/ merge-schemes.ts(repo root) runs, reading the package'ssrc/schemes.ts- Each scheme definition specifies: the original Angular schema, extension files (
schema.ext.json), and output path - The merge uses lodash
mergeWithwith two special markers:__REPLACE__array prefix: replaces the base value entirely instead of merging__DELETE__string value: removes the property from the output schema
- Merged schemas are written to
dist/*/schema.json
merge-schemes.ts uses resolvePackagePath from common to bypass package exports maps when resolving @angular/build's internal schema files.
Important exception: The Jest builder's schema is NOT merged from an Angular base schema -- it is its own hand-authored schema.json (based on Jest's CLI options). Only custom-esbuild and custom-webpack use the schema merging mechanism. (Source: SME interview, Jeb, 2026-02-16)
This project extends Angular CLI rather than replacing it. The Angular CLI team provides the builder interface but does not support custom configurations -- any issues arising from customized builds are this project's responsibility, not Angular's. This is why most user-filed issues land here. (Source: SME interview, Jeb, 2026-02-16)
The biggest maintenance burdens are: (1) keeping up with Angular CLI internal API changes that break builders -- a major effort every ~6 months, and (2) user support -- triaging issues, answering questions, managing community expectations. The most common user issues are version compatibility problems after Angular upgrades and peer dependency mismatches. (Source: SME interview, Jeb, 2026-02-16)
Long-term vision: Follows Angular. Whatever Angular CLI supports, builders will support. When Angular drops webpack support, custom-webpack will follow suit. (Source: SME interview, Jeb, 2026-02-16)
| Concern | Pattern | Reference |
|---|---|---|
| Module loading (CJS/ESM/TS) | All user-provided modules loaded via @angular-builders/common's loadModule() |
packages/common/AGENTS.md |
| Angular version tracking | All packages track the same Angular major. Update via yarn update:packages <version> |
scripts/AGENTS.md |
| Publishing | Independent versioning via Lerna-Lite. Beta on merge to master, graduation via manual dispatch. See Release & Publishing below | .github/workflows/ci.yml |
| Testing (unit) | Jest 30. Config at repo root: jest-ut.config.js, jest-e2e.config.js |
Package-level yarn test |
| Testing (integration) | Defined in packages/*/tests/integration.js, executed against examples/* apps |
scripts/AGENTS.md, examples/AGENTS.md |
| Code formatting | Prettier via lint-staged + Husky pre-commit hook | Root package.json prettier config |
| Commits | Conventional Commits enforced via commitlint. Drives auto-generated CHANGELOGs | .commitlintrc.json |
| Dependency updates | Renovate bot with config in renovate.json |
renovate.json |
| Documentation | Package READMEs are the npm page content (install steps, config examples, option docs). Update when builder options or Angular prerequisites change. Example READMEs are auto-generated scaffold -- ignore them | packages/*/README.md |
Lerna-Lite manages versioning and publishing. Packages use independent versioning ("version": "independent" in lerna.json) -- majors are aligned to Angular, but patches and minors are released independently per package.
- Conventional commits (
feat:,fix:,feat!:,BREAKING CHANGE:footer) drive version bumps and CHANGELOG generation. Enforced by commitlint + Husky pre-commit hook. - Beta publish (automatic): Every merge to master triggers
scripts/default-registry.sh, which runslerna publish --dist-tag=next --preid=beta --conventional-prerelease --yes. Publishes to npm under thenexttag. - Graduation (manual): Dispatch the CI workflow with
release_type: graduate. Runslerna publish --conventional-commits --conventional-graduate. Promotes the latest beta to a stable release under thelatesttag. - CHANGELOGs: Fully auto-generated by Lerna-Lite during both beta and graduate publishes, driven by conventional commit messages. Preset:
conventional-changelog-conventionalcommits(configured inlerna.json). - npm trusted publishing: Uses OIDC (
id-token: writepermission). CI installsnpm@latestbecause Node 20's bundled npm 10 lacks full OIDC support. - Commit guard: Lerna's publish commit message is
ci(release): publish. The CI workflow skips entirely when it seesci(release)in the head commit to avoid infinite publish loops.
| Workflow | Trigger | Purpose |
|---|---|---|
ci.yml |
push to master, PRs, manual | Build → integration matrix → ci-pass gate → publish |
auto-approve.yml |
PRs from trusted bots/maintainer | Auto-approve PRs from just-jeb, renovate[bot], allcontributors[bot] |
update.yml |
manual dispatch | Update Angular version across packages and examples |
ci.yml has four jobs: build (compile + test discovery), integration (~41 parallel test matrix), ci-pass (aggregation gate for branch protection), publish (beta or graduate via Lerna-Lite). See .github/AGENTS.md for CI tribal knowledge (cache warming, ci:full label, ci-pass gate).
- PR template (
.github/PULL_REQUEST_TEMPLATE.md): Requires test checkbox, docs checkbox, PR type, current/new behavior, breaking change flag. - Bug report (
.github/ISSUE_TEMPLATE/bug_report.md): Requires a reproduction repo. Policy: no repro = immediate close. - Feature request (
.github/ISSUE_TEMPLATE/feature_request.md): Standard template.
MUST: Builder major versions match Angular CLI major version. A v21 builder requires Angular CLI 21.
MUST: All packages publish under @angular-builders npm scope with public access.
MUST: custom-esbuild and custom-webpack run merge-schemes.ts during build. Missing this step means builder schemas in dist/ will be absent or stale, causing Angular CLI validation failures.
MUST NEVER: Cross-import between builder packages (e.g., custom-esbuild importing from custom-webpack). Shared code goes in common.
MUST NEVER: Edit auto-generated files: packages/jest/src/schema.ts, packages/bazel/src/schema.ts, packages/timestamp/src/schema.ts (generated by quicktype), dist/*/schema.json (generated by merge-schemes), and packages/*/CHANGELOG.md (generated by Lerna-Lite from conventional commits).
MUST NEVER: Ship a breaking dependency update (e.g., a new webpack-merge major) as a minor version of a builder package. Breaking changes must wait for the next major version aligned with Angular. (Source: SME interview, Jeb, 2026-02-16)
MUST NEVER: Use ci(release) in commit messages outside of the automated publish process -- it causes CI to skip the entire pipeline.
MUST: When creating a pull request, read .github/PULL_REQUEST_TEMPLATE.md and use its structure for the PR body. Fill in all sections: PR checklist, PR type, current behavior, new behavior, and breaking change flag.
The upgrade process is not fully automated. It partially originates from Renovate PRs, but each Angular major update also requires running ng update for apps in examples/. The goal is full automation but it currently requires manual steps. Work sometimes begins against Angular RCs to have PRs ready, so only a final version update is needed when the major release lands. The packages layer is where Angular CLI internal API changes are felt most -- internal API moves (renamed/moved packages or exports) and schema changes to builder options are the most common breakages. (Source: SME interview, Jeb, 2026-02-16)