UNPKG

@criticalmanufacturing/node-package-bundler

Version:
363 lines 20.3 kB
"use strict"; 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()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PackagePacker = void 0; /* eslint-disable no-useless-escape */ const inversify_config_1 = require("./inversify.config"); const io = require("fs-extra"); const path = require("path"); const os = require("node:os"); const unzipper = require("unzipper"); const configuration_1 = require("./models/configuration"); // eslint-disable-next-line @typescript-eslint/no-var-requires const ncc = require("@vercel/ncc"); const types_1 = require("./types"); class PackagePacker { go(options) { return __awaiter(this, void 0, void 0, function* () { var _a, _b; const source = options.i || options.input || process.cwd(); const destination = options.o || options.output || ""; let temp = options.t || options.temp || path.join(source, "__TEMP__"); const configurationFile = options.c || options.config || path.join(source, "packConfig.json"); let addons = options.a || options.addons; const version = options.v || options.version || ""; const debug = options.d || options.debug || false; this._logger = inversify_config_1.container.get(types_1.TYPES.Logger); this._operations = inversify_config_1.container.get(types_1.TYPES.Operations); const packageFile = path.join(path.dirname(__filename), "..", "package.json"); const packageContent = io.readJSONSync(packageFile); this._logger.notice(`** Using Package Bundler version '${packageContent.version}' **`); this._logger.notice(``); this._logger.debug(`Using the following settings:`); this._logger.debug(` Source : ${source}`); this._logger.debug(` Destination : ${destination}`); this._logger.debug(` Temporary : ${temp}`); this._logger.debug(` Configuration : ${configurationFile}`); this._logger.debug(` Addons : ${addons}`); this._logger.debug(` Version : ${version}`); this._logger.debug(` Debug Mode : ${debug}`); this._logger.debug(""); // Sanity checks if (!io.existsSync(source)) { this._logger.error(`Source directory '${source}' doesn't exist!`); process.exit(1); } if (!io.existsSync(configurationFile)) { this._logger.error(`Configuration file '${configurationFile}' doesn't exist!`); this._logger.error(`This package will not packed!`); process.exit(2); } const configuration = JSON.parse(io.readFileSync(configurationFile, "utf8")); // Only process addons if there are addons to process and if there is an arg for addons if (configuration.addons != null && addons != null && addons !== "") { addons = yield this.processAddOns(addons, source, configuration); if (!io.existsSync(addons)) { this._logger.error(`Addons location '${addons}' doesn't exist!`); process.exit(1); } } const paths = inversify_config_1.container.get(types_1.TYPES.Paths); paths.setup(source, destination, temp, addons); // Prepare temp Directory if (configuration.type === configuration_1.ComponentType.TasksPackage) { temp = io.readJSONSync(path.join(source, "ng-package.json")).dest; if (!io.existsSync(temp)) { this._logger.error(`'${temp}' doesn't exist! Did you forget to run 'ng build'?`); process.exit(1); } this._logger.warn(`Temporary directory changed to '${temp}'`); } else { this._operations.deleteDirectory(temp); this._operations.createDirectory(temp); } const main = (_a = io.readJSONSync(path.join(source, "package.json"))) === null || _a === void 0 ? void 0 : _a.main; const mainSplitted = main === null || main === void 0 ? void 0 : main.split("/"); const index = mainSplitted === null || mainSplitted === void 0 ? void 0 : mainSplitted[mainSplitted.length - 1]; mainSplitted === null || mainSplitted === void 0 ? void 0 : mainSplitted.pop(); const srcDirectory = (_b = mainSplitted === null || mainSplitted === void 0 ? void 0 : mainSplitted.join("/")) !== null && _b !== void 0 ? _b : "src"; // Pack package const packs = configuration.packs || []; if (packs.length === 0) { switch (configuration.type) { case configuration_1.ComponentType.TasksPackage: packs.push({ directory: srcDirectory, source: "public-api-runtime.js", destination: index, }); break; case configuration_1.ComponentType.BusinessScenario: break; default: packs.push({ directory: srcDirectory, source: index, destination: index, }); } } for (const pack of packs) { yield this.packPackage(path.join(source, pack.directory), pack.source || "index.js", temp, pack.destination || "index.js"); } if (configuration.type !== configuration_1.ComponentType.TasksPackage) { // Copy necessary files to generate package if (!io.existsSync("npm-shrinkwrap.json")) { this._logger.warn("npm-shrinkwrap.json file not found. Trying to generate it..."); inversify_config_1.container.get(types_1.TYPES.Processors.ShrinkwrapGenerator).process(source, "npm-shrinkwrap.json"); } this._operations.copyFile("npm-shrinkwrap.json", source, temp, true); this._operations.copyFile(".npmignore", source, temp, true); this._operations.copyFile(".npmrc", source, temp, true); this._operations.copyFile("README.md", source, temp); this._operations.copyFile("package.json", source, temp); // normalize package.json main const packageJSONTemp = io.readJSONSync(path.join(temp, "package.json")); packageJSONTemp.main = "src/index.js"; io.writeJSONSync(path.join(temp, "package.json"), packageJSONTemp); } if (configuration.type === configuration_1.ComponentType.TasksPackage) { this._operations.deleteFile(path.join(source, "src", "index.js")); } this._operations.setPackageJsonAsPacked(path.join(temp, "package.json")); if (version != null && version !== "") { this._operations.changePackageJsonVersion(path.join(temp, "package.json"), version); } // TasksPackages must have the dependencies for the GUI. All others, clear them if (configuration.type !== configuration_1.ComponentType.TasksPackage) { this._operations.removeDependenciesFromPackageJson(path.join(temp, "package.json")); } // Copy .node files (Addons) (configuration.addons || []).forEach((addon) => { const sourceAddonDir = path.join(/*mappedAddons ||*/ addons, addon.name, addon.version); const destinationAddonDir = path.join(temp, "addons", addon.name); this._operations.createDirectory(path.join(temp, "addons")); this._operations.createDirectory(destinationAddonDir); for (const addonFile of this.findByExtension(sourceAddonDir, addon.fileMask)) { this._operations.copyFile(addonFile, sourceAddonDir, destinationAddonDir); } }); // Process any template action if (configuration.templates != null) { const destinationTemplates = path.join(temp, "package.json"); switch (configuration.type) { case configuration_1.ComponentType.Component: inversify_config_1.container.get(types_1.TYPES.Processors.DriverTemplates).process(configuration.templates, destinationTemplates); break; case configuration_1.ComponentType.TasksPackage: case configuration_1.ComponentType.TasksLibrary: yield inversify_config_1.container.get(types_1.TYPES.Processors.LibraryTemplates).process(configuration.templates, destinationTemplates); break; } } // Process any business Scenarios if (configuration.businessScenarios != null) { const destinationBusinessScenarios = path.join(temp, "package.json"); switch (configuration.type) { case configuration_1.ComponentType.TasksPackage: case configuration_1.ComponentType.TasksLibrary: case configuration_1.ComponentType.BusinessScenario: yield inversify_config_1.container.get(types_1.TYPES.Processors.LibraryBusinessScenarios).process(configuration.businessScenarios, destinationBusinessScenarios); break; } } // Process any font action if (configuration.font != null) { const destinationFont = path.join(temp, "package.json"); if (configuration.type === configuration_1.ComponentType.TasksLibrary || configuration.type === configuration_1.ComponentType.TasksPackage) { inversify_config_1.container.get(types_1.TYPES.Processors.LibraryFontProcessor).process(configuration.font, destinationFont); } } // process Post actions (configuration.postActions || []).forEach((action) => { const actionSource = (action.source || "") .replace("${Source}", source) .replace("${Temp}", temp) .replace("${Destination}", destination) .replace("${Addons}", addons); const actionDestination = (action.destination || "") .replace("${Source}", source) .replace("${Temp}", temp) .replace("${Destination}", destination) .replace("${Addons}", addons); switch (action.type) { case configuration_1.ActionType.DeleteFile: this._operations.deleteFile(actionSource); break; case configuration_1.ActionType.DeleteDirectory: this._operations.deleteDirectory(actionSource); break; case configuration_1.ActionType.CopyDirectory: this._operations.copyDirectory(actionSource, actionDestination); break; case configuration_1.ActionType.CopyFile: this._operations.copyFile(action.file || "", actionSource, actionDestination); break; case configuration_1.ActionType.MoveFile: this._operations.moveFile(action.file || "", actionSource, actionDestination); break; case configuration_1.ActionType.RenameFile: this._operations.renameFile(actionSource, actionDestination); break; case configuration_1.ActionType.ReplaceText: this._operations.replaceTextInFile(actionSource, action.search || "", action.replace || "", action.isRegularExpression || false); break; } }); // Place index.js into src directory this._operations.createDirectory(path.join(temp, "src")); if (configuration.type === configuration_1.ComponentType.TasksPackage) { this._operations.moveFile("index.js", temp, path.join(temp, "src")); } else { for (const pack of packs) { // Fix issue with nconf // https://github.com/zeit/ncc/issues/451 ["argv", "env", "file", "literal", "memory"].forEach((toFix) => { this._operations.replaceTextInFile(path.join(temp, pack.destination || "index.js"), `arg === \"${toFix}.js\"`, `arg === \"${toFix}\"`, false); }); this._operations.moveFile(pack.destination || "index.js", temp, path.join(temp, "src")); } } // Create Package and place it in the destination if (destination !== "") { this._operations.createDirectory(destination); if (os.platform() === "win32") { this._operations.run("npm.cmd", ["pack"], temp); } else { this._operations.run("npm", ["pack"], temp); } for (const packedPackage of this.findByExtension(temp, "*.tgz")) { this._operations.moveFile(packedPackage, temp, destination); } } // Delete temp if (debug === false) { this._operations.deleteDirectory(temp); } else { this._logger.warn(`Directory '${temp}' was *NOT* deleted`); } this._logger.info(""); this._logger.success("** Finished **"); }); } /** * Retrieves a list of files that math a glob * @param searchPath Full path to search * @param extension Glob expression */ findByExtension(searchPath, extension, basePath) { if (extension.startsWith("*.")) { extension = extension.substring(1); } basePath = basePath !== null && basePath !== void 0 ? basePath : ""; const result = []; const files = io.readdirSync(searchPath); for (const file of files) { const filename = path.join(searchPath, file); const stat = io.lstatSync(filename); if (stat.isDirectory()) { result.push(...this.findByExtension(filename, extension, basePath + `/${path.basename(filename)}`)); } else if (filename.endsWith(extension) || extension === "*") { result.push(path.join(basePath, path.basename(filename))); } } return (result); } /** * Execute ncc over a selected file to bundle it * @param SourceDirectory Directory where the file is * @param sourceFile name of the file to bundle * @param destinationDirectory Destination where to save the result * @param destinationFile Name of the final bundled file */ packPackage(SourceDirectory, sourceFile, destinationDirectory, destinationFile) { return __awaiter(this, void 0, void 0, function* () { const nccInput = path.join(SourceDirectory, sourceFile); const nccOptions = { minify: false, sourceMap: false, sourceMapRegister: false, quiet: true }; const { code, assets } = yield ncc(nccInput, nccOptions); for (const [assetName, assetCode] of Object.entries(assets)) { const assetSize = Math.round(Buffer.byteLength(assetCode.source, "utf8") / 1024); this._operations.createFile(path.join(destinationDirectory, assetName), assetCode.source); this._logger.notice(`[PACKED ASSET] ${assetSize}Kb \t ${assetName} `); } // await this.sleep(5000); const codeSize = Math.round(Buffer.byteLength(code, "utf8") / 1024); // const mapSize = map ? Math.round(Buffer.byteLength(map, "utf8") / 1024) : 0; this._operations.createFile(path.join(destinationDirectory, destinationFile), code); this._logger.notice(`[PACK RESULT] ${codeSize}Kb \t ${destinationFile}`); }); } /** * Sleep for a moment before continuing to the next instruction * @param ms Number of milliseconds to sleep */ sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } /** * Treat addons entry. To validate, download, unzip and reajust addons location. * @param addons Addons location * @param source Where is the source location * @param configuration Configurations parsed from the packConfig */ processAddOns(addons, source, configuration) { return __awaiter(this, void 0, void 0, function* () { var _a; if (this._operations.isValidUrl(addons)) { const url = new URL(addons); const localAddons = path.join(source, "__ADDONS__"); let success = 0; if (configuration.addons != null && configuration.addons.length > 0) { this._operations.deleteDirectory(localAddons); this._operations.createDirectory(localAddons); } for (const addon of configuration.addons || []) { const packageName = `${addon.name}-${addon.version}.zip`; const destination = path.join(localAddons, `${addon.name}/${addon.version}/`); const downloadUrl = `${url.href}/${addon.name}/${packageName}`; this._logger.debug(`Downloading package: ${addon.name}-${addon.version} to ${destination} from ${downloadUrl}`); // Download the package const response = yield fetch(downloadUrl, { method: "GET", }); if (!response.ok || (response === null || response === void 0 ? void 0 : response.body) === null) { this._logger.error(`Failed to download package: ${response.statusText}`); process.exit(1); } // Convert the ReadableStream into a Stream const nodeStream = yield this._operations.readStreamToBuffer(response.body); // Unzip to the destination folder yield unzipper.Open.buffer(nodeStream) .then(d => d.extract({ path: destination, concurrency: 5 })); success += 1; } ; if (success === ((_a = configuration.addons) === null || _a === void 0 ? void 0 : _a.length)) { addons = localAddons; this._logger.debug(`Changed the default addon location to: ${addons}`); } else { this._operations.deleteDirectory(localAddons); this._logger.error(`Failed to download all the required addons from the nexus.`); process.exit(1); } } return addons; }); } } exports.PackagePacker = PackagePacker; //# sourceMappingURL=packagePacker.js.map