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: 1 addition & 1 deletion docs/deploy/getting-started.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Deploy your application on Firebase Hosting & Functions

> **This page is out of date.** It describes a setup flow that `ng add @angular/fire` no longer performs, and wiring the deploy target by hand from the samples below puts you on a deprecated path that warns on every deploy. For current guidance see [the Quickstart](../install-and-setup.md), step 6, and for server-side rendered apps see the [App Hosting guide](../app-hosting.md).
> **This page is out of date.** It describes a setup flow that `ng add @angular/fire` no longer performs. Deploying server-side rendering to Cloud Functions with `ng deploy` (a deploy target with `ssr: true`, and the `functionsRuntimeOptions` and `CF3v2` options only it reads) is deprecated in AngularFire 22 and will be removed in AngularFire 23. Hosting-only deploys (`ssr` absent or `false`) are not deprecated. For current guidance see [the Quickstart](../install-and-setup.md), step 6, and for server-side rendered apps see the [App Hosting guide](../app-hosting.md).

In this guide, we'll look at how to use `@angular/fire` to automatically deploy an Angular application to Firebase hosting or functions by using the Angular CLI.

Expand Down
2 changes: 2 additions & 0 deletions docs/universal/cloud-functions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Deploying your Universal application on Cloud Functions for Firebase

> **This page is out of date.** It describes the Angular Universal and `firebase-tools` setup of 2019. Deploy server-rendered apps with Firebase App Hosting instead, see the [App Hosting guide](../app-hosting.md).

After [setting up your application with Angular Universal as outlined in Getting Started](getting-started.md), you're now ready to build your application for Firebase Hosting & Cloud Functions.

> Cloud Functions for Firebase lets you automatically run backend code in response to events triggered by Firebase features and HTTPS requests. Your code is stored in Google's cloud and runs in a managed environment. There's no need to manage and scale your own servers. [Learn more about Cloud Functions for Firebase](https://firebase.google.com/docs/functions/).
Expand Down
51 changes: 50 additions & 1 deletion src/schematics/deploy/actions.jasmine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Script } from 'vm';
import { BuilderContext, BuilderRun, ScheduleOptions, Target } from '@angular-devkit/architect';
import { JsonObject, logging } from '@angular-devkit/core';
import { BuildTarget, DeployBuilderSchema, FSHost, FirebaseDeployConfig, FirebaseTools } from '../interfaces';
import deploy, { assertSafeDependencyName, assertSafeFunctionName, assertSafeNodeVersion, assertSafeOutputPath, assertSupportedPackageManager, buildCloudRunBuildsSubmitArgs, buildCloudRunDeployArgs, deployToCloudRun, deployToFunction, findPackageVersion, processHost } from './actions.js'
import deploy, { CLOUD_FUNCTIONS_DEPRECATION, assertSafeDependencyName, assertSafeFunctionName, assertSafeNodeVersion, assertSafeOutputPath, assertSupportedPackageManager, buildCloudRunBuildsSubmitArgs, buildCloudRunDeployArgs, deployToCloudRun, deployToFunction, findPackageVersion, processHost } from './actions.js'
import 'jasmine';

let context: BuilderContext;
Expand Down Expand Up @@ -333,6 +333,55 @@ describe('universal deployment', () => {
});*/
});

