Skip to content

Commit bc957da

Browse files
authored
Merge branch 'main' into taeold-patch-1
2 parents 1e7514b + 12bb6f3 commit bc957da

File tree

6 files changed

+130
-110
lines changed

6 files changed

+130
-110
lines changed

README.md

Lines changed: 102 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,135 +1,139 @@
1-
# Firebase CLI & Web Frameworks
2-
3-
## Frameworks
4-
5-
| Framework | Support | |
6-
| ---------- | ------- | - |
7-
| [Next.js](https://firebase.google.com/docs/hosting/frameworks/nextjs) | **Early preview** | |
8-
| [Angular](https://firebase.google.com/docs/hosting/frameworks/angular) | **Early preview** | |
9-
| [Express](https://firebase.google.com/docs/hosting/frameworks/express) | **Early preview** | |
10-
| Flask | **Early preview** | Coming soon... |
11-
| Django | Experimental | Coming soon... |
12-
| [Flutter](https://firebase.google.com/docs/hosting/frameworks/flutter) | Experimental | |
13-
| Nuxt | Experimental | |
14-
| Astro | Experimental | |
15-
| SvelteKit | Experimental | |
16-
| Preact<br>React<br>Lit<br>Svelte<br>and more... | Experimental | Static web apps, powered by *Vite* |
1+
# App Hosting adapters
172

183
## Overview
194

20-
Firebase Hosting integrates with popular modern web frameworks including Angular and Next.js. Using Firebase Hosting and
21-
Cloud Functions for Firebase with these frameworks, you can develop apps and microservices in your preferred framework
22-
environment, and then deploy them in a managed, secure server environment. Support during this early preview includes
23-
the following functionality:
5+
App Hosting provides configuration-free build and deploy support for Web apps developed in these frameworks:
246

25-
* Deploy Web apps comprised of static web content
26-
* Deploy Web apps that use pre-rendering / Static Site Generation (SSG)
27-
* Deploy Web apps that use server-side Rendering (SSR)—full server rendering on demand
7+
* Next.js 13+
8+
* Angular 17.2+
289

29-
Firebase provides this functionality through the Firebase CLI. When initializing Hosting on the command line, you
30-
provide information about your new or existing Web project, and the CLI sets up the right resources for your chosen Web
31-
framework.
10+
This repo holds the code for the adapters that enable support for these frameworks. At a high level these adapters transform framework specific configurations into an [output bundle spec](#app-hosting-output-bundle) that App Hosting can use to configure frameworks support. For more information see [Framework integration](https://firebase.google.com/docs/app-hosting/about-app-hosting#frameworks).
3211

33-
We'd love to learn from you. [Express your interest in helping us shape the future of Firebase Hosting here.](https://goo.gle/41enW5X)
12+
## App Hosting output bundle
3413

35-
## Status
14+
The App Hosting output bundle is a file based specification that allows different frameworks to configure and customize their App Hosting deployment for enhanced support.
3615

37-
![Status: Experimental](https://img.shields.io/badge/Status-Experimental-blue)
16+
Any framework that can generate a build output in accordance with the App Hosting output bundle can be deployed on App Hosting.
3817

39-
This repository is maintained by Google but is not a supported Firebase product. Issues here are answered by
40-
maintainers and other community members on GitHub on a best-effort basis.
18+
The output bundle primarily consists of a `bundle.yaml` file that sits inside of the `.apphosting` directory. This bundle.yaml contains all the ways that frameworks can configure App Hosting when users deploy their applications.
4119

42-
[Please open issues related to Web Frameworks support in Firease CLI in the firebase-tools repository](https://github.com/firebase/firebase-tools/issues/new/choose).
20+
> [!NOTE]
21+
> App Hosting technically supports all all node applications, but no custom framework features will be enabled without the output bundle.
4322
44-
## Enable framework-awareness
23+
## Output bundle Schema
4524

46-
An experimental add-on to the Firebase CLI provides web framework support. To enable it, call the following:
25+
The output bundle is contained in a single file:
4726

4827
```shell
49-
firebase experiments:enable webframeworks
28+
.apphosting/bundle.yaml
5029
```
5130

52-
## Prerequisites
31+
As long as this file exists and follows the schema, App Hosting will be able to process the build properly.
5332

54-
- Firebase CLI version 10.9.1 or later (see installation instructions [here](https://firebase.google.com/docs/cli))
33+
The schema can also be found in [source](https://github.com/FirebaseExtended/firebase-framework-tools/blob/main/packages/%40apphosting/common/src/index.ts#L4)
5534

56-
57-
## Initialize Firebase Hosting
58-
59-
When you initialize Firebase Hosting it should automatically detect known Web Frameworks, if one isn't discovered
60-
you'll be given a list of supported frameworks to start with.
61-
62-
```shell
63-
firebase init hosting
64-
```
65-
66-
You should see the "source" option in your `firebase.json` rather than the traditional "public". This points to the
67-
root directory of your application's source code, relative to your `firebase.json`.
68-
69-
```json
70-
{
71-
"hosting": {
72-
"source": ".",
73-
"ignore": [
74-
"firebase.json",
75-
"**/.*",
76-
"**/node_modules/**"
77-
],
78-
"frameworksBackend": {
79-
"region": "us-central1"
80-
}
81-
}
35+
```typescript
36+
interface OutputBundle {
37+
version: "v1"
38+
runConfig: RunConfig;
39+
metadata: Metadata;
8240
}
8341
```
8442

85-
## Serve locally
43+
### Version
8644

87-
You can test your integration locally by following these steps:
45+
The `version` represents which output bundle version is currently being used. The current version is v1.
8846

89-
1. Run `firebase emulators:start` from the terminal. This should build your app and serve it using the Firebase CLI.
90-
2. Open your web app at the local URL returned by the CLI (usually http://localhost:5000).
47+
### RunConfig
9148

92-
## Deploy your app to Firebase Hosting
49+
The `runConfig` fields configures the Cloud Run service associated with the App Hosting Backend.
9350

94-
When you're ready to share your changes with the world, deploy your app to your live site:
51+
```typescript
52+
interface RunConfig {
53+
runCommand: string;
54+
environmentVariables?: EnvVarConfig[];
55+
concurrency?: number;
56+
cpu?: number;
57+
memoryMiB?: number;
58+
minInstances?: number;
59+
maxInstances?: number;
60+
}
61+
```
9562

96-
1. Run `firebase deploy` from the terminal. This will build your application, determine if a backend is needed, and if so build and deploy a Cloud Function for you.
97-
3. Check your website on: `SITE_ID.web.app` or `PROJECT_ID.web.app` (or your custom domain, if you set one up)
63+
| Field | Type | Description | Required? |
64+
| ---------- | ------- | - | - |
65+
| `runCommand` | `string` |Command to start the server (e.g. `node dist/index.js`). Assume this command is run from the root dir of the workspace. This should be the productionized version of the server start command. | y |
66+
| `environmentVariables`| `EnvVarConfig[]` | Environment variables present in the server execution environment.| n |
67+
| `concurrency` | `number` | The maximum number of concurrent requests that each server instance can receive.| n |
68+
| `cpu` | `number` |The number of CPUs used in a single server instance. | n |
69+
| `memoryMiB` | `number` | The amount of memory available for a server instance.| n |
70+
| `minInstance` | `number` |The limit on the minimum number of function instances that may coexist at a given time. | n |
71+
| `MaxInstance` | `number` | The limit on the maximum number of function instances that may coexist at a given time.| n |
72+
73+
Many of these fields are shared with `apphosting.yaml`. See the [runConfig reference documentation](https://firebase.google.com/docs/reference/apphosting/rest/v1beta/projects.locations.backends.builds#runconfig) for additional context and default values.
74+
75+
### EnvVarConfig
76+
77+
```typescript
78+
interface EnvVarConfig {
79+
variable: string;
80+
value: string;
81+
availability: 'RUNTIME'
82+
}
9883

99-
## Configuring your backend
84+
```
10085

101-
In your `firebase.json` you can alter the configuration of the code-generated Cloud Function by editing the "frameworksBackend"
102-
option. "frameworksBackend" takes the same options as [firebase-functions/v2/https.httpsOptions](https://firebase.google.com/docs/reference/functions/2nd-gen/node/firebase-functions.https.httpsoptions)
103-
though JSON-serializable. E.g,
86+
| Field | Type | Description | Required? |
87+
| ---------- | ------- | - | - |
88+
| `variable` | `string` |Name of the environment variable | y |
89+
| `value` | `string` |Value associated with the environment variable | y |
90+
| `availability` | `RUNTIME` | Where the variable will be available. For now this will always be `RUNTIME` | y |
10491

92+
### Metadata
10593

106-
```json
107-
{
108-
"hosting": {
109-
"source": ".",
110-
"ignore": [
111-
"firebase.json",
112-
"**/.*",
113-
"**/node_modules/**"
114-
],
115-
"frameworksBackend": {
116-
"region": "us-central1",
117-
"minInstances": 1,
118-
"maxInstances": 10
119-
}
120-
}
94+
```typescript
95+
interface Metadata {
96+
adapterPackageName: string;
97+
adapterVersion: string;
98+
framework: string;
99+
frameworkVersion?: string;
121100
}
101+
122102
```
123103

124-
# Contributors
104+
| Field | Type | Description | Required? |
105+
| ---------- | ------- | - | - |
106+
| `adapterPackageName` | `string` |Name of the adapter (this should be the npm package name) | y |
107+
| `adapterVersion`| `string` | Version of the adapter | y |
108+
| `framework` | `string` | Name of the framework that is being supported | y |
109+
| `frameworkVersion` | `string` |Version of the framework that is being supported | n |
125110

126-
We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to
127-
follow. [See CONTRIBUTING](./CONTRIBUTING.md).
111+
Here is a sample `bundle.yaml` file putting all this together:
128112

129-
## Building
113+
```
114+
> cat .apphosting/bundle.yaml
115+
116+
version: v1
117+
runConfig:
118+
runCommand:
119+
- node
120+
- dist/index.js
121+
environmentVariables:
122+
- variable: VAR
123+
value: 8080
124+
availability: RUNTIME
125+
concurrency: 80
126+
cpu: 2
127+
memoryMiB: 512
128+
minInstances: 0
129+
maxInstances: 14
130+
131+
metadata:
132+
adapterNpmPackageName: npm-name
133+
adapterVersion: 12.0.0
134+
frameworkNpmPackageName: framework-name
135+
adapterVersion: 1.0.0
130136
131-
```bash
132-
$ cd <YOUR-GIT-CHECKOUT>
133-
$ npm i
134-
$ npm run build
135137
```
138+
139+
As long as you have the `bundle.yaml` in this format, App Hosting will be able to deploy any framework that supports server side rendering.

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@apphosting/adapter-angular/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@apphosting/adapter-angular",
3-
"version": "17.2.10",
3+
"version": "17.2.11",
44
"main": "dist/index.js",
55
"description": "Experimental addon to the Firebase CLI to add web framework support",
66
"repository": {

packages/@apphosting/adapter-angular/src/bin/build.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
checkBuildConditions,
55
validateOutputDirectory,
66
parseOutputBundleOptions,
7+
outputBundleExists,
78
} from "../utils.js";
89
import { getBuildOptions, runBuild } from "@apphosting/common";
910

@@ -21,8 +22,10 @@ const { stdout: output } = await runBuild();
2122
if (!output) {
2223
throw new Error("No output from Angular build command, expecting a build manifest file.");
2324
}
24-
const outputBundleOptions = parseOutputBundleOptions(output);
25-
const root = process.cwd();
26-
await generateBuildOutput(root, outputBundleOptions, process.env.FRAMEWORK_VERSION);
25+
if (!outputBundleExists()) {
26+
const outputBundleOptions = parseOutputBundleOptions(output);
27+
const root = process.cwd();
28+
await generateBuildOutput(root, outputBundleOptions, process.env.FRAMEWORK_VERSION);
2729

28-
await validateOutputDirectory(outputBundleOptions);
30+
await validateOutputDirectory(outputBundleOptions);
31+
}

packages/@apphosting/adapter-angular/src/interface.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,7 @@ export const buildManifestSchema = z.object({
6363
server: z.optional(url),
6464
browser: url,
6565
}),
66-
prerenderedRoutes: z.optional(z.string().array()),
66+
// angular v18 has an array type and v19 has an object type
67+
// We should uncomment this when we need to use prerenderedRoutes
68+
// prerenderedRoutes: z.optional(z.union([z.string().array(), z.object({})])),
6769
});

packages/@apphosting/adapter-angular/src/utils.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ const __filename = fileURLToPath(import.meta.url);
2424
const __dirname = dirname(__filename);
2525
const SIMPLE_SERVER_FILE_PATH = join(__dirname, "simple-server", "bundled_server.mjs");
2626

27-
export const REQUIRED_BUILDER = "@angular-devkit/build-angular:application";
27+
export const ALLOWED_BUILDERS = [
28+
"@angular-devkit/build-angular:application",
29+
"@analogjs/platform:vite",
30+
];
2831

2932
/**
3033
* Check if the following build conditions are satisfied for the workspace:
@@ -38,9 +41,9 @@ export async function checkBuildConditions(opts: BuildOptions): Promise<void> {
3841
const output = execSync(`npx nx show project ${opts.projectName}`);
3942
const projectJson = JSON.parse(output.toString());
4043
const builder = projectJson.targets.build.executor;
41-
if (builder !== REQUIRED_BUILDER) {
44+
if (!ALLOWED_BUILDERS.includes(builder)) {
4245
throw new Error(
43-
"Only the Angular application builder is supported. Please refer to https://angular.dev/tools/cli/build-system-migration#for-existing-applications guide to upgrade your builder to the Angular application builder. ",
46+
`Currently, only the following builders are supported: ${ALLOWED_BUILDERS.join(",")}.`,
4447
);
4548
}
4649
return;
@@ -75,9 +78,9 @@ export async function checkBuildConditions(opts: BuildOptions): Promise<void> {
7578
if (!workspaceProject.targets.has(target)) throw new Error("Could not find build target.");
7679

7780
const { builder } = workspaceProject.targets.get(target)!;
78-
if (builder !== REQUIRED_BUILDER) {
81+
if (!ALLOWED_BUILDERS.includes(builder)) {
7982
throw new Error(
80-
"Only the Angular application builder is supported. Please refer to https://angular.dev/tools/cli/build-system-migration#for-existing-applications guide to upgrade your builder to the Angular application builder. ",
83+
`Currently, only the following builders are supported: ${ALLOWED_BUILDERS.join(",")}.`,
8184
);
8285
}
8386
}
@@ -226,3 +229,11 @@ export const isMain = (meta: ImportMeta) => {
226229
if (!process.argv[1]) return false;
227230
return process.argv[1] === fileURLToPath(meta.url);
228231
};
232+
233+
export const outputBundleExists = () => {
234+
const outputBundleDir = resolve(".apphosting");
235+
if (existsSync(outputBundleDir)) {
236+
return true;
237+
}
238+
return false;
239+
};

0 commit comments

Comments
 (0)