UNPKG

firebase-tools

Version:
507 lines (506 loc) 24.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getBuilderType = exports.tryToGetOptionsForTarget = exports.getAngularVersion = exports.getBuildConfig = exports.getServerConfig = exports.getBrowserConfig = exports.getContext = exports.getAllTargets = exports.BuilderType = void 0; const utils_1 = require("../utils"); const error_1 = require("../../error"); const path_1 = require("path"); const assert_1 = require("assert"); const utils_2 = require("../../utils"); const semver_1 = require("semver"); async function localesForTarget(dir, architectHost, target, workspaceProject) { var _a; const { targetStringFromTarget } = await (0, utils_1.relativeRequire)(dir, "@angular-devkit/architect"); const targetOptions = await architectHost.getOptionsForTarget(target); if (!targetOptions) { const targetString = targetStringFromTarget(target); throw new error_1.FirebaseError(`Couldn't find options for ${targetString}.`); } let locales = undefined; let defaultLocale = undefined; if (targetOptions.localize) { const i18n = (_a = workspaceProject.extensions) === null || _a === void 0 ? void 0 : _a.i18n; if (!i18n) throw new error_1.FirebaseError(`No i18n config on project.`); if (typeof i18n.sourceLocale === "string") { throw new error_1.FirebaseError(`All your i18n locales must have a baseHref of "" on Firebase, use an object for sourceLocale in your angular.json: "i18n": { "sourceLocale": { "code": "${i18n.sourceLocale}", "baseHref": "" }, ... }`); } if (i18n.sourceLocale.baseHref !== "") throw new error_1.FirebaseError('All your i18n locales must have a baseHref of "" on Firebase, errored on sourceLocale.'); defaultLocale = i18n.sourceLocale.code; if (targetOptions.localize === true) { locales = [defaultLocale]; for (const [locale, { baseHref }] of Object.entries(i18n.locales)) { if (baseHref !== "") throw new error_1.FirebaseError(`All your i18n locales must have a baseHref of \"\" on Firebase, errored on ${locale}.`); locales.push(locale); } } else if (Array.isArray(targetOptions.localize)) { locales = [defaultLocale]; for (const locale of targetOptions.localize) { if (typeof locale !== "string") continue; locales.push(locale); } } } (0, utils_1.validateLocales)(locales); return { locales, defaultLocale }; } var BuilderType; (function (BuilderType) { BuilderType["DEPLOY"] = "deploy"; BuilderType["DEV_SERVER"] = "dev-server"; BuilderType["SSR_DEV_SERVER"] = "ssr-dev-server"; BuilderType["SERVER"] = "server"; BuilderType["BROWSER"] = "browser"; BuilderType["BROWSER_ESBUILD"] = "browser-esbuild"; BuilderType["APPLICATION"] = "application"; BuilderType["PRERENDER"] = "prerender"; })(BuilderType = exports.BuilderType || (exports.BuilderType = {})); const DEV_SERVER_TARGETS = [BuilderType.DEV_SERVER, BuilderType.SSR_DEV_SERVER]; function getValidBuilderTypes(purpose) { return [ BuilderType.APPLICATION, BuilderType.BROWSER_ESBUILD, BuilderType.DEPLOY, BuilderType.BROWSER, BuilderType.PRERENDER, ...(purpose === "deploy" ? [] : DEV_SERVER_TARGETS), ]; } async function getAllTargets(purpose, dir) { const validBuilderTypes = getValidBuilderTypes(purpose); const [{ NodeJsAsyncHost }, { workspaces }, { targetStringFromTarget }] = await Promise.all([ (0, utils_1.relativeRequire)(dir, "@angular-devkit/core/node"), (0, utils_1.relativeRequire)(dir, "@angular-devkit/core"), (0, utils_1.relativeRequire)(dir, "@angular-devkit/architect"), ]); const host = workspaces.createWorkspaceHost(new NodeJsAsyncHost()); const { workspace } = await workspaces.readWorkspace(dir, host); const targets = []; workspace.projects.forEach((projectDefinition, project) => { if (projectDefinition.extensions.projectType !== "application") return; projectDefinition.targets.forEach((targetDefinition, target) => { const builderType = getBuilderType(targetDefinition.builder); if (builderType && !validBuilderTypes.includes(builderType)) { return; } const configurations = Object.keys(targetDefinition.configurations || {}); if (!configurations.includes("production")) configurations.push("production"); if (!configurations.includes("development")) configurations.push("development"); configurations.forEach((configuration) => { targets.push(targetStringFromTarget({ project, target, configuration })); }); }); }); return targets; } exports.getAllTargets = getAllTargets; async function getContext(dir, targetOrConfiguration) { const [{ NodeJsAsyncHost }, { workspaces }, { WorkspaceNodeModulesArchitectHost }, { Architect, targetFromTargetString, targetStringFromTarget }, { parse },] = await Promise.all([ (0, utils_1.relativeRequire)(dir, "@angular-devkit/core/node"), (0, utils_1.relativeRequire)(dir, "@angular-devkit/core"), (0, utils_1.relativeRequire)(dir, "@angular-devkit/architect/node"), (0, utils_1.relativeRequire)(dir, "@angular-devkit/architect"), (0, utils_1.relativeRequire)(dir, "jsonc-parser"), ]); const host = workspaces.createWorkspaceHost(new NodeJsAsyncHost()); const { workspace } = await workspaces.readWorkspace(dir, host); const architectHost = new WorkspaceNodeModulesArchitectHost(workspace, dir); const architect = new Architect(architectHost); let overrideTarget; let deployTarget; let project; let buildTarget; let browserTarget; let serverTarget; let prerenderTarget; let serveTarget; let serveOptimizedImages = false; let configuration = undefined; if (targetOrConfiguration) { try { overrideTarget = targetFromTargetString(targetOrConfiguration); configuration = overrideTarget.configuration; project = overrideTarget.project; } catch (e) { configuration = targetOrConfiguration; } } if (!project) { const angularJson = parse(await host.readFile((0, path_1.join)(dir, "angular.json"))); project = angularJson.defaultProject; } if (!project) { const apps = []; workspace.projects.forEach((value, key) => { if (value.extensions.projectType === "application") apps.push(key); }); if (apps.length === 1) project = apps[0]; } if (!project) { throwCannotDetermineTarget(); } const workspaceProject = workspace.projects.get(project); if (!workspaceProject) throw new error_1.FirebaseError(`No project ${project} found.`); if (overrideTarget) { const target = workspaceProject.targets.get(overrideTarget.target); const builderType = getBuilderType(target.builder); switch (builderType) { case BuilderType.DEPLOY: deployTarget = overrideTarget; break; case BuilderType.APPLICATION: buildTarget = overrideTarget; break; case BuilderType.BROWSER: case BuilderType.BROWSER_ESBUILD: browserTarget = overrideTarget; break; case BuilderType.PRERENDER: prerenderTarget = overrideTarget; break; case BuilderType.DEV_SERVER: case BuilderType.SSR_DEV_SERVER: serveTarget = overrideTarget; break; default: throw new error_1.FirebaseError(`builder type ${builderType} not known.`); } } else if (workspaceProject.targets.has("deploy")) { const { builder, defaultConfiguration = "production" } = workspaceProject.targets.get("deploy"); if (getBuilderType(builder) === BuilderType.DEPLOY) { deployTarget = { project, target: "deploy", configuration: configuration || defaultConfiguration, }; } } if (deployTarget) { const options = await architectHost .getOptionsForTarget(deployTarget) .catch(() => { var _a; return (_a = workspaceProject.targets.get(deployTarget.target)) === null || _a === void 0 ? void 0 : _a.options; }); if (!options) throw new error_1.FirebaseError("Unable to get options for ng-deploy."); if (options.buildTarget) { (0, utils_2.assertIsString)(options.buildTarget); buildTarget = targetFromTargetString(options.buildTarget); } if (options.prerenderTarget) { (0, utils_2.assertIsString)(options.prerenderTarget); prerenderTarget = targetFromTargetString(options.prerenderTarget); } if (options.browserTarget) { (0, utils_2.assertIsString)(options.browserTarget); browserTarget = targetFromTargetString(options.browserTarget); } if (options.serverTarget) { (0, utils_2.assertIsString)(options.serverTarget); serverTarget = targetFromTargetString(options.serverTarget); } if (options.serveTarget) { (0, utils_2.assertIsString)(options.serveTarget); serveTarget = targetFromTargetString(options.serveTarget); } if (options.serveOptimizedImages) { serveOptimizedImages = true; } if (prerenderTarget) { const prerenderOptions = await architectHost.getOptionsForTarget(prerenderTarget); if (!browserTarget) { throw new error_1.FirebaseError("ng-deploy with prerenderTarget requires a browserTarget"); } if (targetStringFromTarget(browserTarget) !== (prerenderOptions === null || prerenderOptions === void 0 ? void 0 : prerenderOptions.browserTarget)) { throw new error_1.FirebaseError("ng-deploy's browserTarget and prerender's browserTarget do not match. Please check your angular.json"); } if (serverTarget && targetStringFromTarget(serverTarget) !== (prerenderOptions === null || prerenderOptions === void 0 ? void 0 : prerenderOptions.serverTarget)) { throw new error_1.FirebaseError("ng-deploy's serverTarget and prerender's serverTarget do not match. Please check your angular.json"); } if (!serverTarget) { console.warn("Treating the application as fully rendered. Add a serverTarget to your deploy target in angular.json to utilize server-side rendering."); } } if (!buildTarget && !browserTarget) { throw new error_1.FirebaseError("ng-deploy is missing a build target. Plase check your angular.json."); } } else if (!overrideTarget) { if (workspaceProject.targets.has("prerender")) { const { defaultConfiguration = "production" } = workspaceProject.targets.get("prerender"); prerenderTarget = { project, target: "prerender", configuration: configuration || defaultConfiguration, }; const options = await architectHost.getOptionsForTarget(prerenderTarget); (0, utils_2.assertIsString)(options === null || options === void 0 ? void 0 : options.browserTarget); browserTarget = targetFromTargetString(options.browserTarget); (0, utils_2.assertIsString)(options === null || options === void 0 ? void 0 : options.serverTarget); serverTarget = targetFromTargetString(options.serverTarget); } if (!buildTarget && !browserTarget && workspaceProject.targets.has("build")) { const { builder, defaultConfiguration = "production" } = workspaceProject.targets.get("build"); const builderType = getBuilderType(builder); const target = { project, target: "build", configuration: configuration || defaultConfiguration, }; if (builderType === BuilderType.BROWSER || builderType === BuilderType.BROWSER_ESBUILD) { browserTarget = target; } else { buildTarget = target; } } if (!serverTarget && workspaceProject.targets.has("server")) { const { defaultConfiguration = "production" } = workspaceProject.targets.get("server"); serverTarget = { project, target: "server", configuration: configuration || defaultConfiguration, }; } } if (!serveTarget) { if (serverTarget && workspaceProject.targets.has("serve-ssr")) { const { defaultConfiguration = "development" } = workspaceProject.targets.get("serve-ssr"); serveTarget = { project, target: "serve-ssr", configuration: configuration || defaultConfiguration, }; } else if (workspaceProject.targets.has("serve")) { const { defaultConfiguration = "development" } = workspaceProject.targets.get("serve"); serveTarget = { project, target: "serve", configuration: configuration || defaultConfiguration, }; } } for (const target of [ deployTarget, buildTarget, prerenderTarget, serverTarget, browserTarget, serveTarget, ]) { if (target) { const targetString = targetStringFromTarget(target); if (target.project !== project) throw new error_1.FirebaseError(`${targetString} is not in project ${project}. Please check your angular.json`); const definition = workspaceProject.targets.get(target.target); if (!definition) throw new error_1.FirebaseError(`${target} could not be found in your angular.json`); const { builder } = definition; const builderType = getBuilderType(builder); if (target === deployTarget && builderType === BuilderType.DEPLOY) continue; if (target === buildTarget && builderType === BuilderType.APPLICATION) continue; if (target === buildTarget && builderType === BuilderType.BROWSER) continue; if (target === browserTarget && builderType === BuilderType.BROWSER_ESBUILD) continue; if (target === browserTarget && builderType === BuilderType.BROWSER) continue; if (target === browserTarget && builderType === BuilderType.APPLICATION) continue; if (target === prerenderTarget && builderType === BuilderType.PRERENDER) continue; if (target === prerenderTarget && builderType === BuilderType.PRERENDER) continue; if (target === serverTarget && builderType === BuilderType.SERVER) continue; if (target === serveTarget && builderType === BuilderType.SSR_DEV_SERVER) continue; if (target === serveTarget && builderType === BuilderType.DEV_SERVER) continue; if (target === serveTarget && builderType === BuilderType.SERVER) continue; throw new error_1.FirebaseError(`${definition.builder} (${targetString}) is not a recognized builder. Please check your angular.json`); } } const buildOrBrowserTarget = buildTarget || browserTarget; if (!buildOrBrowserTarget) { throw new error_1.FirebaseError(`No build target on ${project}`); } const browserTargetOptions = await tryToGetOptionsForTarget(architectHost, buildOrBrowserTarget); if (!browserTargetOptions) { const targetString = targetStringFromTarget(buildOrBrowserTarget); throw new error_1.FirebaseError(`Couldn't find options for ${targetString}.`); } const baseHref = browserTargetOptions.baseHref || "/"; (0, utils_2.assertIsString)(baseHref); const buildTargetOptions = buildTarget && (await tryToGetOptionsForTarget(architectHost, buildTarget)); const ssr = buildTarget ? !!(buildTargetOptions === null || buildTargetOptions === void 0 ? void 0 : buildTargetOptions.ssr) : !!serverTarget; return { architect, architectHost, baseHref, host, buildTarget, browserTarget, prerenderTarget, serverTarget, serveTarget, workspaceProject, serveOptimizedImages, ssr, }; } exports.getContext = getContext; async function getBrowserConfig(sourceDir, configuration) { const { architectHost, browserTarget, buildTarget, baseHref, workspaceProject } = await getContext(sourceDir, configuration); const buildOrBrowserTarget = buildTarget || browserTarget; if (!buildOrBrowserTarget) { throw new assert_1.AssertionError({ message: "expected build or browser target defined" }); } const [{ locales, defaultLocale }, targetOptions, builderName] = await Promise.all([ localesForTarget(sourceDir, architectHost, buildOrBrowserTarget, workspaceProject), architectHost.getOptionsForTarget(buildOrBrowserTarget), architectHost.getBuilderNameForTarget(buildOrBrowserTarget), ]); const buildOutputPath = typeof (targetOptions === null || targetOptions === void 0 ? void 0 : targetOptions.outputPath) === "string" ? targetOptions.outputPath : (0, path_1.join)("dist", buildOrBrowserTarget.project); const outputPath = (0, path_1.join)(buildOutputPath, buildTarget && getBuilderType(builderName) === BuilderType.APPLICATION ? "browser" : ""); return { locales, baseHref, outputPath, defaultLocale }; } exports.getBrowserConfig = getBrowserConfig; async function getServerConfig(sourceDir, configuration) { var _a; const { architectHost, host, buildTarget, serverTarget, browserTarget, baseHref, workspaceProject, serveOptimizedImages, ssr, } = await getContext(sourceDir, configuration); const buildOrBrowserTarget = buildTarget || browserTarget; if (!buildOrBrowserTarget) { throw new assert_1.AssertionError({ message: "expected build or browser target to be defined" }); } const browserTargetOptions = await architectHost.getOptionsForTarget(buildOrBrowserTarget); const buildOutputPath = typeof (browserTargetOptions === null || browserTargetOptions === void 0 ? void 0 : browserTargetOptions.outputPath) === "string" ? browserTargetOptions.outputPath : (0, path_1.join)("dist", buildOrBrowserTarget.project); const browserOutputPath = (0, path_1.join)(buildOutputPath, buildTarget ? "browser" : "") .split(path_1.sep) .join(path_1.posix.sep); const packageJson = JSON.parse(await host.readFile((0, path_1.join)(sourceDir, "package.json"))); if (!ssr) { return { packageJson, browserOutputPath, serverOutputPath: undefined, baseHref, bundleDependencies: false, externalDependencies: [], serverLocales: [], browserLocales: undefined, defaultLocale: undefined, serveOptimizedImages, }; } const buildOrServerTarget = buildTarget || serverTarget; if (!buildOrServerTarget) { throw new assert_1.AssertionError({ message: "expected build or server target to be defined" }); } const { locales: serverLocales, defaultLocale } = await localesForTarget(sourceDir, architectHost, buildOrServerTarget, workspaceProject); const serverTargetOptions = await architectHost.getOptionsForTarget(buildOrServerTarget); if (!serverTargetOptions) { throw new assert_1.AssertionError({ message: `expected "JsonObject" but got "${typeof serverTargetOptions}"`, }); } const serverTargetOutputPath = typeof (serverTargetOptions === null || serverTargetOptions === void 0 ? void 0 : serverTargetOptions.outputPath) === "string" ? serverTargetOptions.outputPath : (0, path_1.join)("dist", buildOrServerTarget.project); const serverOutputPath = (0, path_1.join)(serverTargetOutputPath, buildTarget ? "server" : "") .split(path_1.sep) .join(path_1.posix.sep); if (serverLocales && !defaultLocale) { throw new error_1.FirebaseError("It's required that your source locale to be one of the localize options"); } const serverEntry = buildTarget ? "server.mjs" : serverTarget && "main.js"; const externalDependencies = serverTargetOptions.externalDependencies || []; const bundleDependencies = (_a = serverTargetOptions.bundleDependencies) !== null && _a !== void 0 ? _a : true; const { locales: browserLocales } = await localesForTarget(sourceDir, architectHost, buildOrBrowserTarget, workspaceProject); return { packageJson, browserOutputPath, serverOutputPath, baseHref, bundleDependencies, externalDependencies, serverLocales, browserLocales, defaultLocale, serveOptimizedImages, serverEntry, }; } exports.getServerConfig = getServerConfig; async function getBuildConfig(sourceDir, configuration) { const { targetStringFromTarget } = await (0, utils_1.relativeRequire)(sourceDir, "@angular-devkit/architect"); const { buildTarget, browserTarget, baseHref, prerenderTarget, serverTarget, architectHost, workspaceProject, serveOptimizedImages, ssr, } = await getContext(sourceDir, configuration); const targets = (buildTarget ? [buildTarget] : prerenderTarget ? [prerenderTarget] : [browserTarget, serverTarget].filter((it) => !!it)).map((it) => targetStringFromTarget(it)); const buildOrBrowserTarget = buildTarget || browserTarget; if (!buildOrBrowserTarget) { throw new assert_1.AssertionError({ message: "expected build or browser target defined" }); } const locales = await localesForTarget(sourceDir, architectHost, buildOrBrowserTarget, workspaceProject); return { targets, baseHref, locales, serveOptimizedImages, ssr, }; } exports.getBuildConfig = getBuildConfig; function getAngularVersion(cwd) { const dependency = (0, utils_1.findDependency)("@angular/core", { cwd, depth: 0, omitDev: false }); if (!dependency) return undefined; const angularVersionSemver = (0, semver_1.coerce)(dependency.version); if (!angularVersionSemver) return dependency.version; return angularVersionSemver.toString(); } exports.getAngularVersion = getAngularVersion; async function tryToGetOptionsForTarget(architectHost, target) { return await architectHost.getOptionsForTarget(target).catch(throwCannotDetermineTarget); } exports.tryToGetOptionsForTarget = tryToGetOptionsForTarget; function throwCannotDetermineTarget(error) { throw new error_1.FirebaseError(`Unable to determine the application to deploy, specify a target via the FIREBASE_FRAMEWORKS_BUILD_TARGET environment variable.`, { original: error }); } function getBuilderType(builder) { const colonIndex = builder.lastIndexOf(":"); const builderType = colonIndex >= 0 ? builder.slice(colonIndex + 1) : undefined; if (!builderType || !Object.values(BuilderType).includes(builderType)) { return null; } return builderType; } exports.getBuilderType = getBuilderType;