From f26f57fa38f4fbbe77731ad530c05c8be7733ede Mon Sep 17 00:00:00 2001 From: Brian Li Date: Tue, 7 May 2024 21:34:10 +0000 Subject: [PATCH 1/3] run monorepo builds from root context --- .../adapter-angular/src/bin/build.ts | 26 ++++++++++++------- .../@apphosting/adapter-angular/src/utils.ts | 13 +++++++--- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/packages/@apphosting/adapter-angular/src/bin/build.ts b/packages/@apphosting/adapter-angular/src/bin/build.ts index 9b70c5a4..89863118 100644 --- a/packages/@apphosting/adapter-angular/src/bin/build.ts +++ b/packages/@apphosting/adapter-angular/src/bin/build.ts @@ -10,22 +10,28 @@ import { const root = process.cwd(); -// Determine root of project to build +// Determine which build runner to use +let cmd = process.env.MONOREPO_COMMAND || DEFAULT_COMMAND; + +// Read environment variable (only relevant for monorepos with multiple targets) +let target = process.env.MONOREPO_PROJECT || ""; + +// Determine root of project to build. let projectRoot = root; -if (process.env.MONOREPO_PROJECT && process.env.FIREBASE_APP_DIRECTORY) { +// N.B. We don't want to change directories for monorepo builds, so that the build process can +// locate necessary files outside the project directory (e.g. at the root). +if (process.env.FIREBASE_APP_DIRECTORY && !target) { projectRoot = projectRoot.concat("/", process.env.FIREBASE_APP_DIRECTORY); - const builder = process.env.MONOREPO_BUILDER || ""; - checkMonorepoBuildConditions(builder); +} + +// Check build conditions, which vary depending on your project structure (standalone or monorepo) +if (target) { + checkMonorepoBuildConditions(cmd, target); } else { await checkStandaloneBuildConditions(projectRoot); } -// Determine which build runner to use -let cmd = DEFAULT_COMMAND; -if (process.env.MONOREPO_COMMAND) { - cmd = process.env.MONOREPO_COMMAND; -} -const outputBundleOptions = await build(projectRoot, cmd); +const outputBundleOptions = await build(projectRoot, cmd, target); await generateOutputDirectory(root, outputBundleOptions); await validateOutputDirectory(outputBundleOptions); diff --git a/packages/@apphosting/adapter-angular/src/utils.ts b/packages/@apphosting/adapter-angular/src/utils.ts index 00098340..3dd06904 100644 --- a/packages/@apphosting/adapter-angular/src/utils.ts +++ b/packages/@apphosting/adapter-angular/src/utils.ts @@ -2,7 +2,7 @@ import fsExtra from "fs-extra"; import logger from "firebase-functions/logger"; import { fileURLToPath } from "url"; -import { spawn } from "child_process"; +import { spawn, execSync } from "child_process"; import { resolve, normalize, relative, dirname, join } from "path"; import { stringify as yamlStringify } from "yaml"; import { @@ -64,7 +64,13 @@ export async function checkStandaloneBuildConditions(cwd: string): Promise /** * Check if the monorepo build system is using the Angular application builder. */ -export function checkMonorepoBuildConditions(builder: string): void { +export function checkMonorepoBuildConditions(cmd: string, target: string) { + let builder; + if (cmd === "nx") { + const output = execSync(`npx nx show project ${target}`); + const projectJson = JSON.parse(output.toString()); + builder = projectJson.targets.build.executor; + } if (builder !== REQUIRED_BUILDER) { throw new Error( "Only the Angular application builder is supported. Please refer to https://angular.dev/tools/cli/esbuild#for-existing-applications guide to upgrade your builder to the Angular application builder. ", @@ -100,11 +106,12 @@ export function populateOutputBundleOptions(outputPaths: OutputPaths): OutputBun export const build = ( projectRoot = process.cwd(), cmd = DEFAULT_COMMAND, + ...argv: string[] ): Promise => new Promise((resolve, reject) => { // enable JSON build logs for application builder process.env.NG_BUILD_LOGS_JSON = "1"; - const childProcess = spawn(cmd, ["run", "build"], { + const childProcess = spawn(cmd, ["build", ...argv], { cwd: projectRoot, shell: true, stdio: ["inherit", "pipe", "pipe"], From 290ee3bab95ab46f219be167f6899b126e0450bc Mon Sep 17 00:00:00 2001 From: Brian Li Date: Tue, 7 May 2024 21:35:57 +0000 Subject: [PATCH 2/3] update gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index b92ea225..2d64a7f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ /packages/**/*/dist/ /examples/ /dist +/packages/@apphosting/publish-dev/.local +/packages/@apphosting/publish-dev/htpasswd # NPM node_modules From 2aa41168ff270d7e30a124a577f21819ee691dcb Mon Sep 17 00:00:00 2001 From: Brian Li Date: Wed, 8 May 2024 22:09:34 +0000 Subject: [PATCH 3/3] add 'run' back into 'npm run build' and read build args from env --- .../adapter-angular/src/bin/build.ts | 26 +++++++++++++------ .../@apphosting/adapter-angular/src/utils.ts | 2 +- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/@apphosting/adapter-angular/src/bin/build.ts b/packages/@apphosting/adapter-angular/src/bin/build.ts index 89863118..666c2eee 100644 --- a/packages/@apphosting/adapter-angular/src/bin/build.ts +++ b/packages/@apphosting/adapter-angular/src/bin/build.ts @@ -10,28 +10,38 @@ import { const root = process.cwd(); -// Determine which build runner to use -let cmd = process.env.MONOREPO_COMMAND || DEFAULT_COMMAND; +// TODO(blidd-google): Refactor monorepo logic into separate module -// Read environment variable (only relevant for monorepos with multiple targets) -let target = process.env.MONOREPO_PROJECT || ""; +// Determine which project in a monorepo to build. The environment variable will only exist when +// a monorepo has been detected in the parent buildpacks, so it can also be used to determine +// whether the project we are building is in a monorepo setup. +const project = process.env.MONOREPO_PROJECT || ""; // Determine root of project to build. let projectRoot = root; // N.B. We don't want to change directories for monorepo builds, so that the build process can // locate necessary files outside the project directory (e.g. at the root). -if (process.env.FIREBASE_APP_DIRECTORY && !target) { +if (process.env.FIREBASE_APP_DIRECTORY && !project) { projectRoot = projectRoot.concat("/", process.env.FIREBASE_APP_DIRECTORY); } +// Determine which command to run the build +const cmd = process.env.MONOREPO_COMMAND || DEFAULT_COMMAND; + +// Parse args to pass to the build command +let cmdArgs: string[] = []; +if (process.env.MONOREPO_BUILD_ARGS) { + cmdArgs = process.env.MONOREPO_BUILD_ARGS.split(","); +} + // Check build conditions, which vary depending on your project structure (standalone or monorepo) -if (target) { - checkMonorepoBuildConditions(cmd, target); +if (project) { + checkMonorepoBuildConditions(cmd, project); } else { await checkStandaloneBuildConditions(projectRoot); } -const outputBundleOptions = await build(projectRoot, cmd, target); +const outputBundleOptions = await build(projectRoot, cmd, ...cmdArgs); await generateOutputDirectory(root, outputBundleOptions); await validateOutputDirectory(outputBundleOptions); diff --git a/packages/@apphosting/adapter-angular/src/utils.ts b/packages/@apphosting/adapter-angular/src/utils.ts index 3dd06904..e19bf4b9 100644 --- a/packages/@apphosting/adapter-angular/src/utils.ts +++ b/packages/@apphosting/adapter-angular/src/utils.ts @@ -111,7 +111,7 @@ export const build = ( new Promise((resolve, reject) => { // enable JSON build logs for application builder process.env.NG_BUILD_LOGS_JSON = "1"; - const childProcess = spawn(cmd, ["build", ...argv], { + const childProcess = spawn(cmd, ["run", "build", ...argv], { cwd: projectRoot, shell: true, stdio: ["inherit", "pipe", "pipe"],