UNPKG

pcf-scripts

Version:

This package contains a module for building PowerApps Component Framework (PCF) controls. See project homepage how to install.

178 lines (176 loc) 8.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CompileTaskForWatch = exports.CompileTask = void 0; const fs = require("fs-extra"); const path = require("node:path"); const webpack_1 = require("webpack"); const constants = require("../constants"); const diagnosticMessages_generated_1 = require("../diagnosticMessages.generated"); const locale_1 = require("../generated/locale"); const pcfFileWatcher_1 = require("../pcfFileWatcher"); const webpackConfig_1 = require("../webpackConfig"); class CompileTask { constructor() { this._options = {}; } getDescription() { return (0, locale_1.translate)(diagnosticMessages_generated_1.strings.task_compile_and_bundle.key); } setOptions(options) { this._options = { ...this._options, ...options }; } run(context) { return this.runBuild(context, false); } runBuild(context, isWatch, maxBundleSizeInBytes) { if (context.shouldUseESBuild()) { if (maxBundleSizeInBytes) { this.addError(diagnosticMessages_generated_1.strings.esbuild_max_bundle_size_not_supported, context.getDiagnostic()); return Promise.reject(new Error(diagnosticMessages_generated_1.strings.esbuild_max_bundle_size_not_supported.message)); } return this.runESBuild(context, isWatch); } return this.runWebpackBuild(context, isWatch, maxBundleSizeInBytes); } runESBuild(context, isWatch) { const buildMode = context.getBuildMode(); const outDir = context.getOutDir(); if (!outDir) { context.getDiagnostic().push(diagnosticMessages_generated_1.strings.buildconfig_no_outdir); return Promise.reject(new Error()); } return context.mapControls(async (control) => { const esbuild = await Promise.resolve().then(() => require("esbuild")); const controlOutputDir = path.resolve(outDir, control.getControlFolderName()); const bundlePath = path.join(controlOutputDir, constants.BUNDLE_NAME); fs.ensureDirSync(controlOutputDir); if (isWatch) { // remove old errors, only needed when watching const diag = context.getDiagnostic(); diag.clear(); } // The link below points to the TS schema for ESBuild's BuildOptions object: // https://github.com/evanw/esbuild/blob/main/lib/shared/types.ts#L113 const globalName = constants.TEMP_NAMESPACE; const buildOptions = { entryPoints: [`./${control.getControlPath()}`], bundle: true, outfile: bundlePath, sourcemap: buildMode === "development", minify: buildMode === "production", write: true, treeShaking: true, globalName, loader: { [".svg"]: "dataurl", }, }; const build = await esbuild.build(buildOptions); const stub = (0, webpackConfig_1.generateStub)(control.getControlNamespace(), control.getControlName()); fs.appendFileSync(bundlePath, stub, "utf8"); return build; }); } runWebpackBuild(context, isWatch, maxBundleSizeInBytes) { const buildMode = context.getBuildMode(); const outDir = context.getOutDir(); if (!outDir) { context.getDiagnostic().push(diagnosticMessages_generated_1.strings.buildconfig_no_outdir); return Promise.reject(new Error()); } return context.mapControls((control) => { const controlOutputDir = path.resolve(outDir, control.getControlFolderName()); const config = (0, webpackConfig_1.getWebpackConfig)(control, controlOutputDir, buildMode, isWatch); const bundlePath = path.join(controlOutputDir, constants.BUNDLE_NAME); const bundleSizeInBytes = typeof maxBundleSizeInBytes === "number" && maxBundleSizeInBytes > 0 ? maxBundleSizeInBytes : constants.MAX_BUNDLE_SIZE_IN_MB * 1024 * 1024; fs.ensureDirSync(controlOutputDir); return new Promise((resolve, reject) => (0, webpack_1.webpack)(config, (error, stats) => { let colorize = false; let toReject = false; const diag = context.getDiagnostic(); if (this._options?.colorize) { colorize = true; } if (!isWatch || error || stats?.hasErrors()) { console.log(`[Webpack ${(0, locale_1.translate)(diagnosticMessages_generated_1.strings.statistics.key)}]:\n${stats?.toString({ chunks: false, colors: colorize })}`); } if (error) { this.addError(diagnosticMessages_generated_1.strings.build_error_generic, diag, error.message); toReject = true; } else if (stats?.hasErrors()) { this.addError(diagnosticMessages_generated_1.strings.bundling_error, diag); toReject = true; } else if (buildMode === "production") { let assets = stats?.toJson().assets; if (assets) { assets = assets.filter((obj) => obj.name === constants.BUNDLE_NAME); // webpack stats object uses byte as unit if (assets.length > 0 && assets[0].size > bundleSizeInBytes) { this.addError(diagnosticMessages_generated_1.strings.bundle_size_exceeds_max, diag, (bundleSizeInBytes / (1024 * 1024)).toString()); toReject = true; } } } if (!control.getControlManifest().getManifestData().manifest) { this.addError(diagnosticMessages_generated_1.strings.generating_stub_error, diag); toReject = true; } // If there are no other errors, check that the bundle file exists // If the bundle is missing even though webpack completed without errors, that could mean that the webpack config was misconfigured. if (!fs.existsSync(bundlePath) && !toReject) { this.addError(diagnosticMessages_generated_1.strings.bundle_not_found, diag, bundlePath); toReject = true; } if (toReject) { return reject(new Error(diagnosticMessages_generated_1.strings.bundling_error.message)); } if (isWatch) { diag.clear(); } // remove old errors, only needed when watching const stub = (0, webpackConfig_1.generateStub)(control.getControlNamespace(), control.getControlName()); fs.appendFileSync(bundlePath, stub, "utf8"); return resolve({ compileTime: stats?.toJson().time }); })); }); } // In watch mode: need to check for duplication of errors in case they were not fixed from last save addError(error, diag, errorMessage) { let lastEntry; let secondToLastEntry; if (diag.length() > 0) { lastEntry = diag.peek(); if (diag.length() > 1) { secondToLastEntry = diag.peek(diag.length() - 2); } } if (secondToLastEntry && lastEntry) { if (error.code !== secondToLastEntry.diag.code && error.code !== lastEntry.diag.code) { errorMessage ? diag.pushA(error, [errorMessage]) : diag.push(error); } } else if (lastEntry) { if (error.code !== lastEntry.diag.code) { errorMessage ? diag.pushA(error, [errorMessage]) : diag.push(error); } } else { errorMessage ? diag.pushA(error, [errorMessage]) : diag.push(error); } } } exports.CompileTask = CompileTask; class CompileTaskForWatch extends CompileTask { run(context) { return this.runBuild(context, false).then(() => { const fileWatcher = new pcfFileWatcher_1.PCFFileWatcher(); // eslint-disable-next-line @typescript-eslint/no-floating-promises fileWatcher.start(context); // eslint-disable-next-line @typescript-eslint/no-floating-promises this.runBuild(context, true); }); } } exports.CompileTaskForWatch = CompileTaskForWatch; //# sourceMappingURL=compileTask.js.map