describe('Cloud Functions deprecation', () => {
beforeEach(() => initMocks());

/* deploy() also warns about a Node version mismatch, so every assertion is about the
* deprecation text, never about the number of warn calls. */
const deprecationWarnings = (warnSpy: jasmine.Spy) =>
warnSpy.calls.allArgs().filter(([message]) => message === CLOUD_FUNCTIONS_DEPRECATION);

/* Makes the SSR routes throw at their first statement (the output path check), after the
* warning has or has not printed and before anything touches the file system or gcloud. */
const withUnreadableOutputPaths = () => {
context.getTargetOptions = () => Promise.resolve({});
};

it('warns before the build when deploying server-side rendering to Cloud Functions', async () => {
withUnreadableOutputPaths();
const warnSpy = spyOn(context.logger, 'warn');
const scheduleSpy = spyOn(context, 'scheduleTarget').and.callThrough();
await expectAsync(
deploy(firebaseMock, context, STATIC_BUILD_TARGET, SERVER_BUILD_TARGET, undefined, FIREBASE_PROJECT, { preview: false, ssr: true }, FIREBASE_TOKEN)
).toBeRejectedWithError(/Cannot read the output path option/);
expect(deprecationWarnings(warnSpy).length).toBe(1);
expect(warnSpy).toHaveBeenCalledBefore(scheduleSpy);
});

it('does not warn on a hosting-only deploy', async () => {
const warnSpy = spyOn(context.logger, 'warn');
await deploy(firebaseMock, context, STATIC_BUILD_TARGET, undefined, undefined, FIREBASE_PROJECT, { preview: false }, FIREBASE_TOKEN);
expect(deprecationWarnings(warnSpy)).toEqual([]);
});

it('does not warn when version 2 routes an ssr target to hosting', async () => {
const warnSpy = spyOn(context.logger, 'warn');
const deploySpy = spyOn(firebaseMock, 'deploy').and.callThrough();
await deploy(firebaseMock, context, STATIC_BUILD_TARGET, SERVER_BUILD_TARGET, undefined, FIREBASE_PROJECT, { preview: false, version: 2, ssr: true }, FIREBASE_TOKEN);
expect(deploySpy).toHaveBeenCalledWith(jasmine.objectContaining({ only: 'hosting:' + PROJECT }));
expect(deprecationWarnings(warnSpy)).toEqual([]);
});

it('does not warn on a Cloud Run deploy', async () => {
withUnreadableOutputPaths();
const warnSpy = spyOn(context.logger, 'warn');
await expectAsync(
deploy(firebaseMock, context, STATIC_BUILD_TARGET, SERVER_BUILD_TARGET, undefined, FIREBASE_PROJECT, { preview: false, ssr: 'cloud-run' }, FIREBASE_TOKEN)
).toBeRejectedWithError(/Cannot read the output path option/);
expect(deprecationWarnings(warnSpy)).toEqual([]);
});
});

