build: classify the firebase symbols a version raise would newly wrap - #3759
Conversation
…ything ngPostUpdate took a Tree and returned it unchanged. It was registered in migration.json, listed in the schematics tsconfig, loaded as a build entry point and bundled on every build, and running it was always a no-op. Its description claimed it printed results after ng-update, and it printed nothing. Leaving it in place costs more than the eight lines suggest. Anyone auditing what ng update does has to open the file to find out that the answer is nothing, and a dead entry point is one more thing the build has to keep loading. The entry was spelled ng-post-upgate, missing the d, so a search for the correct spelling did not find it. tools/build.ts refers to it as ['update', 'index'], assembled from parts, so a search for the path did not find that either. Removing it changes no behavior. Nothing referenced ngPostUpdate except the four places removed here, and the file exported nothing else.
… the generator The build regenerates src/<module>/firebase.ts from the declarations of whatever firebase is installed, wrapping every lowercase-initial function. Raising the minimum version would wrap symbols nobody has classified, and one breaks: the auth persistence exports are classes that firebase constructs with `new`, and the wrapper replaces them with an ordinary function. These entries settle that first, and stay inert until the version rises. Do not wrap maximum, minimum, getTemplateGenerativeModel or makeMemoryCacheProvider: each is synchronous and returns a plain value, so wrapping only adds a warning to a call that cannot destabilize anything. Wrap the messaging subscriptions with blockUntilFirst off. With it on, subscribing holds a pending task until the callback fires, and these fire on a registration change that may never happen. The generator is now exported so `npm run generate` runs it without `ng build`, and it fails on an override key its entry point does not declare, which is otherwise ignored in silence.
The guide said to call Firebase APIs inside an injection context and showed how, but never said what AngularFire does with one, so the warning read as a lint rule rather than a description of something lost. The new section says what AngularFire asks Angular for, what happens without it, and names the consequence: the call is never added to the PendingTasks register, which is what server-side rendering waits on before it serializes the page.
tyler-reitz
left a comment
There was a problem hiding this comment.
Approving. Ran the checks rather than reading them: npm run generate is clean at firebase 12.4.0, and the new guard genuinely fails. Re-adding the misfiled isSupported key exits 1 with your message, a typo'd indexedDBLocalPersistance does too, and flipping debugErrorMap to a real override produces the expected src/auth/firebase.ts diff. The docs/zones.md section matches zones.ts:134-138 exactly, and all five persistence exports are typeof function at runtime, with browserCookiePersistence marked "Excluded from this release type" in auth-public.d.ts:740. The four you left unwrapped read right to me.
One question, not blocking. The misfiled isSupported is deleted rather than moved to the firebase/remote-config block, so remote-config keeps ɵzoneWrap(_isSupported, true) (src/remote-config/firebase.ts:31) while messaging has false. Reading zones.ts, that costs a PendingTask around the promise and flips the default log level from VERBOSE to WARN (zones.ts:125), so out-of-context calls warn per call. I did not run that difference. Deliberate, or should the entry move?
Worth noting the guard is stronger than the PR says: buildLibrary awaits it (tools/build.ts:449) and CI runs npm run build, so it already fires on every PR.
|
Deliberate, and I agree it should move. Moving it changes One correction on the cost, since it changes what that follow-up needs to measure. The two effects cannot both reach the same call. So a call made outside an injection context warns and returns immediately, and registers no pending task whether I read that rather than ran it, same as you, so the follow-up should measure it before changing the value. The intent looks clear enough though: both Thanks for the note on the check, and that is a better description than the one in my PR body. |
The generated src/<module>/firebase.ts files are written from the type declarations of whatever firebase is installed, so the set of functions AngularFire wraps is decided by the version the build resolves. That was 12.4.0 while npm latest reached 12.18.0, leaving newly added functions reaching callers through the star export with no zone integration and no pending-task registration. Raising the required version wraps them. Everything the override entries in angular#3759 classified as unwrapped stays out. getImagenModel loses its entry because firebase removed the symbol in 12.18.0, so the generator no longer sees it. The exemption list it sat in is empty now and stays as the place the next unclassified name goes. Fixes angular#3756
The generated src/<module>/firebase.ts files are written from the type declarations of the installed firebase, which decides which functions AngularFire wraps. That was 12.4.0 while npm latest reached 12.18.0, leaving everything firebase added in between to reach callers through `export *`, with no zone integration and no pending-task registration. Raising the required version wraps them. Everything the override entries in #3759 classified as unwrapped stays out. `getImagenModel` loses its entry because firebase removed the symbol in 12.18.0, and the exemption list it sat in is empty now and stays as the place the next unclassified name goes. Only `src/messaging/firebase.ts` changes among the generated files, gaining onRegistered, onUnregistered, register and unregister. `docs/messaging.md` was updated to use those calls. The Node send example keeps its token field, which Firebase says still accepts an installation ID during the migration, rather than the fid field it recommends, because firebase-admin 13.5.0 does not declare one. `exportsSeenPerOverrides` is keyed by the overrides object, and firestore and firestore/lite are handed the same firestoreOverrides, so a name listed for one silences the check for the other. Fixes #3756
Checklist
firebaseversion AngularFire is built against, so functions added since 12.4.0 are wrapped #3756 (required)docs/zones.md)yarn install,yarn testrun successfully? yes, via the npm equivalentsDescription
@angular/firedoes not hand-write its wrapper files.tools/build.tsregeneratessrc/<module>/firebase.tsfrom the type declarations of whateverfirebaseis installed, wrapping every exported function whose name starts with a lowercase letter. Raising the installed version therefore wraps every function Firebase has added in between, all at once, whether or not wrapping does anything useful for a given one. #3756 has the background.One of them does not merely gain nothing, it breaks. The auth persistence exports are classes, and Firebase constructs whichever one it is given with
new. Wrapping replaces the class with an ordinary function, and calling it withoutnewthrows. #3550 is a user hitting exactly that onbrowserLocalPersistence, which is why that one and its three neighbors already carry an entry.browserCookiePersistenceis the fifth, and it becomes visible when the version rises.This PR settles the classification while the installed version is still 12.4.0, so the version raise stays a small change rather than a behavior change bundled with it. Nothing here alters generated output, because the generator builds its export list from the installed declarations, so an entry naming a symbol that version does not have is never consulted.
What each entry decides:
maximum,minimum,getTemplateGenerativeModelandmakeMemoryCacheProviderstay unwrapped. Each is synchronous, takes no callback and returns a plain value, so wrapping only adds an out-of-injection-context warning to a call that cannot destabilize anything.browserCookiePersistencestays unwrapped, for thenewreason above.onRegisteredandonUnregisteredare wrapped withblockUntilFirstoff, matchingonMessage. With it on, subscribing registers a pending task that clears only when the callback fires or the caller unsubscribes, and these fire on a Cloud Messaging registration change that may never happen.unregisteris quieted to matchdeleteToken.registerkeeps the default, matching its counterpartgetToken.Two supporting changes:
tools/build.tsno longer runs itself on import, and exports the generator, sonpm run generatecan regenerate the files withoutng build. That is what makes a regenerate-and-compare check runnable in CI.Two smaller items ride along:
ngPostUpdate, anng updatemigration that took a Tree and returned it unchanged, is removed. It was registered in four places, one of which spelled itng-post-upgate.docs/zones.mdgains a section on what AngularFire asks Angular for when you call a wrapped API, and what is lost when that call happens outside an injection context. Firebase API called outside injection context - missing details on how to fix this #3629 asked for that detail.Testing
No unit tests, because nothing here changes runtime behavior: the generated files are byte-identical before and after. The check that matters is that regenerating produces no diff, which is what shows the entries are inert against firebase 12.4.0.
That is empty on this branch. Two further results:
src/messaging/firebase.ts, and every entry lands as described above.If any of this reads wrong to you, particularly the four I am leaving unwrapped, say so and I will revisit before the version raise goes up.
Refs #3756