diff --git a/package-lock.json b/package-lock.json index ce44600f..e0d93a6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25604,7 +25604,7 @@ } }, "packages/@apphosting/adapter-angular": { - "version": "17.2.8", + "version": "17.2.9", "license": "Apache-2.0", "dependencies": { "@apphosting/common": "*", @@ -25663,12 +25663,6 @@ "zone.js": "~0.14.0" } }, - "packages/@apphosting/adapter-angular/node_modules/@apphosting/common": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@apphosting/common/-/common-0.0.2.tgz", - "integrity": "sha512-ab+vq1ntGo1YoKvyYRptkQt3QE86dg+tSZYFSCt9ovEtFjV/zepOGW8hvhnWLpNGErcyE7f2cExySOiLZW/ZPQ==", - "license": "Apache-2.0" - }, "packages/@apphosting/adapter-angular/node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -25814,7 +25808,7 @@ } }, "packages/@apphosting/common": { - "version": "0.0.3", + "version": "0.0.4", "license": "Apache-2.0" }, "packages/@apphosting/create": { diff --git a/packages/@apphosting/adapter-angular/e2e/run-local.ts b/packages/@apphosting/adapter-angular/e2e/run-local.ts index 794e7d3d..6bd3c964 100644 --- a/packages/@apphosting/adapter-angular/e2e/run-local.ts +++ b/packages/@apphosting/adapter-angular/e2e/run-local.ts @@ -73,7 +73,7 @@ const tests = await Promise.all( const bundleYaml = parseYaml(readFileSync(join(cwd, ".apphosting/bundle.yaml")).toString()); - const runCommand = bundleYaml.runCommand; + const runCommand = bundleYaml.serverConfig.runCommand; if (typeof runCommand !== "string") { throw new Error("runCommand must be a string"); diff --git a/packages/@apphosting/adapter-angular/package.json b/packages/@apphosting/adapter-angular/package.json index 9858c0e0..9febda09 100644 --- a/packages/@apphosting/adapter-angular/package.json +++ b/packages/@apphosting/adapter-angular/package.json @@ -1,6 +1,6 @@ { "name": "@apphosting/adapter-angular", - "version": "17.2.8", + "version": "17.2.9", "main": "dist/index.js", "description": "Experimental addon to the Firebase CLI to add web framework support", "repository": { diff --git a/packages/@apphosting/adapter-angular/src/bin/build.spec.ts b/packages/@apphosting/adapter-angular/src/bin/build.spec.ts index 2e500c8b..0a4d9807 100644 --- a/packages/@apphosting/adapter-angular/src/bin/build.spec.ts +++ b/packages/@apphosting/adapter-angular/src/bin/build.spec.ts @@ -13,38 +13,32 @@ describe("build commands", () => { beforeEach(() => { tmpDir = generateTmpDir(); outputBundleOptions = { - baseDirectory: resolve(tmpDir, "dist", "test"), - browserDirectory: resolve(tmpDir, ".apphosting", "dist", "browser"), + browserDirectory: resolve(tmpDir, "dist", "test", "browser"), bundleYamlPath: resolve(tmpDir, ".apphosting", "bundle.yaml"), - outputBaseDirectory: resolve(tmpDir, ".apphosting", "dist"), - outputDirectory: resolve(tmpDir, ".apphosting"), - serverFilePath: resolve(tmpDir, ".apphosting", "dist", "server", "server.mjs"), + serverFilePath: resolve(tmpDir, "dist", "test", "server", "server.mjs"), needsServerGenerated: false, }; defaultAngularVersion = "17.3.8"; }); it("expects all output bundle files to be generated", async () => { - const { generateOutputDirectory, validateOutputDirectory, createMetadata } = await importUtils; + const { generateBuildOutput, validateOutputDirectory, createMetadata } = await importUtils; const files = { "dist/test/browser/browserfile": "", "dist/test/server/server.mjs": "", }; const packageVersion = createMetadata(defaultAngularVersion).adapterVersion; generateTestFiles(tmpDir, files); - await generateOutputDirectory(tmpDir, outputBundleOptions, defaultAngularVersion); + await generateBuildOutput(tmpDir, outputBundleOptions, defaultAngularVersion); await validateOutputDirectory(outputBundleOptions); const expectedFiles = { - ".apphosting/dist/browser/browserfile": "", - ".apphosting/dist/server/server.mjs": "", - ".apphosting/bundle.yaml": ` -runCommand: node .apphosting/dist/server/server.mjs -neededDirs: - - .apphosting -staticAssets: - - .apphosting/dist/browser -env: [] + "dist/test/browser/browserfile": "", + "dist/test/server/server.mjs": "", + ".apphosting/bundle.yaml": `version: v1 +serverConfig: + runCommand: node dist/test/server/server.mjs + environmentVariables: [] metadata: adapterPackageName: "@apphosting/adapter-angular" adapterVersion: ${packageVersion} @@ -56,43 +50,40 @@ metadata: }); it("expects SSR_PORT variable is added to bundle.yaml for Angular v17.3.2", async () => { - const { generateOutputDirectory } = await importUtils; + const { generateBuildOutput } = await importUtils; const files = { "dist/test/browser/browserfile": "", "dist/test/server/server.mjs": "", }; generateTestFiles(tmpDir, files); - await generateOutputDirectory(tmpDir, outputBundleOptions, "17.3.2"); + await generateBuildOutput(tmpDir, outputBundleOptions, "17.3.2"); - const expectedContents = `env: - - variable: SSR_PORT - value: "8080" - availability: RUNTIME -`; + const expectedContents = ` environmentVariables: + - variable: SSR_PORT + value: "8080" + availability: + - RUNTIME`; validateFileExistsAndContains(tmpDir, ".apphosting/bundle.yaml", expectedContents); }); it("test failed validateOutputDirectory", async () => { - const { generateOutputDirectory, validateOutputDirectory } = await importUtils; + const { generateBuildOutput, validateOutputDirectory } = await importUtils; const files = { "dist/test/browser/browserfile": "", "dist/test/server/notserver.mjs": "", }; generateTestFiles(tmpDir, files); - await generateOutputDirectory(tmpDir, outputBundleOptions, defaultAngularVersion); + await generateBuildOutput(tmpDir, outputBundleOptions, defaultAngularVersion); assert.rejects(async () => await validateOutputDirectory(outputBundleOptions)); }); it("test populate output bundle options", async () => { const { populateOutputBundleOptions } = await importUtils; const expectedOutputBundleOptions = { - baseDirectory: "/test", - browserDirectory: resolve(".apphosting", "browser"), + browserDirectory: "/browser", bundleYamlPath: resolve(".apphosting", "bundle.yaml"), - outputBaseDirectory: resolve(".apphosting", "dist"), - outputDirectory: resolve("", ".apphosting"), needsServerGenerated: false, - serverFilePath: resolve(".apphosting", "server", "server.mjs"), + serverFilePath: path.join("/server", "server.mjs"), }; const outputPaths = { root: new URL("file:///test"), diff --git a/packages/@apphosting/adapter-angular/src/bin/build.ts b/packages/@apphosting/adapter-angular/src/bin/build.ts index 72ad102a..cc67f4a8 100644 --- a/packages/@apphosting/adapter-angular/src/bin/build.ts +++ b/packages/@apphosting/adapter-angular/src/bin/build.ts @@ -1,13 +1,12 @@ #! /usr/bin/env node import { - generateOutputDirectory, + generateBuildOutput, checkBuildConditions, validateOutputDirectory, parseOutputBundleOptions, } from "../utils.js"; import { getBuildOptions, runBuild } from "@apphosting/common"; -const root = process.cwd(); const opts = getBuildOptions(); // Check build conditions, which vary depending on your project structure (standalone or monorepo) @@ -23,6 +22,7 @@ if (!output) { throw new Error("No output from Angular build command, expecting a build manifest file."); } const outputBundleOptions = parseOutputBundleOptions(output); -await generateOutputDirectory(root, outputBundleOptions, process.env.FRAMEWORK_VERSION); +const root = process.cwd(); +await generateBuildOutput(root, outputBundleOptions, process.env.FRAMEWORK_VERSION); await validateOutputDirectory(outputBundleOptions); diff --git a/packages/@apphosting/adapter-angular/src/interface.ts b/packages/@apphosting/adapter-angular/src/interface.ts index 5826d2a4..1605b31f 100644 --- a/packages/@apphosting/adapter-angular/src/interface.ts +++ b/packages/@apphosting/adapter-angular/src/interface.ts @@ -4,9 +4,6 @@ import { URL } from "node:url"; // options to help generate output directory export interface OutputBundleOptions { bundleYamlPath: string; - outputDirectory: string; - baseDirectory: string; - outputBaseDirectory: string; serverFilePath: string; browserDirectory: string; needsServerGenerated: boolean; diff --git a/packages/@apphosting/adapter-angular/src/utils.ts b/packages/@apphosting/adapter-angular/src/utils.ts index de96f270..0b760085 100644 --- a/packages/@apphosting/adapter-angular/src/utils.ts +++ b/packages/@apphosting/adapter-angular/src/utils.ts @@ -5,17 +5,16 @@ import { fileURLToPath } from "url"; import { execSync } from "child_process"; import { resolve, normalize, relative, dirname, join } from "path"; import { stringify as yamlStringify } from "yaml"; -import { - Availability, - EnvironmentVariable, - Metadata, - OutputBundleOptions, - OutputPaths, - buildManifestSchema, -} from "./interface.js"; +import { OutputBundleOptions, OutputPaths, buildManifestSchema } from "./interface.js"; import { createRequire } from "node:module"; import stripAnsi from "strip-ansi"; -import { BuildOptions } from "@apphosting/common"; +import { + BuildOptions, + OutputBundleConfig, + EnvVarConfig, + Metadata, + Availability, +} from "@apphosting/common"; // fs-extra is CJS, readJson can't be imported using shorthand export const { writeFile, move, readJson, mkdir, copyFile, readFileSync, existsSync } = fsExtra; @@ -95,14 +94,10 @@ export function populateOutputBundleOptions(outputPaths: OutputPaths): OutputBun serverRelativePath = relative(baseDirectory, fileURLToPath(outputPaths["server"])); needsServerGenerated = false; } - return { bundleYamlPath: resolve(outputBundleDir, "bundle.yaml"), - outputDirectory: outputBundleDir, - baseDirectory, - outputBaseDirectory: resolve(outputBundleDir, "dist"), - serverFilePath: resolve(outputBundleDir, "dist", serverRelativePath, "server.mjs"), - browserDirectory: resolve(outputBundleDir, "dist", browserRelativePath), + serverFilePath: resolve(baseDirectory, serverRelativePath, "server.mjs"), + browserDirectory: resolve(baseDirectory, browserRelativePath), needsServerGenerated, }; } @@ -161,17 +156,13 @@ export function createMetadata(angularVersion: string): Metadata { } /** - * Move the base output directory, which contains the server and browser bundle directory, and prerendered routes - * as well as generating bundle.yaml. + * Generate the bundle.yaml */ -export async function generateOutputDirectory( +export async function generateBuildOutput( cwd: string, outputBundleOptions: OutputBundleOptions, angularVersion: string, ): Promise { - await move(outputBundleOptions.baseDirectory, outputBundleOptions.outputBaseDirectory, { - overwrite: true, - }); if (outputBundleOptions.needsServerGenerated) { await generateServer(outputBundleOptions); } @@ -179,14 +170,14 @@ export async function generateOutputDirectory( } // add environment variable to bundle.yaml if needed for specific versions -function generateEnvVars(angularVersion: string): EnvironmentVariable[] { - const runtimeEnvVars: EnvironmentVariable[] = []; +function generateEnvVars(angularVersion: string): EnvVarConfig[] { + const runtimeEnvVars: EnvVarConfig[] = []; // add env var to solve angular port issue, existing only for Angular v17.3.2 (b/332896115) if (angularVersion === "17.3.2") { - const ssrPortEnvVar: EnvironmentVariable = { + const ssrPortEnvVar: EnvVarConfig = { variable: "SSR_PORT", value: "8080", - availability: Availability.Runtime, + availability: [Availability.Runtime], }; runtimeEnvVars.push(ssrPortEnvVar); } @@ -195,20 +186,20 @@ function generateEnvVars(angularVersion: string): EnvironmentVariable[] { // Generate bundle.yaml async function generateBundleYaml( - outputBundleOptions: OutputBundleOptions, + opts: OutputBundleOptions, cwd: string, angularVersion: string, ): Promise { - await writeFile( - outputBundleOptions.bundleYamlPath, - yamlStringify({ - runCommand: `node ${normalize(relative(cwd, outputBundleOptions.serverFilePath))}`, - neededDirs: [normalize(relative(cwd, outputBundleOptions.outputDirectory))], - staticAssets: [normalize(relative(cwd, outputBundleOptions.browserDirectory))], - env: generateEnvVars(angularVersion), - metadata: createMetadata(angularVersion), - }), - ); + await mkdir(dirname(opts.bundleYamlPath)); + const outputBundle: OutputBundleConfig = { + version: "v1", + serverConfig: { + runCommand: `node ${normalize(relative(cwd, opts.serverFilePath))}`, + environmentVariables: generateEnvVars(angularVersion), + }, + metadata: createMetadata(angularVersion), + }; + await writeFile(opts.bundleYamlPath, yamlStringify(outputBundle)); } // Generate server file for CSR apps @@ -222,7 +213,6 @@ export async function validateOutputDirectory( outputBundleOptions: OutputBundleOptions, ): Promise { if ( - !(await fsExtra.exists(outputBundleOptions.outputDirectory)) || !(await fsExtra.exists(outputBundleOptions.browserDirectory)) || !(await fsExtra.exists(outputBundleOptions.serverFilePath)) || !(await fsExtra.exists(outputBundleOptions.bundleYamlPath)) diff --git a/packages/@apphosting/adapter-nextjs/e2e/app.spec.ts b/packages/@apphosting/adapter-nextjs/e2e/app.spec.ts index 888ac71e..2cee8383 100644 --- a/packages/@apphosting/adapter-nextjs/e2e/app.spec.ts +++ b/packages/@apphosting/adapter-nextjs/e2e/app.spec.ts @@ -96,7 +96,7 @@ describe("app", () => { const initialResponse = await fetch(posix.join(host, "isr", "demand")); assert.ok(initialResponse.ok); const initialText = await initialResponse.text(); - const initialUUID = initialText.match(/UUID<\/p>\s*

([^<]+)<\/h2>/)?.[1]; + const initialUUID = /UUID<\/p>\s*

([^<]+)<\/h2>/.exec(initialText)?.[1]; // Trigger revalidation const revalidateResponse = await fetch(posix.join(host, "isr", "demand", "revalidate"), { @@ -108,7 +108,7 @@ describe("app", () => { const newResponse = await fetch(posix.join(host, "isr", "demand")); assert.ok(newResponse.ok); const newText = await newResponse.text(); - const newUUID = newText.match(/UUID<\/p>\s*

([^<]+)<\/h2>/)?.[1]; + const newUUID = /UUID<\/p>\s*

([^<]+)<\/h2>/.exec(newText)?.[1]; // Check if the UUID has changed, indicating successful revalidation assert.notEqual(initialUUID, newUUID, "UUID should change after revalidation"); diff --git a/packages/@apphosting/common/package.json b/packages/@apphosting/common/package.json index b598da48..44951768 100644 --- a/packages/@apphosting/common/package.json +++ b/packages/@apphosting/common/package.json @@ -1,6 +1,6 @@ { "name": "@apphosting/common", - "version": "0.0.3", + "version": "0.0.4", "description": "Shared library code for App Hosting framework adapters", "author": { "name": "Firebase", diff --git a/packages/@apphosting/common/src/index.ts b/packages/@apphosting/common/src/index.ts index 00f4430e..146930ea 100644 --- a/packages/@apphosting/common/src/index.ts +++ b/packages/@apphosting/common/src/index.ts @@ -51,7 +51,7 @@ export interface EnvVarConfig { // Represents where environment variables are made available export enum Availability { // Runtime environment variables are available on the server when the app is run - Runtime, + Runtime = "RUNTIME", } // Options to configure the build of a framework application