@apphosting/adapter-angular
Advanced tools
Comparing version 17.0.0-canary.a076bd8 to 17.0.0-canary.cbdb6cb
#! /usr/bin/env node | ||
import { spawn } from "child_process"; | ||
import { loadConfig } from "../utils.js"; | ||
const build = (cwd = process.cwd()) => new Promise((resolve, reject) => { | ||
// TODO warn if the build script contains anything other than `ng build` | ||
const process = spawn("npm", ["run", "build"], { cwd, shell: true, stdio: "pipe" }); | ||
process.stdout.on("data", (it) => console.log(it.toString().trim())); | ||
process.stderr.on("data", (it) => console.error(it.toString().trim())); | ||
process.on("exit", (code) => { | ||
if (code === 0) | ||
return resolve(); | ||
reject(); | ||
}); | ||
}); | ||
const config = await loadConfig(process.cwd()); | ||
await build().catch(() => process.exit(1)); | ||
// TODO do all the things | ||
console.log({ config }); | ||
import { checkBuildConditions, build, generateOutputDirectory } from "../utils.js"; | ||
const cwd = process.cwd(); | ||
await checkBuildConditions(cwd); | ||
const outputBundleOptions = await build().catch(() => process.exit(1)); | ||
await generateOutputDirectory(cwd, outputBundleOptions); |
@@ -7,3 +7,3 @@ import assert from "assert"; | ||
const importCreateJs = import("@apphosting/adapter-angular/dist/bin/create.js"); | ||
describe("peer dependencies", async () => { | ||
describe("peer dependencies", () => { | ||
let expectedAngularRange; | ||
@@ -15,5 +15,5 @@ let exepctedDevKitArchitectRange; | ||
if (!version) | ||
throw "couldn't parse package.json version"; | ||
throw new Error("couldn't parse package.json version"); | ||
expectedAngularRange = `~${version.major}.${version.minor}.0`; | ||
exepctedDevKitArchitectRange = `~0.${version.major}${version.minor < 10 ? '0' : ''}${version.minor}.0`; | ||
exepctedDevKitArchitectRange = `~0.${version.major}${version.minor < 10 ? "0" : ""}${version.minor}.0`; | ||
}); | ||
@@ -20,0 +20,0 @@ it("expected @angular/cli version requirement to match", async () => { |
@@ -1,3 +0,10 @@ | ||
export declare const readJson: typeof import("jsonfile").readFile; | ||
export declare function loadConfig(cwd: string): Promise<import("@angular-devkit/core").JsonObject>; | ||
/// <reference types="node" resolution-mode="require"/> | ||
import fsExtra from "fs-extra"; | ||
import { OutputPathOptions, OutputPaths } from "./interface.js"; | ||
export declare const writeFile: typeof import("fs").writeFile.__promisify__ & typeof import("fs").writeFile, move: typeof fsExtra.move, readJson: typeof import("jsonfile").readFile; | ||
export declare function checkBuildConditions(cwd: string): Promise<void>; | ||
export declare function populateOutputBundleOptions(outputPaths: OutputPaths): OutputPathOptions; | ||
export declare const build: (cwd?: string) => Promise<OutputPathOptions>; | ||
export declare function generateOutputDirectory(cwd: string, outputPathOptions: OutputPathOptions): Promise<void>; | ||
export declare function generateBundleYaml(outputPathOptions: OutputPathOptions, cwd: string): Promise<void>; | ||
export declare const isMain: (meta: ImportMeta) => boolean; |
import fsExtra from "fs-extra"; | ||
import logger from "firebase-functions/logger"; | ||
import { fileURLToPath } from "url"; | ||
import { spawn } from "child_process"; | ||
import { resolve, normalize, relative } from "path"; | ||
import { stringify as yamlStringify } from "yaml"; | ||
import { buildManifestSchema } from "./interface.js"; | ||
// fs-extra is CJS, readJson can't be imported using shorthand | ||
export const { readJson } = fsExtra; | ||
export async function loadConfig(cwd) { | ||
// dynamically load NextJS so this can be used in an NPX context | ||
export const { writeFile, move, readJson } = fsExtra; | ||
/* | ||
Check if build conditions are satisfied for the workspace: | ||
The workspace cannot contain multiple angular projects. | ||
The angular project must be using application builder. | ||
*/ | ||
export async function checkBuildConditions(cwd) { | ||
// dynamically load Angular so this can be used in an NPX context | ||
const { NodeJsAsyncHost } = await import(`${cwd}/node_modules/@angular-devkit/core/node/index.js`); | ||
const { workspaces } = await import(`${cwd}/node_modules/@angular-devkit/core/src/index.js`); | ||
const { WorkspaceNodeModulesArchitectHost } = await import(`${cwd}/node_modules/@angular-devkit/architect/node/index.js`); | ||
const host = workspaces.createWorkspaceHost(new NodeJsAsyncHost()); | ||
const { workspace } = await workspaces.readWorkspace(cwd, host); | ||
const architectHost = new WorkspaceNodeModulesArchitectHost(workspace, cwd); | ||
const apps = []; | ||
@@ -27,16 +35,95 @@ workspace.projects.forEach((value, key) => { | ||
throw new Error("Could not find build target."); | ||
const { builder, defaultConfiguration: configuration = "production" } = workspaceProject.targets.get(target); | ||
const { builder } = workspaceProject.targets.get(target); | ||
if (builder !== "@angular-devkit/build-angular:application") { | ||
throw new Error("Only the Angular application builder is supported."); | ||
} | ||
const buildTarget = { | ||
project, | ||
target, | ||
configuration, | ||
} | ||
// Populate file or directory paths we need for generating output directory | ||
export function populateOutputBundleOptions(outputPaths) { | ||
const outputBundleDir = resolve(".apphosting"); | ||
const baseDirectory = fileURLToPath(outputPaths["root"]); | ||
const browserRelativePath = relative(baseDirectory, fileURLToPath(outputPaths["browser"])); | ||
let serverRelativePath = "server"; | ||
if (outputPaths["server"]) { | ||
serverRelativePath = relative(baseDirectory, fileURLToPath(outputPaths["server"])); | ||
} | ||
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), | ||
}; | ||
const options = await architectHost.getOptionsForTarget(buildTarget); | ||
if (!options) | ||
throw new Error("Not able to find options for build target."); | ||
return options; | ||
} | ||
// Run build command | ||
export const build = (cwd = process.cwd()) => new Promise((resolve, reject) => { | ||
// enable JSON build logs for application builder | ||
process.env.NG_BUILD_LOGS_JSON = "1"; | ||
const childProcess = spawn("npm", ["run", "build"], { | ||
cwd, | ||
shell: true, | ||
stdio: ["inherit", "pipe", "pipe"], | ||
}); | ||
let outputPathOptions = {}; | ||
let manifest = {}; | ||
if (childProcess.stdout) { | ||
childProcess.stdout.on("data", (data) => { | ||
try { | ||
if (data.toString().includes("outputPaths")) { | ||
const parsedManifest = JSON.parse(data); | ||
// validate if the manifest is of the expected form | ||
manifest = buildManifestSchema.parse(parsedManifest); | ||
if (manifest["errors"].length > 0) { | ||
// errors when extracting manifest | ||
manifest.errors.forEach((error) => { | ||
logger.error(error); | ||
}); | ||
} | ||
if (manifest["warnings"].length > 0) { | ||
// warnings when extracting manifest | ||
manifest.warnings.forEach((warning) => { | ||
logger.info(warning); | ||
}); | ||
} | ||
outputPathOptions = populateOutputBundleOptions(manifest["outputPaths"]); | ||
} | ||
} | ||
catch (error) { | ||
throw new Error("Build manifest is not of expected structure: " + error); | ||
} | ||
}); | ||
} | ||
else { | ||
throw new Error("Unable to locate build manifest with output paths."); | ||
} | ||
childProcess.on("exit", (code) => { | ||
if (code === 0) | ||
return resolve(outputPathOptions); | ||
reject(); | ||
}); | ||
}); | ||
/* | ||
Move the base output directory, which contains the server and browser bundle directory, and prerendered routes | ||
as well as generating bundle.yaml. | ||
*/ | ||
export async function generateOutputDirectory(cwd, outputPathOptions) { | ||
await Promise.all([ | ||
move(outputPathOptions.baseDirectory, outputPathOptions.outputBaseDirectory, { | ||
overwrite: true, | ||
}), | ||
generateBundleYaml(outputPathOptions, cwd), | ||
]); | ||
} | ||
// Generate bundle.yaml | ||
export async function generateBundleYaml(outputPathOptions, cwd) { | ||
await writeFile(outputPathOptions.bundleYamlPath, yamlStringify({ | ||
headers: [], | ||
redirects: [], | ||
rewrites: [], | ||
runCommand: `node ${normalize(relative(cwd, outputPathOptions.serverFilePath))}`, | ||
neededDirs: [normalize(relative(cwd, outputPathOptions.outputDirectory))], | ||
staticAssets: [normalize(relative(cwd, outputPathOptions.browserDirectory))], | ||
})); | ||
} | ||
export const isMain = (meta) => { | ||
@@ -43,0 +130,0 @@ if (!meta) |
{ | ||
"name": "@apphosting/adapter-angular", | ||
"version": "17.0.0-canary.a076bd8", | ||
"version": "17.0.0-canary.cbdb6cb", | ||
"main": "dist/index.js", | ||
@@ -42,6 +42,5 @@ "description": "Experimental addon to the Firebase CLI to add web framework support", | ||
"dependencies": { | ||
"fs-extra": "*", | ||
"yaml": "*", | ||
"tslib": "*", | ||
"@npmcli/run-script": "*" | ||
"fs-extra": "^11.1.1", | ||
"yaml": "^2.3.4", | ||
"tslib": "^2.3.1" | ||
}, | ||
@@ -48,0 +47,0 @@ "peerDependencies": { |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Wildcard dependency
QualityPackage has a dependency with a floating version range. This can cause issues if the dependency publishes a new major version.
Found 4 instances in 1 package
13556
5
13
299
1
3
3
- Removed@npmcli/run-script@*
- Removed@isaacs/cliui@8.0.2(transitive)
- Removed@isaacs/fs-minipass@4.0.1(transitive)
- Removed@npmcli/agent@3.0.0(transitive)
- Removed@npmcli/fs@4.0.0(transitive)
- Removed@npmcli/git@6.0.3(transitive)
- Removed@npmcli/node-gyp@4.0.0(transitive)
- Removed@npmcli/package-json@6.1.1(transitive)
- Removed@npmcli/promise-spawn@8.0.2(transitive)
- Removed@npmcli/run-script@9.0.2(transitive)
- Removed@pkgjs/parseargs@0.11.0(transitive)
- Removedabbrev@3.0.0(transitive)
- Removedagent-base@7.1.3(transitive)
- Removedansi-regex@5.0.16.1.0(transitive)
- Removedansi-styles@4.3.06.2.1(transitive)
- Removedbalanced-match@1.0.2(transitive)
- Removedbrace-expansion@2.0.1(transitive)
- Removedcacache@19.0.1(transitive)
- Removedchownr@3.0.0(transitive)
- Removedcolor-convert@2.0.1(transitive)
- Removedcolor-name@1.1.4(transitive)
- Removedcross-spawn@7.0.6(transitive)
- Removeddebug@4.4.0(transitive)
- Removedeastasianwidth@0.2.0(transitive)
- Removedemoji-regex@8.0.09.2.2(transitive)
- Removedencoding@0.1.13(transitive)
- Removedenv-paths@2.2.1(transitive)
- Removederr-code@2.0.3(transitive)
- Removedexponential-backoff@3.1.2(transitive)
- Removedforeground-child@3.3.0(transitive)
- Removedfs-minipass@3.0.3(transitive)
- Removedglob@10.4.5(transitive)
- Removedhosted-git-info@8.0.2(transitive)
- Removedhttp-cache-semantics@4.1.1(transitive)
- Removedhttp-proxy-agent@7.0.2(transitive)
- Removedhttps-proxy-agent@7.0.6(transitive)
- Removediconv-lite@0.6.3(transitive)
- Removedimurmurhash@0.1.4(transitive)
- Removedini@5.0.0(transitive)
- Removedip-address@9.0.5(transitive)
- Removedis-fullwidth-code-point@3.0.0(transitive)
- Removedisexe@2.0.03.1.1(transitive)
- Removedjackspeak@3.4.3(transitive)
- Removedjsbn@1.1.0(transitive)
- Removedjson-parse-even-better-errors@4.0.0(transitive)
- Removedlru-cache@10.4.3(transitive)
- Removedmake-fetch-happen@14.0.3(transitive)
- Removedminimatch@9.0.5(transitive)
- Removedminipass@3.3.67.1.2(transitive)
- Removedminipass-collect@2.0.1(transitive)
- Removedminipass-fetch@4.0.0(transitive)
- Removedminipass-flush@1.0.5(transitive)
- Removedminipass-pipeline@1.2.4(transitive)
- Removedminipass-sized@1.0.3(transitive)
- Removedminizlib@3.0.1(transitive)
- Removedmkdirp@3.0.1(transitive)
- Removedms@2.1.3(transitive)
- Removednegotiator@1.0.0(transitive)
- Removednode-gyp@11.1.0(transitive)
- Removednopt@8.1.0(transitive)
- Removednpm-install-checks@7.1.1(transitive)
- Removednpm-normalize-package-bin@4.0.0(transitive)
- Removednpm-package-arg@12.0.2(transitive)
- Removednpm-pick-manifest@10.0.0(transitive)
- Removedp-map@7.0.3(transitive)
- Removedpackage-json-from-dist@1.0.1(transitive)
- Removedpath-key@3.1.1(transitive)
- Removedpath-scurry@1.11.1(transitive)
- Removedproc-log@5.0.0(transitive)
- Removedpromise-retry@2.0.1(transitive)
- Removedretry@0.12.0(transitive)
- Removedrimraf@5.0.10(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsemver@7.7.1(transitive)
- Removedshebang-command@2.0.0(transitive)
- Removedshebang-regex@3.0.0(transitive)
- Removedsignal-exit@4.1.0(transitive)
- Removedsmart-buffer@4.2.0(transitive)
- Removedsocks@2.8.4(transitive)
- Removedsocks-proxy-agent@8.0.5(transitive)
- Removedspdx-correct@3.2.0(transitive)
- Removedspdx-exceptions@2.5.0(transitive)
- Removedspdx-expression-parse@3.0.1(transitive)
- Removedspdx-license-ids@3.0.21(transitive)
- Removedsprintf-js@1.1.3(transitive)
- Removedssri@12.0.0(transitive)
- Removedstring-width@4.2.35.1.2(transitive)
- Removedstrip-ansi@6.0.17.1.0(transitive)
- Removedtar@7.4.3(transitive)
- Removedunique-filename@4.0.0(transitive)
- Removedunique-slug@5.0.0(transitive)
- Removedvalidate-npm-package-license@3.0.4(transitive)
- Removedvalidate-npm-package-name@6.0.0(transitive)
- Removedwhich@2.0.25.0.0(transitive)
- Removedwrap-ansi@7.0.08.1.0(transitive)
- Removedyallist@4.0.05.0.0(transitive)
Updatedfs-extra@^11.1.1
Updatedtslib@^2.3.1
Updatedyaml@^2.3.4