Skip to content
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

Follow on fixes for #5892 #5895

Merged
merged 14 commits into from
May 25, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Address additional cases where we were attempting to deploy a framework's development bundle (#5895)
2 changes: 1 addition & 1 deletion src/deploy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const deploy = async function (
const config = options.config.get("hosting");
if (Array.isArray(config) ? config.some((it) => it.source) : config.source) {
experiments.assertEnabled("webframeworks", "deploy a web framework from source");
await prepareFrameworks(targetNames, context, options);
await prepareFrameworks("deploy", targetNames, context, options);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/emulator/commandUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ export async function emulatorExec(script: string, options: any): Promise<void>
let deprecationNotices;
try {
const showUI = !!options.ui;
({ deprecationNotices } = await controller.startAll(options, showUI));
({ deprecationNotices } = await controller.startAll(options, showUI, true));
exitCode = await runScript(script, extraEnv);
await controller.onExit(options);
} finally {
Expand Down
11 changes: 9 additions & 2 deletions src/emulator/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ interface EmulatorOptions extends Options {
*/
export async function startAll(
options: EmulatorOptions,
showUI = true
showUI = true,
runningTestScript = false
): Promise<{ deprecationNotices: string[] }> {
// Emulators config is specified in firebase.json as:
// "emulators": {
Expand Down Expand Up @@ -463,7 +464,13 @@ export async function startAll(
}
}
// This may add additional sources for Functions emulator and must be done before it.
await prepareFrameworks(targets, options, options, emulators);
await prepareFrameworks(
runningTestScript ? "test" : "emulate",
targets,
undefined,
options,
emulators
);
}

const projectDir = (options.extDevDir || options.config.projectDir) as string;
Expand Down
2 changes: 1 addition & 1 deletion src/frameworks/angular/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export async function getValidBuildTargets(purpose: BUILD_TARGET_PURPOSE, dir: s
const validTargetNames = new Set(["development", "production"]);
try {
const { workspaceProject, browserTarget, serverTarget, serveTarget } = await getContext(dir);
const { target } = ((purpose === "serve" && serveTarget) || serverTarget || browserTarget)!;
const { target } = ((purpose === "emulate" && serveTarget) || serverTarget || browserTarget)!;
const workspaceTarget = workspaceProject.targets.get(target)!;
Object.keys(workspaceTarget.configurations || {}).forEach((it) => validTargetNames.add(it));
} catch (e) {
Expand Down
47 changes: 21 additions & 26 deletions src/frameworks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { sync as spawnSync } from "cross-spawn";
import { copyFile, readdir, readFile, rm, writeFile } from "fs/promises";
import { mkdirp, pathExists, stat } from "fs-extra";
import * as process from "node:process";
import * as semver from "semver";
import * as glob from "glob";

import { needProjectId } from "../projectUtils";
Expand Down Expand Up @@ -42,10 +41,18 @@ import {
VALID_ENGINES,
WebFrameworks,
} from "./constants";
import { BUILD_TARGET_PURPOSE, BuildResult, FirebaseDefaults, Framework } from "./interfaces";
import {
BUILD_TARGET_PURPOSE,
BuildResult,
FirebaseDefaults,
Framework,
FrameworkContext,
FrameworksOptions,
} from "./interfaces";
import { logWarning } from "../utils";
import { ensureTargeted } from "../functions/ensureTargeted";
import { isDeepStrictEqual } from "util";
import { resolveProjectPath } from "../projectPath";

export { WebFrameworks };

Expand Down Expand Up @@ -100,21 +107,14 @@ function memoizeBuild(
*
*/
export async function prepareFrameworks(
purpose: BUILD_TARGET_PURPOSE,
targetNames: string[],
context: any,
options: any,
context: FrameworkContext | undefined,
options: FrameworksOptions,
emulators: EmulatorInfo[] = []
): Promise<void> {
// `firebase-frameworks` requires Node >= 16. We must check for this to avoid horrible errors.
const nodeVersion = process.version;
if (!semver.satisfies(nodeVersion, ">=16.0.0")) {
throw new FirebaseError(
`The frameworks awareness feature requires Node.JS >= 16 and npm >= 8 in order to work correctly, due to some of the downstream dependencies. Please upgrade your version of Node.JS, reinstall firebase-tools, and give it another go.`
);
}

const project = needProjectId(context);
const { projectRoot } = options;
const project = needProjectId(context || options);
const projectRoot = resolveProjectPath(options, ".");
const account = getProjectDefaultAccount(projectRoot);
// 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
Expand Down Expand Up @@ -260,11 +260,11 @@ export async function prepareFrameworks(
);

const hostingEmulatorInfo = emulators.find((e) => e.name === Emulators.HOSTING);
const buildTargetPurpose: BUILD_TARGET_PURPOSE =
context._name === "deploy" ? "deploy" : context._name === "emulators:exec" ? "test" : "serve";
const validBuildTargets = await getValidBuildTargets(buildTargetPurpose, getProjectPath());
const frameworksBuildTarget = getFrameworksBuildTarget(buildTargetPurpose, validBuildTargets);
const useDevModeHandle = await shouldUseDevModeHandle(frameworksBuildTarget, getProjectPath());
const validBuildTargets = await getValidBuildTargets(purpose, getProjectPath());
const frameworksBuildTarget = getFrameworksBuildTarget(purpose, validBuildTargets);
const useDevModeHandle =
purpose !== "deploy" &&
(await shouldUseDevModeHandle(frameworksBuildTarget, getProjectPath()));

let codegenFunctionsDirectory: Framework["ɵcodegenFunctionsDirectory"];

Expand Down Expand Up @@ -321,7 +321,7 @@ export async function prepareFrameworks(
process.env.__FIREBASE_DEFAULTS__ = JSON.stringify(firebaseDefaults);
}

if (context.hostingChannel) {
if (context?.hostingChannel) {
experiments.assertEnabled(
"pintags",
"deploy an app that requires a backend to a preview channel"
Expand All @@ -344,12 +344,7 @@ export async function prepareFrameworks(
// This is just a fallback for previous behavior if the user manually
// disables the pintags experiment (e.g. there is a break and they would
// rather disable the experiment than roll back).
if (
!experiments.isEnabled("pintags") ||
context._name === "serve" ||
context._name === "emulators:start" ||
context._name === "emulators:exec"
) {
if (!experiments.isEnabled("pintags") || purpose !== "deploy") {
if (!targetNames.includes("functions")) {
targetNames.unshift("functions");
}
Expand Down
19 changes: 17 additions & 2 deletions src/frameworks/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { IncomingMessage, ServerResponse } from "http";
import { EmulatorInfo } from "../emulator/types";
import { HostingHeaders, HostingRedirects, HostingRewrites } from "../firebaseConfig";
import { HostingOptions } from "../hosting/options";
import { Options } from "../options";

// These serve as the order of operations for discovery
// E.g, a framework utilizing Vite should be given priority
Expand Down Expand Up @@ -32,6 +34,19 @@ export interface BuildResult {
i18n?: boolean;
}

export type RequestHandle = (req: IncomingMessage, res: ServerResponse, next: () => void) => void;
jamesdaniels marked this conversation as resolved.
Show resolved Hide resolved

export type FrameworksOptions = HostingOptions &
Options & {
frameworksDevModeHandle?: RequestHandle;
nonInteractive?: boolean;
};

export type FrameworkContext = {
projectId?: string;
hostingChannel?: string;
};

export interface Framework {
discover: (dir: string) => Promise<Discovery | undefined>;
type: FrameworkType;
Expand All @@ -44,7 +59,7 @@ export interface Framework {
dir: string,
target: string,
hostingEmulatorInfo?: EmulatorInfo
) => Promise<(req: IncomingMessage, res: ServerResponse, next: () => void) => void>;
) => Promise<RequestHandle>;
ɵcodegenPublicDirectory: (
dir: string,
dest: string,
Expand All @@ -70,7 +85,7 @@ export interface Framework {
shouldUseDevModeHandle?: (target: string, dir: string) => Promise<boolean>;
}

export type BUILD_TARGET_PURPOSE = "deploy" | "test" | "serve";
export type BUILD_TARGET_PURPOSE = "deploy" | "test" | "emulate";

// TODO pull from @firebase/util when published
export interface FirebaseDefaults {
Expand Down
2 changes: 1 addition & 1 deletion src/serve/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export async function serve(options: any): Promise<void> {
options.port = parseInt(options.port, 10);
if (targetNames.includes("hosting") && config.extract(options).some((it: any) => it.source)) {
experiments.assertEnabled("webframeworks", "emulate a web framework");
await prepareFrameworks(targetNames, options, options);
await prepareFrameworks("emulate", targetNames, undefined, options);
}
const isDemoProject = Constants.isDemoProject(getProjectId(options) || "");
targetNames.forEach((targetName) => {
Expand Down