389 lines
20 KiB
JavaScript
389 lines
20 KiB
JavaScript
"use strict";
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
}) : (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
o[k2] = m[k];
|
|
}));
|
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
}) : function(o, v) {
|
|
o["default"] = v;
|
|
});
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
if (mod && mod.__esModule) return mod;
|
|
var result = {};
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
__setModuleDefault(result, mod);
|
|
return result;
|
|
};
|
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
};
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.deployToCloudRun = exports.deployToFunction = void 0;
|
|
const architect_1 = require("@angular-devkit/architect");
|
|
const fs_1 = require("fs");
|
|
const fs_extra_1 = require("fs-extra");
|
|
const path_1 = require("path");
|
|
const child_process_1 = require("child_process");
|
|
const functions_templates_1 = require("./functions-templates");
|
|
const semver_1 = require("semver");
|
|
const open_1 = __importDefault(require("open"));
|
|
const schematics_1 = require("@angular-devkit/schematics");
|
|
const versions_json_1 = require("../versions.json");
|
|
const winston = __importStar(require("winston"));
|
|
const triple_beam_1 = __importDefault(require("triple-beam"));
|
|
const inquirer = __importStar(require("inquirer"));
|
|
const DEFAULT_EMULATOR_PORT = 5000;
|
|
const DEFAULT_EMULATOR_HOST = 'localhost';
|
|
const DEFAULT_CLOUD_RUN_OPTIONS = {
|
|
memory: '1Gi',
|
|
timeout: 60,
|
|
maxInstances: 'default',
|
|
maxConcurrency: 'default',
|
|
minInstances: 'default',
|
|
cpus: 1,
|
|
};
|
|
const spawnAsync = (command, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
return new Promise((resolve, reject) => {
|
|
const [spawnCommand, ...args] = command.split(/\s+/);
|
|
const spawnProcess = child_process_1.spawn(spawnCommand, args, options);
|
|
const chunks = [];
|
|
const errorChunks = [];
|
|
spawnProcess.stdout.on('data', (data) => {
|
|
process.stdout.write(data.toString());
|
|
chunks.push(data);
|
|
});
|
|
spawnProcess.stderr.on('data', (data) => {
|
|
process.stderr.write(data.toString());
|
|
errorChunks.push(data);
|
|
});
|
|
spawnProcess.on('error', (error) => {
|
|
reject(error);
|
|
});
|
|
spawnProcess.on('close', (code) => {
|
|
if (code === 1) {
|
|
reject(Buffer.concat(errorChunks).toString());
|
|
return;
|
|
}
|
|
resolve(Buffer.concat(chunks));
|
|
});
|
|
});
|
|
});
|
|
const escapeRegExp = (str) => str.replace(/[\-\[\]\/{}()*+?.\\^$|]/g, '\\$&');
|
|
const moveSync = (src, dest) => {
|
|
fs_extra_1.copySync(src, dest);
|
|
fs_extra_1.removeSync(src);
|
|
};
|
|
const deployToHosting = (firebaseTools, context, workspaceRoot, options, firebaseToken) => __awaiter(void 0, void 0, void 0, function* () {
|
|
var _a;
|
|
const siteTarget = (_a = options.target) !== null && _a !== void 0 ? _a : context.target.project;
|
|
if (options.preview) {
|
|
yield firebaseTools.serve({
|
|
port: DEFAULT_EMULATOR_PORT,
|
|
host: DEFAULT_EMULATOR_HOST,
|
|
only: `hosting:${siteTarget}`,
|
|
nonInteractive: true,
|
|
projectRoot: workspaceRoot,
|
|
});
|
|
const { deployProject } = yield inquirer.prompt({
|
|
type: 'confirm',
|
|
name: 'deployProject',
|
|
message: 'Would you like to deploy your application to Firebase Hosting?'
|
|
});
|
|
if (!deployProject) {
|
|
return;
|
|
}
|
|
process.env.FIREBASE_FRAMEWORKS_SKIP_BUILD = 'true';
|
|
}
|
|
return yield firebaseTools.deploy({
|
|
only: `hosting:${siteTarget}`,
|
|
cwd: workspaceRoot,
|
|
token: firebaseToken,
|
|
nonInteractive: true,
|
|
projectRoot: workspaceRoot,
|
|
});
|
|
});
|
|
const defaultFsHost = {
|
|
moveSync,
|
|
writeFileSync: fs_1.writeFileSync,
|
|
renameSync: fs_1.renameSync,
|
|
copySync: fs_extra_1.copySync,
|
|
removeSync: fs_extra_1.removeSync,
|
|
existsSync: fs_1.existsSync,
|
|
};
|
|
const findPackageVersion = (packageManager, name) => {
|
|
const match = child_process_1.execSync(`${packageManager} list ${name}`).toString().match(`[^|\s]${escapeRegExp(name)}[@| ][^\s]+(\s.+)?$`);
|
|
return match ? match[0].split(new RegExp(`${escapeRegExp(name)}[@| ]`))[1].split(/\s/)[0] : null;
|
|
};
|
|
const getPackageJson = (context, workspaceRoot, options, main) => {
|
|
var _a, _b, _c, _d, _e;
|
|
const dependencies = {};
|
|
const devDependencies = {};
|
|
if (options.ssr !== 'cloud-run') {
|
|
Object.keys(versions_json_1.firebaseFunctionsDependencies).forEach(name => {
|
|
const { version, dev } = versions_json_1.firebaseFunctionsDependencies[name];
|
|
(dev ? devDependencies : dependencies)[name] = version;
|
|
});
|
|
}
|
|
if (fs_1.existsSync(path_1.join(workspaceRoot, 'angular.json'))) {
|
|
const angularJson = JSON.parse(fs_1.readFileSync(path_1.join(workspaceRoot, 'angular.json')).toString());
|
|
const packageManager = (_b = (_a = angularJson.cli) === null || _a === void 0 ? void 0 : _a.packageManager) !== null && _b !== void 0 ? _b : 'npm';
|
|
const server = angularJson.projects[context.target.project].architect.server;
|
|
const externalDependencies = ((_c = server === null || server === void 0 ? void 0 : server.options) === null || _c === void 0 ? void 0 : _c.externalDependencies) || [];
|
|
const bundleDependencies = (_e = (_d = server === null || server === void 0 ? void 0 : server.options) === null || _d === void 0 ? void 0 : _d.bundleDependencies) !== null && _e !== void 0 ? _e : true;
|
|
if (bundleDependencies) {
|
|
externalDependencies.forEach(externalDependency => {
|
|
const packageVersion = findPackageVersion(packageManager, externalDependency);
|
|
if (packageVersion) {
|
|
dependencies[externalDependency] = packageVersion;
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
if (fs_1.existsSync(path_1.join(workspaceRoot, 'package.json'))) {
|
|
const packageJson = JSON.parse(fs_1.readFileSync(path_1.join(workspaceRoot, 'package.json')).toString());
|
|
Object.keys(packageJson.dependencies).forEach((dependency) => {
|
|
dependencies[dependency] = packageJson.dependencies[dependency];
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return functions_templates_1.defaultPackage(dependencies, devDependencies, options, main);
|
|
};
|
|
const deployToFunction = (firebaseTools, context, workspaceRoot, staticBuildTarget, serverBuildTarget, options, firebaseToken, fsHost = defaultFsHost) => __awaiter(void 0, void 0, void 0, function* () {
|
|
var _b;
|
|
const staticBuildOptions = yield context.getTargetOptions(architect_1.targetFromTargetString(staticBuildTarget.name));
|
|
if (!staticBuildOptions.outputPath || typeof staticBuildOptions.outputPath !== 'string') {
|
|
throw new Error(`Cannot read the output path option of the Angular project '${staticBuildTarget.name}' in angular.json`);
|
|
}
|
|
const serverBuildOptions = yield context.getTargetOptions(architect_1.targetFromTargetString(serverBuildTarget.name));
|
|
if (!serverBuildOptions.outputPath || typeof serverBuildOptions.outputPath !== 'string') {
|
|
throw new Error(`Cannot read the output path option of the Angular project '${serverBuildTarget.name}' in angular.json`);
|
|
}
|
|
const staticOut = path_1.join(workspaceRoot, staticBuildOptions.outputPath);
|
|
const serverOut = path_1.join(workspaceRoot, serverBuildOptions.outputPath);
|
|
const functionsOut = options.outputPath ? path_1.join(workspaceRoot, options.outputPath) : path_1.dirname(serverOut);
|
|
const functionName = options.functionName || functions_templates_1.DEFAULT_FUNCTION_NAME;
|
|
const newStaticOut = path_1.join(functionsOut, staticBuildOptions.outputPath);
|
|
const newServerOut = path_1.join(functionsOut, serverBuildOptions.outputPath);
|
|
if (options.outputPath) {
|
|
fsHost.removeSync(functionsOut);
|
|
fsHost.copySync(staticOut, newStaticOut);
|
|
fsHost.copySync(serverOut, newServerOut);
|
|
}
|
|
else {
|
|
fsHost.moveSync(staticOut, newStaticOut);
|
|
fsHost.moveSync(serverOut, newServerOut);
|
|
}
|
|
const packageJson = getPackageJson(context, workspaceRoot, options);
|
|
const nodeVersion = packageJson.engines.node;
|
|
if (!semver_1.satisfies(process.versions.node, nodeVersion.toString())) {
|
|
context.logger.warn(`⚠️ Your Node.js version (${process.versions.node}) does not match the Firebase Functions runtime (${nodeVersion}).`);
|
|
}
|
|
const functionsPackageJsonPath = path_1.join(functionsOut, 'package.json');
|
|
fsHost.writeFileSync(functionsPackageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
if (options.CF3v2) {
|
|
fsHost.writeFileSync(path_1.join(functionsOut, 'index.js'), functions_templates_1.functionGen2(serverBuildOptions.outputPath, options, functionName));
|
|
}
|
|
else {
|
|
fsHost.writeFileSync(path_1.join(functionsOut, 'index.js'), functions_templates_1.defaultFunction(serverBuildOptions.outputPath, options, functionName));
|
|
}
|
|
if (!options.prerender) {
|
|
try {
|
|
fsHost.renameSync(path_1.join(newStaticOut, 'index.html'), path_1.join(newStaticOut, 'index.original.html'));
|
|
}
|
|
catch (e) { }
|
|
}
|
|
const siteTarget = (_b = options.target) !== null && _b !== void 0 ? _b : context.target.project;
|
|
if (fsHost.existsSync(functionsPackageJsonPath)) {
|
|
child_process_1.execSync(`npm --prefix ${functionsOut} install`);
|
|
}
|
|
else {
|
|
console.error(`No package.json exists at ${functionsOut}`);
|
|
}
|
|
if (options.preview) {
|
|
yield firebaseTools.serve({
|
|
port: DEFAULT_EMULATOR_PORT,
|
|
host: DEFAULT_EMULATOR_HOST,
|
|
targets: [`hosting:${siteTarget}`, `functions:${functionName}`],
|
|
nonInteractive: true,
|
|
projectRoot: workspaceRoot,
|
|
});
|
|
const { deployProject } = yield inquirer.prompt({
|
|
type: 'confirm',
|
|
name: 'deployProject',
|
|
message: 'Would you like to deploy your application to Firebase Hosting & Cloud Functions?'
|
|
});
|
|
if (!deployProject) {
|
|
return;
|
|
}
|
|
}
|
|
return yield firebaseTools.deploy({
|
|
only: `hosting:${siteTarget},functions:${functionName}`,
|
|
cwd: workspaceRoot,
|
|
token: firebaseToken,
|
|
nonInteractive: true,
|
|
projectRoot: workspaceRoot,
|
|
});
|
|
});
|
|
exports.deployToFunction = deployToFunction;
|
|
const deployToCloudRun = (firebaseTools, context, workspaceRoot, staticBuildTarget, serverBuildTarget, options, firebaseToken, fsHost = defaultFsHost) => __awaiter(void 0, void 0, void 0, function* () {
|
|
var _c;
|
|
const staticBuildOptions = yield context.getTargetOptions(architect_1.targetFromTargetString(staticBuildTarget.name));
|
|
if (!staticBuildOptions.outputPath || typeof staticBuildOptions.outputPath !== 'string') {
|
|
throw new Error(`Cannot read the output path option of the Angular project '${staticBuildTarget.name}' in angular.json`);
|
|
}
|
|
const serverBuildOptions = yield context.getTargetOptions(architect_1.targetFromTargetString(serverBuildTarget.name));
|
|
if (!serverBuildOptions.outputPath || typeof serverBuildOptions.outputPath !== 'string') {
|
|
throw new Error(`Cannot read the output path option of the Angular project '${serverBuildTarget.name}' in angular.json`);
|
|
}
|
|
const staticOut = path_1.join(workspaceRoot, staticBuildOptions.outputPath);
|
|
const serverOut = path_1.join(workspaceRoot, serverBuildOptions.outputPath);
|
|
const cloudRunOut = options.outputPath ? path_1.join(workspaceRoot, options.outputPath) : path_1.join(path_1.dirname(serverOut), 'run');
|
|
const serviceId = options.functionName || functions_templates_1.DEFAULT_FUNCTION_NAME;
|
|
const newStaticOut = path_1.join(cloudRunOut, staticBuildOptions.outputPath);
|
|
const newServerOut = path_1.join(cloudRunOut, serverBuildOptions.outputPath);
|
|
fsHost.removeSync(cloudRunOut);
|
|
fsHost.copySync(staticOut, newStaticOut);
|
|
fsHost.copySync(serverOut, newServerOut);
|
|
const packageJson = getPackageJson(context, workspaceRoot, options, path_1.join(serverBuildOptions.outputPath, 'main.js'));
|
|
const nodeVersion = packageJson.engines.node;
|
|
if (!semver_1.satisfies(process.versions.node, nodeVersion.toString())) {
|
|
context.logger.warn(`⚠️ Your Node.js version (${process.versions.node}) does not match the Cloud Run runtime (${nodeVersion}).`);
|
|
}
|
|
fsHost.writeFileSync(path_1.join(cloudRunOut, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
fsHost.writeFileSync(path_1.join(cloudRunOut, 'Dockerfile'), functions_templates_1.dockerfile(options));
|
|
if (!options.prerender) {
|
|
try {
|
|
fsHost.renameSync(path_1.join(newStaticOut, 'index.html'), path_1.join(newStaticOut, 'index.original.html'));
|
|
}
|
|
catch (e) { }
|
|
}
|
|
if (options.preview) {
|
|
throw new schematics_1.SchematicsException('Cloud Run preview not supported.');
|
|
}
|
|
const deployArguments = [];
|
|
const cloudRunOptions = options.cloudRunOptions || {};
|
|
Object.entries(DEFAULT_CLOUD_RUN_OPTIONS).forEach(([k, v]) => {
|
|
cloudRunOptions[k] || (cloudRunOptions[k] = v);
|
|
});
|
|
if (cloudRunOptions.cpus) {
|
|
deployArguments.push('--cpu', cloudRunOptions.cpus);
|
|
}
|
|
if (cloudRunOptions.maxConcurrency) {
|
|
deployArguments.push('--concurrency', cloudRunOptions.maxConcurrency);
|
|
}
|
|
if (cloudRunOptions.maxInstances) {
|
|
deployArguments.push('--max-instances', cloudRunOptions.maxInstances);
|
|
}
|
|
if (cloudRunOptions.memory) {
|
|
deployArguments.push('--memory', cloudRunOptions.memory);
|
|
}
|
|
if (cloudRunOptions.minInstances) {
|
|
deployArguments.push('--min-instances', cloudRunOptions.minInstances);
|
|
}
|
|
if (cloudRunOptions.timeout) {
|
|
deployArguments.push('--timeout', cloudRunOptions.timeout);
|
|
}
|
|
if (cloudRunOptions.vpcConnector) {
|
|
deployArguments.push('--vpc-connector', cloudRunOptions.vpcConnector);
|
|
}
|
|
context.logger.info(`📦 Deploying to Cloud Run`);
|
|
yield spawnAsync(`gcloud builds submit ${cloudRunOut} --tag gcr.io/${options.firebaseProject}/${serviceId} --project ${options.firebaseProject} --quiet`);
|
|
yield spawnAsync(`gcloud run deploy ${serviceId} --image gcr.io/${options.firebaseProject}/${serviceId} --project ${options.firebaseProject} ${deployArguments.join(' ')} --platform managed --allow-unauthenticated --region=${options.region} --quiet`);
|
|
const siteTarget = (_c = options.target) !== null && _c !== void 0 ? _c : context.target.project;
|
|
return yield firebaseTools.deploy({
|
|
only: `hosting:${siteTarget}`,
|
|
cwd: workspaceRoot,
|
|
token: firebaseToken,
|
|
nonInteractive: true,
|
|
projectRoot: workspaceRoot,
|
|
});
|
|
});
|
|
exports.deployToCloudRun = deployToCloudRun;
|
|
function deploy(firebaseTools, context, staticBuildTarget, serverBuildTarget, prerenderBuildTarget, firebaseProject, options, firebaseToken) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
if (!firebaseToken) {
|
|
yield firebaseTools.login();
|
|
const user = yield firebaseTools.login({ projectRoot: context.workspaceRoot });
|
|
console.log(`Logged into Firebase as ${user.email}.`);
|
|
}
|
|
if (options.version && options.version >= 2) {
|
|
if (semver_1.lt(firebaseTools.cli.version(), '12.2.0')) {
|
|
throw new schematics_1.SchematicsException('firebase-tools version 12.2+ is required.');
|
|
}
|
|
process.env.FIREBASE_FRAMEWORK_BUILD_TARGET = (prerenderBuildTarget || serverBuildTarget || staticBuildTarget).name;
|
|
}
|
|
else {
|
|
if (prerenderBuildTarget) {
|
|
const run = yield context.scheduleTarget(architect_1.targetFromTargetString(prerenderBuildTarget.name), prerenderBuildTarget.options);
|
|
yield run.result;
|
|
}
|
|
else {
|
|
if (!context.target) {
|
|
throw new Error('Cannot execute the build target');
|
|
}
|
|
context.logger.info(`📦 Building "${context.target.project}"`);
|
|
const builders = [
|
|
context.scheduleTarget(architect_1.targetFromTargetString(staticBuildTarget.name), staticBuildTarget.options).then(run => run.result)
|
|
];
|
|
if (serverBuildTarget) {
|
|
builders.push(context.scheduleTarget(architect_1.targetFromTargetString(serverBuildTarget.name), serverBuildTarget.options).then(run => run.result));
|
|
}
|
|
yield Promise.all(builders);
|
|
}
|
|
}
|
|
try {
|
|
yield firebaseTools.use(firebaseProject, {
|
|
project: firebaseProject,
|
|
projectRoot: context.workspaceRoot,
|
|
});
|
|
}
|
|
catch (e) {
|
|
throw new Error(`Cannot select firebase project '${firebaseProject}'`);
|
|
}
|
|
options.firebaseProject = firebaseProject;
|
|
const logger = new winston.transports.Console({
|
|
level: 'info',
|
|
format: winston.format.printf((info) => {
|
|
var _a, _b, _c, _d;
|
|
const emulator = (_c = (_b = (_a = info[triple_beam_1.default.SPLAT]) === null || _a === void 0 ? void 0 : _a[1]) === null || _b === void 0 ? void 0 : _b.metadata) === null || _c === void 0 ? void 0 : _c.emulator;
|
|
const text = (_d = info[triple_beam_1.default.SPLAT]) === null || _d === void 0 ? void 0 : _d[0];
|
|
if (text === null || text === void 0 ? void 0 : text.replace) {
|
|
const plainText = text.replace(/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]/g, '');
|
|
if ((emulator === null || emulator === void 0 ? void 0 : emulator.name) === 'hosting' && plainText.startsWith('Local server: ')) {
|
|
open_1.default(plainText.split(': ')[1]);
|
|
}
|
|
}
|
|
return [info.message, ...(info[triple_beam_1.default.SPLAT] || [])]
|
|
.filter((chunk) => typeof chunk === 'string')
|
|
.join(' ');
|
|
})
|
|
});
|
|
firebaseTools.logger.logger.add(logger);
|
|
if ((!options.version || options.version < 2) && serverBuildTarget) {
|
|
if (options.ssr === 'cloud-run') {
|
|
yield exports.deployToCloudRun(firebaseTools, context, context.workspaceRoot, staticBuildTarget, serverBuildTarget, options, firebaseToken);
|
|
}
|
|
else {
|
|
yield exports.deployToFunction(firebaseTools, context, context.workspaceRoot, staticBuildTarget, serverBuildTarget, options, firebaseToken);
|
|
}
|
|
}
|
|
else {
|
|
yield deployToHosting(firebaseTools, context, context.workspaceRoot, options, firebaseToken);
|
|
}
|
|
});
|
|
}
|
|
exports.default = deploy;
|