Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 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
16 changes: 4 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/@apphosting/adapter-angular/e2e/run-local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
51 changes: 21 additions & 30 deletions packages/@apphosting/adapter-angular/src/bin/build.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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"),
Expand Down
6 changes: 3 additions & 3 deletions packages/@apphosting/adapter-angular/src/bin/build.ts
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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);
3 changes: 0 additions & 3 deletions packages/@apphosting/adapter-angular/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
64 changes: 27 additions & 37 deletions packages/@apphosting/adapter-angular/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
};
}
Expand Down Expand Up @@ -161,32 +156,28 @@ 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<void> {
await move(outputBundleOptions.baseDirectory, outputBundleOptions.outputBaseDirectory, {
overwrite: true,
});
if (outputBundleOptions.needsServerGenerated) {
await generateServer(outputBundleOptions);
}
await generateBundleYaml(outputBundleOptions, cwd, angularVersion);
}

// 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);
}
Expand All @@ -195,20 +186,20 @@ function generateEnvVars(angularVersion: string): EnvironmentVariable[] {

// Generate bundle.yaml
async function generateBundleYaml(
outputBundleOptions: OutputBundleOptions,
opts: OutputBundleOptions,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional nit: you can unpack the relevant fields here if you want

cwd: string,
angularVersion: string,
): Promise<void> {
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
Expand All @@ -222,7 +213,6 @@ export async function validateOutputDirectory(
outputBundleOptions: OutputBundleOptions,
): Promise<void> {
if (
!(await fsExtra.exists(outputBundleOptions.outputDirectory)) ||
!(await fsExtra.exists(outputBundleOptions.browserDirectory)) ||
!(await fsExtra.exists(outputBundleOptions.serverFilePath)) ||
!(await fsExtra.exists(outputBundleOptions.bundleYamlPath))
Expand Down
4 changes: 2 additions & 2 deletions packages/@apphosting/adapter-nextjs/e2e/app.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>([^<]+)<\/h2>/)?.[1];
const initialUUID = /UUID<\/p>\s*<h2>([^<]+)<\/h2>/.exec(initialText)?.[1];

// Trigger revalidation
const revalidateResponse = await fetch(posix.join(host, "isr", "demand", "revalidate"), {
Expand All @@ -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>([^<]+)<\/h2>/)?.[1];
const newUUID = /UUID<\/p>\s*<h2>([^<]+)<\/h2>/.exec(newText)?.[1];

// Check if the UUID has changed, indicating successful revalidation
assert.notEqual(initialUUID, newUUID, "UUID should change after revalidation");
Expand Down
10 changes: 5 additions & 5 deletions packages/@apphosting/common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface OutputBundleConfig {
}

// Fields needed to configure the App Hosting server
interface ServerConfig {
export interface ServerConfig {
// Command to start the server (e.g. "node dist/index.js"). Assume this command is run from the root dir of the workspace
runCommand: string;
// Environment variables set when the app is run
Expand All @@ -27,7 +27,7 @@ interface ServerConfig {
}

// Additonal fields needed for identifying the framework and adapter being used
interface Metadata {
export interface Metadata {
// Name of the adapter (this should be the official package name) e.g. "@apphosting/adapter-nextjs"
adapterPackageName: string;
// Version of the adapter, e.g. "18.0.1"
Expand All @@ -39,7 +39,7 @@ interface Metadata {
}

// Represents a single environment variable.
interface EnvVarConfig {
export interface EnvVarConfig {
// Name of the variable
variable: string;
// Value associated with the variable
Expand All @@ -49,9 +49,9 @@ interface EnvVarConfig {
}

// Represents where environment variables are made available
enum Availability {
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
Expand Down
Loading