nativescript
Version:
Command-line interface for building NativeScript projects
640 lines • 33.2 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BundlerCompilerService = void 0;
const path = require("path");
const semver = require("semver");
const _ = require("lodash");
const events_1 = require("events");
const decorators_1 = require("../../common/decorators");
const constants_1 = require("../../constants");
const yok_1 = require("../../common/yok");
const package_path_helper_1 = require("../../helpers/package-path-helper");
/* for specific bundling debugging separate from logger */
const debugLog = false;
class BundlerCompilerService extends events_1.EventEmitter {
constructor($options, $errors, $childProcess, $fs, $hooksService, $hostInfo, $logger, $mobileHelper, $cleanupService, $packageManager, $packageInstallationManager, // private $sharedEventBus: ISharedEventBus
$projectConfigService) {
super();
this.$options = $options;
this.$errors = $errors;
this.$childProcess = $childProcess;
this.$fs = $fs;
this.$hooksService = $hooksService;
this.$hostInfo = $hostInfo;
this.$logger = $logger;
this.$mobileHelper = $mobileHelper;
this.$cleanupService = $cleanupService;
this.$packageManager = $packageManager;
this.$packageInstallationManager = $packageInstallationManager;
this.$projectConfigService = $projectConfigService;
this.bundlerProcesses = {};
this.expectedHashes = {};
}
async compileWithWatch(platformData, projectData, prepareData) {
return new Promise(async (resolve, reject) => {
if (this.bundlerProcesses[platformData.platformNameLowerCase]) {
resolve(void 0);
return;
}
let isFirstBundlerWatchCompilation = true;
prepareData.watch = true;
try {
const childProcess = await this.startBundleProcess(platformData, projectData, prepareData);
// Handle Vite differently from webpack
const isVite = this.getBundler() === "vite";
childProcess.stdout.on("data", function (data) {
process.stdout.write(data);
});
childProcess.stderr.on("data", function (data) {
process.stderr.write(data);
});
// For both Vite and webpack, we wait for the first build to complete
// Don't resolve immediately for Vite - wait for first IPC message
childProcess.on("message", (message) => {
this.$logger.trace(`Message from ${projectData.bundler}`, message);
// Handle Vite messages
if (isVite &&
message &&
message.emittedFiles) {
message = message;
if (debugLog) {
console.log("Received Vite IPC message:", message);
}
// Copy Vite output files directly to platform destination
const distOutput = path.join(projectData.projectDir, ".ns-vite-build");
const destDir = path.join(platformData.appDestinationDirectoryPath, this.$options.hostProjectModuleName);
if (debugLog) {
console.log(`Copying from ${distOutput} to ${destDir}.`);
}
// Determine which files to copy based on build type and changes
if (message.buildType === "incremental" &&
message.emittedFiles &&
message.emittedFiles.length > 0) {
// Incremental builds: only copy files that are likely affected by the changes
const filesToCopy = this.getIncrementalFilesToCopy(message.emittedFiles);
if (debugLog) {
console.log("Incremental build - files to copy:", filesToCopy);
}
this.copyViteBundleToNative(distOutput, destDir, filesToCopy);
}
else {
if (debugLog) {
console.log("Full build - copying all files.");
}
this.copyViteBundleToNative(distOutput, destDir);
}
// Resolve the promise on first build completion
if (isFirstBundlerWatchCompilation) {
isFirstBundlerWatchCompilation = false;
if (debugLog) {
console.log("Vite first build completed, resolving compileWithWatch");
}
resolve(childProcess);
}
// Transform Vite message to match webpack format
const files = message.emittedFiles.map((file) => path.join(platformData.appDestinationDirectoryPath, this.$options.hostProjectModuleName, file));
const data = {
files,
hasOnlyHotUpdateFiles: message.isHMR || false,
hmrData: {
hash: message.hash || "",
fallbackFiles: [],
},
platform: platformData.platformNameLowerCase,
};
this.$logger.info(`Vite build completed! Files copied to native platform.`);
if (debugLog) {
console.log("Emitting BUNDLER_COMPILATION_COMPLETE for full build.");
}
this.emit(constants_1.BUNDLER_COMPILATION_COMPLETE, data);
return;
}
// if we are on webpack5 - we handle HMR in a slightly different way
if (typeof message === "object" &&
"version" in message &&
"type" in message) {
// first compilation can be ignored because it will be synced regardless
// handling it here would trigger 2 syncs
if (isFirstBundlerWatchCompilation) {
isFirstBundlerWatchCompilation = false;
resolve(childProcess);
return;
}
// if ((message as IWebpackMessage).type === "hmr-status") {
// // we pass message through our event-bus to be handled wherever needed
// // in this case webpack-hmr-status-service listens for this event
// this.$sharedEventBus.emit("webpack:hmr-status", message);
// return;
// }
return this.handleHMRMessage(message, platformData, projectData, prepareData);
}
if (message ===
`${capitalizeFirstLetter(projectData.bundler)} compilation complete.`) {
this.$logger.info(`${capitalizeFirstLetter(projectData.bundler)} build done!`);
resolve(childProcess);
}
message = message;
if (message.emittedFiles) {
if (isFirstBundlerWatchCompilation) {
isFirstBundlerWatchCompilation = false;
this.expectedHashes[platformData.platformNameLowerCase] =
prepareData.hmr ? message.hash : "";
return;
}
// Persist the previousHash value before calling `this.getUpdatedEmittedFiles` as it will modify the expectedHashes object with the current hash
const previousHash = this.expectedHashes[platformData.platformNameLowerCase];
let result;
if (prepareData.hmr) {
result = this.getUpdatedEmittedFiles(message.emittedFiles, message.chunkFiles, message.hash, platformData.platformNameLowerCase);
}
else {
result = {
emittedFiles: message.emittedFiles,
fallbackFiles: [],
hash: "",
};
}
const files = result.emittedFiles.map((file) => path.join(platformData.appDestinationDirectoryPath, this.$options.hostProjectModuleName, file));
const fallbackFiles = result.fallbackFiles.map((file) => path.join(platformData.appDestinationDirectoryPath, this.$options.hostProjectModuleName, file));
const data = {
files,
hasOnlyHotUpdateFiles: files.every((f) => f.indexOf("hot-update") > -1),
hmrData: {
hash: result.hash,
fallbackFiles,
},
platform: platformData.platformNameLowerCase,
};
this.$logger.trace(`Generated data from ${projectData.bundler} message:`, data);
// the hash of the compilation is the same as the previous one and there are only hot updates produced
if (data.hasOnlyHotUpdateFiles && previousHash === message.hash) {
return;
}
if (data.files.length) {
this.emit(constants_1.BUNDLER_COMPILATION_COMPLETE, data);
}
}
});
childProcess.on("error", (err) => {
this.$logger.trace(`Unable to start ${projectData.bundler} process in watch mode. Error is: ${err}`);
delete this.bundlerProcesses[platformData.platformNameLowerCase];
reject(err);
});
childProcess.on("close", async (arg) => {
const exitCode = typeof arg === "number" ? arg : arg && arg.code;
this.$logger.trace(`${capitalizeFirstLetter(projectData.bundler)} process exited with code ${exitCode} when we expected it to be long living with watch.`);
await this.$cleanupService.removeKillProcess(childProcess.pid.toString());
const error = new Error(`Executing ${projectData.bundler} failed with exit code ${exitCode}.`);
error.code = exitCode;
delete this.bundlerProcesses[platformData.platformNameLowerCase];
reject(error);
});
}
catch (err) {
reject(err);
}
});
}
async compileWithoutWatch(platformData, projectData, prepareData) {
return new Promise(async (resolve, reject) => {
if (this.bundlerProcesses[platformData.platformNameLowerCase]) {
resolve();
return;
}
try {
const childProcess = await this.startBundleProcess(platformData, projectData, prepareData);
childProcess.on("error", (err) => {
this.$logger.trace(`Unable to start ${projectData.bundler} process in non-watch mode. Error is: ${err}`);
delete this.bundlerProcesses[platformData.platformNameLowerCase];
reject(err);
});
childProcess.on("close", async (arg) => {
await this.$cleanupService.removeKillProcess(childProcess.pid.toString());
delete this.bundlerProcesses[platformData.platformNameLowerCase];
const exitCode = typeof arg === "number" ? arg : arg && arg.code;
if (exitCode === 0) {
resolve();
}
else {
const error = new Error(`Executing ${projectData.bundler} failed with exit code ${exitCode}.`);
error.code = exitCode;
reject(error);
}
});
}
catch (err) {
reject(err);
}
});
}
async stopBundlerCompiler(platform) {
if (platform) {
await this.stopBundlerForPlatform(platform);
}
else {
const bundlerPlatforms = Object.keys(this.bundlerProcesses);
for (let i = 0; i < bundlerPlatforms.length; i++) {
await this.stopBundlerForPlatform(bundlerPlatforms[i]);
}
}
}
async shouldUsePreserveSymlinksOption() {
// pnpm does not require symlink (https://github.com/nodejs/node-eps/issues/46#issuecomment-277373566)
// and it also does not work in some cases.
// Check https://github.com/NativeScript/nativescript-cli/issues/5259 for more information
const currentPackageManager = await this.$packageManager.getPackageManagerName();
const res = currentPackageManager !== constants_1.PackageManagers.pnpm;
return res;
}
async startBundleProcess(platformData, projectData, prepareData) {
if (projectData.bundlerConfigPath) {
if (!this.$fs.exists(projectData.bundlerConfigPath)) {
this.$errors.fail(`The bundler configuration file ${projectData.bundlerConfigPath} does not exist. Ensure the file exists, or update the path in ${constants_1.CONFIG_FILE_NAME_DISPLAY}.`);
}
}
else {
if (!this.$fs.exists(projectData.bundlerConfigPath)) {
this.$errors.fail(`The ${projectData.bundler} configuration file ${projectData.bundlerConfigPath} does not exist. Ensure the file exists, or update the path in ${constants_1.CONFIG_FILE_NAME_DISPLAY}.`);
}
}
const envData = this.buildEnvData(platformData.platformNameLowerCase, projectData, prepareData);
const isVite = this.getBundler() === "vite";
const cliArgs = await this.buildEnvCommandLineParams(envData, platformData, projectData, prepareData);
// Note: With Vite, we need `--` to prevent vite cli from erroring on unknown options.
const envParams = isVite
? [
`--mode=${prepareData.release ? "production" : "development"}`,
`--watch`,
"--",
...cliArgs,
]
: cliArgs;
const additionalNodeArgs = semver.major(process.version) <= 8 ? ["--harmony"] : [];
if (await this.shouldUsePreserveSymlinksOption()) {
additionalNodeArgs.push("--preserve-symlinks");
}
if (process.arch === "x64") {
additionalNodeArgs.unshift("--max_old_space_size=4096");
}
const args = [
...additionalNodeArgs,
this.getBundlerExecutablePath(projectData),
isVite || this.isModernBundler(projectData) ? "build" : null,
`--config=${projectData.bundlerConfigPath}`,
...envParams,
].filter(Boolean);
if (!isVite) {
if (prepareData.watch) {
args.push("--watch");
}
}
const stdio = prepareData.watch || isVite ? ["ipc"] : "inherit";
const options = {
cwd: projectData.projectDir,
stdio,
};
options.env = {
...process.env,
NATIVESCRIPT_WEBPACK_ENV: JSON.stringify(envData),
NATIVESCRIPT_BUNDLER_ENV: JSON.stringify(envData),
};
if (this.$hostInfo.isWindows) {
Object.assign(options.env, { APPDATA: process.env.appData });
}
if (this.$options.hostProjectPath) {
Object.assign(options.env, {
USER_PROJECT_PLATFORMS_ANDROID: this.$options.hostProjectPath,
USER_PROJECT_PLATFORMS_ANDROID_MODULE: this.$options.hostProjectModuleName,
USER_PROJECT_PLATFORMS_IOS: this.$options.hostProjectPath,
});
}
if (debugLog) {
console.log("args:", args);
}
const childProcess = this.$childProcess.spawn(process.execPath, args, options);
this.bundlerProcesses[platformData.platformNameLowerCase] = childProcess;
await this.$cleanupService.addKillProcess(childProcess.pid.toString());
return childProcess;
}
buildEnvData(platform, projectData, prepareData) {
var _a, _b, _c;
const { env } = prepareData;
const envData = Object.assign({}, env, { [platform.toLowerCase()]: true });
const appId = projectData.projectIdentifiers[platform];
const appPath = projectData.getAppDirectoryRelativePath();
const appResourcesPath = projectData.getAppResourcesRelativeDirectoryPath();
Object.assign(envData, appId && { appId }, appPath && { appPath }, appResourcesPath && { appResourcesPath }, {
nativescriptLibPath: path.resolve(__dirname, "..", "..", "nativescript-cli-lib.js"),
});
envData.verbose = envData.verbose || this.$logger.isVerbose();
envData.production = envData.production || prepareData.release;
// add the config file name to the env data so the webpack process can read the
// correct config file when resolving the CLI lib and the config service
// we are explicitly setting it to false to force using the defaults
envData.config =
(_b = (_a = process.env.NATIVESCRIPT_CONFIG_NAME) !== null && _a !== void 0 ? _a : this.$options.config) !== null && _b !== void 0 ? _b : "false";
// explicitly set the env variable
process.env.NATIVESCRIPT_CONFIG_NAME = envData.config;
// The snapshot generation is wrongly located in the Webpack plugin.
// It should be moved in the Native Prepare of the CLI or a Gradle task in the Runtime.
// As a workaround, we skip the mksnapshot, xxd and android-ndk calls based on skipNativePrepare.
// In this way the plugin will prepare only the snapshot JS entry without any native prepare and
// we will able to execute cloud builds with snapshot without having any local snapshot or Docker setup.
// TODO: Remove this flag when we remove the native part from the plugin.
envData.skipSnapshotTools =
prepareData.nativePrepare && prepareData.nativePrepare.skipNativePrepare;
// only set sourceMap if not explicitly set through a flag
if (typeof ((_c = prepareData === null || prepareData === void 0 ? void 0 : prepareData.env) === null || _c === void 0 ? void 0 : _c.sourceMap) === "undefined") {
if (!prepareData.release) {
envData.sourceMap = true;
}
}
// convert string to boolean
if (envData.sourceMap === "true" || envData.sourceMap === "false") {
envData.sourceMap = envData.sourceMap === "true";
}
if (prepareData.uniqueBundle > 0) {
envData.uniqueBundle = prepareData.uniqueBundle;
}
return envData;
}
async buildEnvCommandLineParams(envData, platformData, projectData, prepareData) {
const envFlagNames = Object.keys(envData);
const canSnapshot = prepareData.release &&
this.$mobileHelper.isAndroidPlatform(platformData.normalizedPlatformName);
if (envData && envData.snapshot) {
if (!canSnapshot) {
this.$logger.warn("Stripping the snapshot flag. " +
"Bear in mind that snapshot is only available in Android release builds.");
envFlagNames.splice(envFlagNames.indexOf("snapshot"), 1);
}
else if (this.$hostInfo.isWindows) {
if (projectData.bundler === "webpack") {
//TODO: check this use case for webpack5 WEBPACK_PLUGIN_NAME
const minWebpackPluginWithWinSnapshotsVersion = "1.3.0";
const installedWebpackPluginVersion = await this.$packageInstallationManager.getInstalledDependencyVersion(constants_1.WEBPACK_PLUGIN_NAME, projectData.projectDir);
const hasWebpackPluginWithWinSnapshotsSupport = !!installedWebpackPluginVersion
? semver.gte(semver.coerce(installedWebpackPluginVersion), minWebpackPluginWithWinSnapshotsVersion)
: true;
if (!hasWebpackPluginWithWinSnapshotsSupport) {
this.$errors.fail(`In order to generate Snapshots on Windows, please upgrade your Webpack plugin version (npm i ${constants_1.WEBPACK_PLUGIN_NAME}).`);
}
}
}
}
const args = [];
envFlagNames.map((item) => {
let envValue = envData[item];
if (typeof envValue === "undefined") {
return;
}
if (typeof envValue === "boolean") {
if (envValue) {
args.push(`--env.${item}`);
}
}
else {
if (!Array.isArray(envValue)) {
envValue = [envValue];
}
envValue.map((value) => args.push(`--env.${item}=${value}`));
}
});
return args;
}
getUpdatedEmittedFiles(allEmittedFiles, chunkFiles, nextHash, platform) {
const currentHash = this.getCurrentHotUpdateHash(allEmittedFiles);
// This logic is needed as there are already cases when webpack doesn't emit any files physically.
// We've set noEmitOnErrors in webpack.config.js based on noEmitOnError from tsconfig.json,
// so webpack doesn't emit any files when noEmitOnErrors: true is set in webpack.config.js and
// there is a compilation error in the source code. On the other side, hmr generates new hot-update files
// on every change and the hash of the next hmr update is written inside hot-update.json file.
// Although webpack doesn't emit any files, hmr hash is still generated. The hash is generated per compilation no matter
// if files will be emitted or not. This way, the first successful compilation after fixing the compilation error generates
// a hash that is not the same as the one expected in the latest emitted hot-update.json file.
// As a result, the hmr chain is broken and the changes are not applied.
const isHashValid = nextHash
? this.expectedHashes[platform] === currentHash
: true;
this.expectedHashes[platform] = nextHash;
const emittedHotUpdatesAndAssets = isHashValid
? _.difference(allEmittedFiles, chunkFiles)
: allEmittedFiles;
const fallbackFiles = chunkFiles.concat(emittedHotUpdatesAndAssets.filter((f) => f.indexOf("hot-update") === -1));
return {
emittedFiles: emittedHotUpdatesAndAssets,
fallbackFiles,
hash: currentHash,
};
}
getCurrentHotUpdateHash(emittedFiles) {
let hotHash;
const hotUpdateScripts = emittedFiles.filter((x) => x.endsWith(".hot-update.js"));
if (hotUpdateScripts && hotUpdateScripts.length) {
// the hash is the same for each hot update in the current compilation
const hotUpdateName = hotUpdateScripts[0];
const matcher = /^(.+)\.(.+)\.hot-update/gm;
const matches = matcher.exec(hotUpdateName);
hotHash = matches[2];
}
return hotHash || "";
}
async stopBundlerForPlatform(platform) {
this.$logger.trace(`Stopping ${this.getBundler()} watch for platform ${platform}.`);
const bundlerProcess = this.bundlerProcesses[platform];
await this.$cleanupService.removeKillProcess(bundlerProcess.pid.toString());
if (bundlerProcess) {
bundlerProcess.kill("SIGINT");
delete this.bundlerProcesses[platform];
}
}
handleHMRMessage(message, platformData, projectData, prepareData) {
// handle new bundler hmr packets
this.$logger.trace(`Received message from ${projectData.bundler} process:`, message);
if (message.type !== "compilation") {
return;
}
this.$logger.trace(`${capitalizeFirstLetter(projectData.bundler)} build done!`);
const files = message.data.emittedAssets.map((asset) => path.join(platformData.appDestinationDirectoryPath, this.$options.hostProjectModuleName, asset));
const staleFiles = message.data.staleAssets.map((asset) => path.join(platformData.appDestinationDirectoryPath, this.$options.hostProjectModuleName, asset));
// extract last hash from emitted filenames
const lastHash = (() => {
const absoluteFileNameWithLastHash = files.find((fileName) => fileName.endsWith("hot-update.js"));
if (!absoluteFileNameWithLastHash) {
return null;
}
const fileNameWithLastHash = path.basename(absoluteFileNameWithLastHash);
const matches = fileNameWithLastHash.match(/\.(.+).hot-update\.js/);
if (matches) {
return matches[1];
}
})();
if (!files.length) {
// ignore compilations if no new files are emitted
return;
}
this.emit(constants_1.BUNDLER_COMPILATION_COMPLETE, {
files,
staleFiles,
hasOnlyHotUpdateFiles: prepareData.hmr,
hmrData: {
hash: lastHash || message.hash,
fallbackFiles: [],
},
platform: platformData.platformNameLowerCase,
});
}
getBundlerExecutablePath(projectData) {
const bundler = this.getBundler();
if (bundler === "vite") {
const packagePath = (0, package_path_helper_1.resolvePackagePath)(`vite`, {
paths: [projectData.projectDir],
});
if (packagePath) {
return path.resolve(packagePath, "bin", "vite.js");
}
}
else if (this.isModernBundler(projectData)) {
const packagePath = (0, package_path_helper_1.resolvePackagePath)(`/${bundler}`, {
paths: [projectData.projectDir],
});
if (packagePath) {
return path.resolve(packagePath, "dist", "bin", "index.js");
}
}
const packagePath = (0, package_path_helper_1.resolvePackagePath)("webpack", {
paths: [projectData.projectDir],
});
if (!packagePath) {
return "";
}
return path.resolve(packagePath, "bin", "webpack.js");
}
isModernBundler(projectData) {
const bundler = this.getBundler();
switch (bundler) {
case "rspack":
return true;
default:
const packageJSONPath = (0, package_path_helper_1.resolvePackageJSONPath)(constants_1.WEBPACK_PLUGIN_NAME, {
paths: [projectData.projectDir],
});
if (packageJSONPath) {
const packageData = this.$fs.readJson(packageJSONPath);
const ver = semver.coerce(packageData.version);
if (semver.satisfies(ver, ">= 5.0.0")) {
return true;
}
}
break;
}
return false;
}
getBundler() {
return this.$projectConfigService.getValue(`bundler`, "webpack");
}
copyViteBundleToNative(distOutput, destDir, specificFiles = null) {
// Clean and copy Vite output to native platform folder
if (debugLog) {
console.log(`Copying Vite bundle from "${distOutput}" to "${destDir}".`);
}
try {
if (specificFiles) {
// Selective mode: only copy specific files (incremental)
if (debugLog) {
console.log("Selective copy - copying specific files:", specificFiles);
}
// Ensure destination directory exists
this.$fs.createDirectory(destDir);
// Copy only the specified files
for (const file of specificFiles) {
const srcPath = path.join(distOutput, file);
const destPath = path.join(destDir, file);
if (!this.$fs.exists(srcPath))
continue;
// create parent dirs
this.$fs.createDirectory(path.dirname(destPath));
this.$fs.copyFile(srcPath, destPath);
if (debugLog) {
console.log(`Copied ${file}`);
}
}
}
else {
// Full build mode: clean and copy everything
if (debugLog) {
console.log("Full build: Copying all files.");
}
// Clean destination directory
if (this.$fs.exists(destDir)) {
this.$fs.deleteDirectory(destDir);
}
this.$fs.createDirectory(destDir);
// Copy all files from dist to platform destination
if (this.$fs.exists(distOutput)) {
this.copyRecursiveSync(distOutput, destDir);
}
else {
this.$logger.warn(`Vite output directory does not exist: ${distOutput}`);
}
}
}
catch (error) {
this.$logger.warn(`Failed to copy Vite bundle: ${error.message}`);
}
}
getIncrementalFilesToCopy(emittedFiles) {
// For incremental builds, we need to determine which emitted files are likely affected
// by the source file changes
const filesToCopy = [];
// default to ignoring vendor files as they are less likely to change during live reloads
const bundleFiles = emittedFiles.filter((file) => !file.includes("vendor") &&
(file.endsWith(".mjs") ||
file.endsWith(".js") ||
file.endsWith(".map")));
filesToCopy.push(...bundleFiles);
// Only copy assets if there are explicit asset-related changes
const assetFiles = emittedFiles.filter((file) => file.includes("assets/") ||
file.includes("static/") ||
file.includes("fonts/") ||
file.includes("images/"));
if (assetFiles.length > 0) {
filesToCopy.push(...assetFiles);
}
// Remove duplicates and return
return [...new Set(filesToCopy)];
}
copyRecursiveSync(src, dest) {
// Ensure destination exists
this.$fs.createDirectory(dest);
const entries = this.$fs.readDirectory(src);
for (const name of entries) {
const srcPath = path.join(src, name);
const destPath = path.join(dest, name);
const lstats = this.$fs.getLsStats(srcPath);
if (lstats.isDirectory()) {
this.copyRecursiveSync(srcPath, destPath);
}
else if (lstats.isFile() || lstats.isSymbolicLink()) {
// create parent directory (copyFile will also ensure it, but keep explicit)
this.$fs.createDirectory(path.dirname(destPath));
this.$fs.copyFile(srcPath, destPath);
}
}
}
}
exports.BundlerCompilerService = BundlerCompilerService;
__decorate([
(0, decorators_1.performanceLog)()
], BundlerCompilerService.prototype, "startBundleProcess", null);
function capitalizeFirstLetter(val) {
return String(val).charAt(0).toUpperCase() + String(val).slice(1);
}
yok_1.injector.register("bundlerCompilerService", BundlerCompilerService);
//# sourceMappingURL=bundler-compiler-service.js.map