describe('Cloud Run gcloud argv construction', () => {
// Regression coverage for the argv-injection fix: these options used to be interpolated
// into a single command string and split on whitespace, so a value containing a space
Expand Down
55 changes: 29 additions & 26 deletions src/schematics/deploy/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,10 @@ const getPackageJson = (context: BuilderContext, workspaceRoot: string, options:
return defaultPackage(dependencies, devDependencies, options, main);
};

export const CLOUD_FUNCTIONS_DEPRECATION = `⚠️ Deploying server-side rendering to Cloud Functions with ng deploy is deprecated in AngularFire 22 and will be removed in AngularFire 23.
Deploy server-rendered apps with Firebase App Hosting instead: https://firebase.google.com/docs/app-hosting
AngularFire's guide: https://github.com/angular/angularfire/blob/main/docs/app-hosting.md`;

export const deployToFunction = async (
firebaseTools: FirebaseTools,
context: BuilderContext,
Expand Down Expand Up @@ -560,6 +564,8 @@ export default async function deploy(
firebaseToken?: string,
) {
const legacyNgDeploy = !options.version || options.version < 2;
const deploysToCloudRun = legacyNgDeploy && !!serverBuildTarget && options.ssr === 'cloud-run';
const deploysToCloudFunctions = legacyNgDeploy && !!serverBuildTarget && !deploysToCloudRun;

if (!firebaseToken && !process.env.GOOGLE_APPLICATION_CREDENTIALS) {
if (!await isSignedIn(firebaseTools)) {
Expand All @@ -579,10 +585,9 @@ export default async function deploy(
console.log(`Using Google Application Credentials.`);
}

if (legacyNgDeploy) {
console.error(`Legacy ng-deploy Firebase is deprecated.
Please migrate to Firebase Hosting's integration with Angular https://firebase.google.com/docs/hosting/frameworks/angular
or the new Firebase App Hosting product https://firebase.google.com/docs/app-hosting`);
// Before the build, so a failed or interrupted build still displays the warning.
if (deploysToCloudFunctions) {
context.logger.warn(CLOUD_FUNCTIONS_DEPRECATION);
}

if (prerenderBuildTarget) {
Expand Down Expand Up @@ -649,28 +654,26 @@ or the new Firebase App Hosting product https://firebase.google.com/docs/app-hos

firebaseTools.logger.logger.add(logger);

if (legacyNgDeploy && serverBuildTarget) {
if (options.ssr === 'cloud-run') {
await deployToCloudRun(
firebaseTools,
context,
context.workspaceRoot,
staticBuildTarget,
serverBuildTarget,
options,
firebaseToken,
);
} else {
await deployToFunction(
firebaseTools,
context,
context.workspaceRoot,
staticBuildTarget,
serverBuildTarget,
options,
firebaseToken,
);
}
if (deploysToCloudRun) {
await deployToCloudRun(
firebaseTools,
context,
context.workspaceRoot,
staticBuildTarget,
serverBuildTarget,
options,
firebaseToken,
);
} else if (deploysToCloudFunctions) {
await deployToFunction(
firebaseTools,
context,
context.workspaceRoot,
staticBuildTarget,
serverBuildTarget,
options,
firebaseToken,
);
} else {
await deployToHosting(
firebaseTools,
Expand Down
8 changes: 5 additions & 3 deletions src/schematics/deploy/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
},
"ssr": {
"oneOf": [{ "type": "boolean" }, { "type": "string" }],
"description": "Should we attempt to deploy the function to Cloud Functions (true or 'cloud-functions') / Cloud Run ('cloud-run') or just Hosting (false)"
"description": "Deploy server-side rendering to Cloud Run ('cloud-run'), or just Hosting (false). Deploying to Cloud Functions (true or 'cloud-functions') is deprecated in AngularFire 22 and will be removed in AngularFire 23. Use Firebase App Hosting for server-rendered apps."
},
"prerender": {
"type": "boolean",
Expand Down Expand Up @@ -61,7 +61,8 @@
},
"CF3v2": {
"type": "boolean",
"description": "Generation of the Functions product to run on"
"description": "Generation of the Functions product to run on. Read only by the Cloud Functions mode, which AngularFire 22 deprecates and AngularFire 23 removes.",
"x-deprecated": "read only by the Cloud Functions mode of ng deploy, which AngularFire 22 deprecates and AngularFire 23 removes. Delete it unless ssr is true or 'cloud-functions'. Use Firebase App Hosting for server-rendered apps."
},
"region": {
"type": "string",
Expand All @@ -74,7 +75,8 @@
},
"functionsRuntimeOptions": {
"type": "object",
"description": "Runtime options for Cloud Functions, if deploying to Cloud Functions"
"description": "Runtime options for Cloud Functions. Read only by the Cloud Functions mode, which AngularFire 22 deprecates and AngularFire 23 removes.",
"x-deprecated": "read only by the Cloud Functions mode of ng deploy, which AngularFire 22 deprecates and AngularFire 23 removes. Delete it unless ssr is true or 'cloud-functions'. Use Firebase App Hosting for server-rendered apps."
},
"preview": {
"type": "boolean",
Expand Down
2 changes: 2 additions & 0 deletions src/schematics/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,11 @@ export interface DeployBuilderSchema {
prerender?: boolean;
functionName?: string;
functionsNodeVersion?: number|string;
/** @deprecated Read only by the Cloud Functions mode, which will be removed in AngularFire 23. */
functionsRuntimeOptions?: HttpsOptions;
cloudRunOptions?: Partial<CloudRunOptions>;
outputPath?: string;
/** @deprecated Read only by the Cloud Functions mode, which will be removed in AngularFire 23. */
CF3v2?: boolean;
version?: number;
}
Expand Down
Loading