-
Couldn't load subscription status.
- Fork 1.1k
More firebase-frameworks work #4463
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
467d76d
96522a5
e79285b
3c6cbd1
80e7c07
00539b1
aeb160b
5bccec6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| import { join } from "path"; | ||
| import { exit } from "process"; | ||
|
|
||
| import { needProjectId } from "../projectUtils"; | ||
| import { normalizedHostingConfigs } from "../hosting/normalizedHostingConfigs"; | ||
| import { listSites, Site } from "../hosting/api"; | ||
| import { getAppConfig, AppPlatform } from "../management/apps"; | ||
| import { promises as fsPromises } from "fs"; | ||
| import { promptOnce } from "../prompt"; | ||
|
|
||
| const { writeFile } = fsPromises; | ||
|
|
||
| export const shortSiteName = (site?: Site) => site?.name && site.name.split("/").pop(); | ||
|
|
||
| export const prepareFrameworks = async (targetNames: string[], context: any, options: any) => { | ||
| const project = needProjectId(context); | ||
| // options.site is not present when emulated. We could call requireHostingSite but IAM permissions haven't | ||
| // been booted up (at this point) and we may be offline, so just use projectId. Most of the time | ||
| // the default site is named the same as the project & for frameworks this is only used for naming the | ||
| // function... unless you're using authenticated server-context TODO explore the implication here. | ||
| const configs = normalizedHostingConfigs({ site: project, ...options }, { resolveTargets: true }); | ||
| options.normalizedHostingConfigs = configs; | ||
| if (configs.length === 0) return; | ||
| for (const config of configs) { | ||
| const { source, site, public: publicDir } = config; | ||
| if (!source) continue; | ||
| const dist = join(".firebase", site); | ||
| const hostingDist = join(dist, "hosting"); | ||
| const functionsDist = join(dist, "functions"); | ||
| if (publicDir) | ||
| throw new Error(`hosting.public and hosting.source cannot both be set in firebase.json`); | ||
| const getProjectPath = (...args: string[]) => join(process.cwd(), source, ...args); | ||
| const functionName = `ssr${site.replace(/-/g, "")}`; | ||
| const { build } = require("firebase-frameworks/tools"); | ||
| const { usingCloudFunctions, rewrites, redirects, headers, usesFirebaseConfig } = await build( | ||
| { | ||
| dist, | ||
| project, | ||
| site, | ||
| function: { | ||
| name: functionName, | ||
| region: "us-central1", | ||
| }, | ||
| }, | ||
| getProjectPath | ||
| ); | ||
| config.public = hostingDist; | ||
| if (usingCloudFunctions) { | ||
| if (context.hostingChannel) { | ||
| // TODO move to prompts | ||
| const message = | ||
| "Cannot preview changes to the backend, you will only see changes to the static content on this channel."; | ||
| if (!options.nonInteractive) { | ||
| const continueDeploy = await promptOnce({ | ||
| type: "confirm", | ||
| default: true, | ||
| message: `${message} Would you like to continue with the deploy?`, | ||
| }); | ||
| if (!continueDeploy) exit(1); | ||
| } else { | ||
| console.error(message); | ||
| } | ||
| } else { | ||
| const functionConfig = { | ||
| source: functionsDist, | ||
| codebase: `firebase-frameworks-${site}`, | ||
| }; | ||
| if (targetNames.includes("functions")) { | ||
| const combinedFunctionsConfig = [functionConfig].concat( | ||
| options.config.get("functions") || [] | ||
| ); | ||
| options.config.set("functions", combinedFunctionsConfig); | ||
| } else { | ||
| targetNames.unshift("functions"); | ||
| options.config.set("functions", functionConfig); | ||
| } | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: add spaces and comments for this block of code. (L16-L77) Reasoning - |
||
|
|
||
| config.rewrites = [ | ||
| ...(config.rewrites || []), | ||
| ...rewrites, | ||
| { | ||
| source: "**", | ||
| function: functionName, | ||
| }, | ||
| ]; | ||
|
|
||
| let firebaseProjectConfig = null; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: (unless null string is intentional) |
||
| if (usesFirebaseConfig) { | ||
| const sites = await listSites(project); | ||
| const selectedSite = sites.find((it) => shortSiteName(it) === site); | ||
| if (selectedSite) { | ||
| const { appId } = selectedSite; | ||
| if (appId) { | ||
| firebaseProjectConfig = await getAppConfig(appId, AppPlatform.WEB); | ||
| } else { | ||
| console.warn( | ||
| `No Firebase app associated with site ${site}, unable to provide authenticated server context` | ||
| ); | ||
| } | ||
| } | ||
| } | ||
| writeFile( | ||
| join(functionsDist, ".env"), | ||
| `FRAMEWORKS_FIREBASE_PROJECT_CONFIG="${JSON.stringify(firebaseProjectConfig).replace( | ||
| /"/g, | ||
| '\\"' | ||
| )}"` | ||
| ); | ||
| } else { | ||
| config.rewrites = [ | ||
| ...(config.rewrites || []), | ||
| ...rewrites, | ||
| { | ||
| source: "**", | ||
| destination: "/index.html", | ||
| }, | ||
| ]; | ||
| } | ||
| config.redirects = [...(config.redirects || []), ...redirects]; | ||
| config.headers = [...(config.headers || []), ...headers]; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,8 +4,13 @@ import { cloneDeep } from "lodash"; | |
| import { FirebaseError } from "../error"; | ||
|
|
||
| interface HostingConfig { | ||
| source?: string; | ||
| public?: string; | ||
| site: string; | ||
| target: string; | ||
| rewrites?: any[]; | ||
| redirects?: any[]; | ||
| headers?: any[]; | ||
| } | ||
|
|
||
| function filterOnly(configs: HostingConfig[], onlyString: string): HostingConfig[] { | ||
|
|
@@ -90,6 +95,9 @@ export function normalizedHostingConfigs( | |
| cmdOptions: any, // eslint-disable-line @typescript-eslint/no-explicit-any | ||
| options: { resolveTargets?: boolean } = {} | ||
| ): HostingConfig[] { | ||
| // First see if there's a momoized copy on the options, from frameworks | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: memoized |
||
| const normalizedHostingConfigs = cmdOptions.normalizedHostingConfigs; | ||
| if (normalizedHostingConfigs) return normalizedHostingConfigs; | ||
| let configs = cloneDeep(cmdOptions.config.get("hosting")); | ||
| if (!configs) { | ||
| return []; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add docs on what this function's purpose is