Skip to content

fix(schematics): pin prerelease installs to the exact version#3709

Merged
armando-navarro merged 3 commits into
angular:mainfrom
armando-navarro:fix/pin-prerelease-versions
Jul 15, 2026
Merged

fix(schematics): pin prerelease installs to the exact version#3709
armando-navarro merged 3 commits into
angular:mainfrom
armando-navarro:fix/pin-prerelease-versions

Conversation

@armando-navarro

Copy link
Copy Markdown
Collaborator

ng add @angular/fire@next records the install with npm's default caret (^21.0.0-rc.0). A prerelease range like that also matches the -canary.<sha> builds published for every merge to main — they sort higher than the RC — so any later fresh install silently replaces the version the user chose with an unreviewed snapshot.

After install, the schematic now pins the workspace's @angular/fire entry to the exact installed version when the recorded spec is a caret or tilde range around a prerelease (and only when the installed version already satisfies that range). Stable ranges, exact versions, and hand-authored range expressions are left untouched. Includes unit specs for the pinning and all leave-alone cases.

Fixes #3708

ng add records the installed package with npm's default caret prefix.
For a stable release that only drifts to reviewed patch releases, but a
prerelease range like ^21.0.0-rc.0 also matches the canary build
published for every merge to main — so a later fresh install could
silently replace the version the user chose with an unreviewed
snapshot.

After install, if the workspace's @angular/fire entry is a caret or
tilde range around a prerelease, rewrite it to the exact installed
version (only when that version already satisfies the range). Stable
ranges and hand-authored range expressions are left untouched.
Comment thread src/schematics/common.ts Outdated
Comment thread src/schematics/common.ts Outdated
Comment thread src/schematics/common.ts Outdated
* directories up. Returns undefined when that layout doesn't hold (e.g. running from source),
* so callers skip pinning instead of failing the schematic.
*/
const readInstalledVersion = () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional/nit, design suggestion: tools/build.ts already stamps values into versions.json at build time, and add/index.ts already imports from it. Adding angularFireVersion there would let you replace the readFileSync/__dirname traversal with a plain JSON import, same pattern already in use and no filesystem-path assumptions.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one turned out more interesting than expected. Trying it revealed that versions.json values are actually dead at runtime: esbuild bundles the schematics and inlines the JSON import from the source stub at build time, so the post-build write to versions.json (the mechanism add/index.ts relies on) is never read by the shipped code. Extending it would have shipped a permanently disabled pin.

So I took your underlying idea — resolve the version at build time, drop the __dirname traversal — via a different mechanism: a placeholder string the build replaces with the real version in the compiled output, with the build failing hard if the placeholder isn't substituted (so a broken pin can't ship silently). Same outcome you were after, without depending on the broken versions.json path.

I've filed the versions.json-is-dead-at-runtime problem as #3715 for a proper fix — it also explains why addDependencies is currently a no-op.

- warn (instead of silently skipping) when the installed version can't be determined
- pin the @angular/fire entry whether it sits in dependencies or devDependencies
- resolve the installed version from a build-written placeholder rather than a
  runtime readFileSync/__dirname traversal; the build fails if the placeholder
  is not substituted, so a broken pin can't ship silently
@armando-navarro armando-navarro merged commit 62d3929 into angular:main Jul 15, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ng add @angular/fire@next records a caret range that silently drifts to canary builds

2 participants