feat(bundler): honor angular.json externalDependencies (#146) - #174
Merged
lukekania merged 1 commit intoMay 18, 2026
Merged
Conversation
Adds support for `externalDependencies` in `angular.json` so projects loading specific npm packages from a CDN (or expecting them as `import` map entries) can exclude those packages from the bundle — matching `@angular/build:application`. - project-resolver: parse `externalDependencies` (base + per-config override) into `ResolvedAngularProject.external_dependencies`. - npm-resolver: new `resolve_npm_dependencies_with_externals` skips externalised specifiers in phase 1 and the transitive BFS, so a package and all its modules stay out of `npm_resolution`. - bundler: `BundleInput.external_specifiers` vetoes `is_local` — an import whose specifier matches an external entry (exact or `<name>/...` subpath) is emitted verbatim and never rewritten to a `__ns_*` namespace reference. Lazy-chunk routing keeps externals as bare specifiers instead of folding them through `./main.js`. - cli: thread externals through every npm-resolver call site; strip externals from `bundled_specifiers` defensively before bundling. - builder: drop the stale "currently ignored" warning. Verified against `test-ng-project`: declaring `externalDependencies: ["jquery"]` and importing `$ from 'jquery'` (and the subpath `jquery/dist/jquery.slim`) emits the imports verbatim in `main.js`, jquery is not installed in the fixture so unresolved externals are silently skipped by the resolver as intended. Bumps workspace to 0.10.10.
lukekania
force-pushed
the
feat/bundler-external-deps
branch
from
May 18, 2026 09:44
94b0efc to
68a6c85
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #146
Summary
angular.json'sexternalDependenciesarray. An import likeimport $ from 'jquery'survives as a bare ESM specifier whenjqueryis declared external — the runtime (browser import map, CDN loader, micro-frontend host) resolves it. The package is neither inlined nor BFS-walked by the resolver, matching@angular/build:application(esbuild--external: jquery).jqueryalso externalisesjquery/dist/jquery.slimetc., consistent with esbuild's package-name external semantics.budgets).Where the change lives
crates/project-resolver/src/angular_json.rs: parseexternalDependencies(base + per-configuration override) intoResolvedAngularProject.external_dependencies.crates/npm-resolver/src/lib.rs: newresolve_npm_dependencies_with_externalsskips externalised specifiers in both phase-1 entry resolution and the phase-2 transitive BFS. The originalresolve_npm_dependenciesis now a thin wrapper that passes an empty set.crates/bundler/src/concat.rs+rewrite.rs: newBundleInput.external_specifiersfield.is_localis updated to veto externals first (so even if a specifier leaks intobundled_specifiers, externals stay bare). Lazy-chunk routing keeps externals as direct bare imports instead of folding them through./main.js.crates/cli/src/main.rs: thread externals through everyresolve_npm_dependenciescall site; defensively strip externals frombundled_specifiersbefore bundling.packages/builder/src/build/options.ts: drop the stale "externalDependenciesis currently ignored" warning.Tests
bundled_specifierscontains the same name (regression guard), and that subpaths of external packages are also kept as bare specifiers.End-to-end verification
Against
test-ng-project:"externalDependencies": ["jquery"]inangular.json.import $ from 'jquery';andimport { something } from 'jquery/dist/jquery.slim';insrc/main.ts.NGC_RS_BINARY=…/target/release/ngc-rs npx ng build.dist/test-ng-project/main.jscontains both imports verbatim; jquery is not installed in the fixture and the resolver silently skips it (the BFS never asks for it) — proving the second acceptance bullet.Notes vs. issue body
<script type="importmap">emission as a separate follow-up. Left out of scope — implementation here only covers "leave the bare specifier".Test plan
cargo build --release -p ngc-rscargo test -p ngc-bundler -p ngc-npm-resolver -p ngc-project-resolvercargo clippy --workspace -- -D warningsexternalDependenciesto a fixture, build, grepdist/main.jsfor the bare import.