Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export class AppComponent {

[Upgrading from v6.0? Check out our guide.](docs/version-7-upgrade.md)

[Upgrading from AngularFire 20? See the v21 upgrade guide.](docs/version-21-upgrade.md)

### Sample app

The [`sample`](sample) folder contains a kitchen sink application that demonstrates use of the "modular" API, in a zoneless server-rendered application, with all the bells and whistles.
Expand Down
2 changes: 2 additions & 0 deletions docs/ai.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Firebase AI Logic gives you access to the latest generative AI models from Googl

[Learn more](https://firebase.google.com/docs/ai-logic)

> Firebase AI Logic was previously called **Vertex AI in Firebase**. If you are upgrading from AngularFire 20, the module moved from `@angular/fire/vertexai` to `@angular/fire/ai` and most symbols were renamed (`provideVertexAI` to `provideAI`, `VertexAI` to `AI`). One is not a rename: plain `getAI()` uses the Gemini Developer API backend, so the old `getVertexAI()` maps to `getAI(app, { backend: new VertexAIBackend() })`. Running `ng update @angular/fire` rewrites all of this for you and keeps your app on the Vertex AI backend. See the [AngularFire 20 to 21 upgrade guide](./version-21-upgrade.md).

## Dependency Injection

As a prerequisite, ensure that `AngularFire` has been added to your project via
Expand Down
42 changes: 42 additions & 0 deletions docs/version-21-upgrade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Upgrading to AngularFire 21

AngularFire 21 targets **Angular 21** and the **Firebase JS SDK v12**. Most of the upgrade is handled for you by `ng update`.

## Run the update

```bash
ng update @angular/core @angular/cli # move your app to Angular 21 first
ng update @angular/fire # then AngularFire 21
```

`ng update @angular/fire` runs a migration that:

- **Aligns your `firebase` dependency to `^12.4.0`.** AngularFire 21 requires Firebase JS SDK 12. If your app still requested `firebase` 11, npm would install both 11 and 12 side by side, and the two copies reject each other's objects at runtime. The migration updates the dependency and reinstalls so you end up with a single copy. Verify with `npm ls firebase`.
- **Rewrites Vertex AI imports to AI Logic** (see below).

## Vertex AI is now Firebase AI Logic

The Vertex AI module has been renamed to Firebase AI Logic. The `@angular/fire/vertexai` entry point (and the older `@angular/fire/vertexai-preview`) are removed in favor of `@angular/fire/ai`:

| Before (`@angular/fire/vertexai`) | After (`@angular/fire/ai`) |
|---|---|
| `getVertexAI(app?, { location? })` | `getAI(app, { backend: new VertexAIBackend(location?) })` |
| `provideVertexAI` | `provideAI` |
| `VertexAI` | `AI` |
| `VertexAIError` | `AIError` |
| `VertexAIErrorCode` | `AIErrorCode` |
| `VertexAIModel` | `AIModel` |
| `VertexAIInstances` | `AIInstances` |
| `vertexAIInstance$` | `AIInstance$` |
| `VertexAIModule` | `AIModule` |

**`getVertexAI` is not a plain rename.** `getAI` already existed alongside it, and a plain `getAI()` call talks to the Gemini Developer API backend, not to Vertex AI. The equivalent of `getVertexAI()` is `getAI(app, { backend: new VertexAIBackend() })`, which is what the migration writes, so your app keeps calling the Vertex AI backend it was configured, enabled, and billed for. A `location` option moves into the `VertexAIBackend` constructor.

`ng update @angular/fire` rewrites these imports and identifiers for you and logs every `getVertexAI` call it rewrites. Code it cannot rewrite safely (for example when the options are not a literal `{ location }` object or that literal references other rewritten symbols, when the function itself is handed around as a value, when a local declaration in the file reuses an imported symbol's name, or when the file already binds `getAI` or `VertexAIBackend` from a source other than AI Logic) is left in place with a warning. The import path itself still moves to the new entry point, so the leftover code fails to compile there, and nothing changes backends silently. A file where a named `getVertexAI` import has any use that cannot be rewritten keeps every use of its named `getVertexAI` imports in place (namespace-style `ns.getVertexAI(...)` calls are judged per call), and each skipped call is logged. `export * from '@angular/fire/vertexai'` is also left alone (rewriting it would silently rename your re-exported public symbols), so replace it with named re-exports by hand. `VertexAIOptions` was removed rather than renamed (the new `AIOptions` takes a `backend` instead of a `location`), so imports of it are left and warned about. Migrate those sites using the table above. `getGenerativeModel` and `getImagenModel` keep their names.

Imports straight from the Firebase SDK (`firebase/vertexai`, gone in SDK 12) are rewritten to `firebase/ai` under the same rules. The rewrite parses your sources with the `typescript` package (an optional peer dependency of `@angular/fire`). Every Angular workspace already has it, but if the migration warns that it could not be resolved, install `typescript` and re-run. See [ai.md](./ai.md) for current usage.

## Other notes

- **Angular 21 is required.** AngularFire 21 peers `@angular/* ^21.0.0` and does not support Angular 22 (a future AngularFire 22 will).
- The obsolete `@angular/platform-browser-dynamic` peer dependency was removed. No action is needed.
6 changes: 4 additions & 2 deletions src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@
"@angular/platform-browser": "^21.0.0",
"@angular/platform-server": "^21.0.0",
"rxjs": "~7.8.0",
"firebase-tools": "^14.0.0 || ^15.0.0"
"firebase-tools": "^14.0.0 || ^15.0.0",
"typescript": ">=5.8 <6.0"
},
"peerDependenciesMeta": {
"firebase-tools": { "optional": true },
"@angular/platform-server": { "optional": true }
"@angular/platform-server": { "optional": true },
"typescript": { "optional": true }
},
"dependencies": {
"firebase": "^12.4.0",
Expand Down
2 changes: 1 addition & 1 deletion src/schematics/migration.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"migration-v21": {
"version": "21.0.0",
"description": "Align the workspace's firebase dependency with the range @angular/fire 21 requires, so the install cannot contain two copies of the firebase SDK",
"description": "Align the workspace's firebase dependency with the range @angular/fire 21 requires, and rewrite Vertex AI imports to Firebase AI Logic (getVertexAI callers keep the Vertex AI backend)",
"factory": "./update/v21#ngUpdate"
},
"ng-post-upgate": {
Expand Down
42 changes: 42 additions & 0 deletions src/schematics/update/v21/index.jasmine.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { logging } from '@angular-devkit/core';
import { HostTree, SchematicContext } from '@angular-devkit/schematics';
import * as typescript from 'typescript';
import { firebaseVersionRange } from '../../common.js';
import { ngUpdate } from './index.js';
import 'jasmine';
Expand Down Expand Up @@ -40,4 +41,45 @@ describe('migration-v21 ngUpdate', () => {
expect(addTask).not.toHaveBeenCalled();
});

it('keeps the firebase alignment when the rewrite throws', () => {
const logger = new logging.Logger('test');
const warn = spyOn(logger, 'warn');
const addTask = jasmine.createSpy('addTask');
const context = { logger, addTask } as unknown as SchematicContext;
const tree = treeWithFirebase('^11.0.0');
tree.create('angular.json', JSON.stringify({
projects: { app: { root: '', sourceRoot: 'src' } },
}));
tree.create('src/app/foo.ts', `import { getVertexAI } from '@angular/fire/vertexai';`);
const throwingCompiler = {
ScriptTarget: typescript.ScriptTarget,
createSourceFile: () => { throw new Error('boom'); },
} as unknown as typeof typescript;

ngUpdate({ compiler: throwingCompiler })(tree, context);

// The rewrite failure costs only the rewrite, never the firebase alignment.
const written = JSON.parse(tree.readText('package.json'));
expect(written.dependencies.firebase).toBe(firebaseVersionRange);
expect(addTask).toHaveBeenCalledTimes(1);
expect(warn.calls.allArgs().map(callArgs => String(callArgs[0])).join('\n'))
.toContain('Skipped the Vertex AI -> AI Logic source rewrite');
});

it('runs the Vertex AI rewrite and the alignment through one ngUpdate call', () => {
const { context, addTask } = contextWithTaskSpy();
const tree = treeWithFirebase('^11.0.0');
tree.create('angular.json', JSON.stringify({
projects: { app: { root: '', sourceRoot: 'src' } },
}));
tree.create('src/app/foo.ts', `import { getVertexAI } from '@angular/fire/vertexai';`);

ngUpdate({ compiler: typescript })(tree, context);

expect(tree.readText('src/app/foo.ts')).toBe(`import { getAI } from '@angular/fire/ai';`);
const written = JSON.parse(tree.readText('package.json'));
expect(written.dependencies.firebase).toBe(firebaseVersionRange);
expect(addTask).toHaveBeenCalledTimes(1);
});

});
18 changes: 16 additions & 2 deletions src/schematics/update/v21/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
// The explicit index.js subpath keeps this importable from the ESM jasmine run; the bare
// The explicit index.js subpath keeps this importable from the ESM jasmine run. The bare
// /tasks directory specifier only resolves under CommonJS.
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks/index.js';
import type * as ts from 'typescript';
import { alignFirebaseVersion } from '../../common.js';
import { rewriteVertexAIToAI } from './vertexai-to-ai/index.js';

// ng update re-runs this migration on rc-to-stable transitions (the CLI clamps the migration
// range's upper bound to the release version), so it must stay a no-op when nothing changes.
export const ngUpdate = (): Rule => (
export const ngUpdate = (options?: { compiler?: typeof ts }): Rule => (
host: Tree,
context: SchematicContext
) => {
// Align firebase before anything else: it is the one step users cannot do without, so no
// failure below may cost it. This step changes dependencies, so only it schedules an install.
if (alignFirebaseVersion(host, context)) {
context.addTask(new NodePackageInstallTask());
}
// Rewrite Vertex AI imports to AI Logic (source-only edits, no dependency change). Guarded so
// an unexpected rewrite failure costs only the rewrite, never the alignment above.
try {
rewriteVertexAIToAI(host, context, options?.compiler);
} catch (error) {
context.logger.warn(
`Skipped the Vertex AI -> AI Logic source rewrite: ${error}. ` +
'Any remaining @angular/fire/vertexai imports need a manual migration - see the v21 upgrade guide (docs/version-21-upgrade.md).'
);
}
return host;
};
Loading
Loading