1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16const fs = require('fs'); 17const path = require('path'); 18const cluster = require('cluster'); 19const process = require('process'); 20const crypto = require('crypto'); 21const events = require('events'); 22const os = require('os'); 23const childProcess = require('child_process'); 24 25const forward = '(global.___mainEntry___ = function (globalObjects) {' + '\n' + 26 ' var define = globalObjects.define;' + '\n' + 27 ' var require = globalObjects.require;' + '\n' + 28 ' var bootstrap = globalObjects.bootstrap;' + '\n' + 29 ' var register = globalObjects.register;' + '\n' + 30 ' var render = globalObjects.render;' + '\n' + 31 ' var $app_define$ = globalObjects.$app_define$;' + '\n' + 32 ' var $app_bootstrap$ = globalObjects.$app_bootstrap$;' + '\n' + 33 ' var $app_require$ = globalObjects.$app_require$;' + '\n' + 34 ' var history = globalObjects.history;' + '\n' + 35 ' var Image = globalObjects.Image;' + '\n' + 36 ' var OffscreenCanvas = globalObjects.OffscreenCanvas;' + '\n' + 37 ' (function(global) {' + '\n' + 38 ' "use strict";' + '\n'; 39const last = '\n' + '})(this.__appProto__);' + '\n' + '})'; 40const genAbcScript = 'gen-abc.js'; 41let output; 42let isWin = false; 43let isMac = false; 44let isDebug = false; 45let arkDir; 46let nodeJs; 47let intermediateJsBundle = []; 48let workerFile = null; 49let fileterIntermediateJsBundle = []; 50let hashJsonObject = {}; 51let buildPathInfo = ""; 52const SUCCESS = 0; 53const FAIL = 1; 54const red = '\u001b[31m'; 55const reset = '\u001b[39m'; 56const blue = '\u001b[34m'; 57const hashFile = 'gen_hash.json'; 58const ARK = '/ark/'; 59const NODE_MODULES = 'node_modules'; 60const TEMPORARY = 'temporary'; 61const TS2ABC = 'ts2abc'; 62const ES2ABC = 'es2abc'; 63const WINDOWS = 'Windows_NT'; 64const LINUX = 'Linux'; 65const MAC = 'Darwin'; 66const FILESINFO_TXT = 'filesInfo.txt'; 67const manageBunldeWorkersScript = 'manage-bundle-workers.js'; 68const PREBUILDINFO_JSON = 'preBuildInfo.json'; 69 70class GenAbcPlugin { 71 constructor(output_, arkDir_, nodeJs_, workerFile_, isDebug_) { 72 output = output_; 73 arkDir = arkDir_; 74 nodeJs = nodeJs_; 75 isDebug = isDebug_; 76 workerFile = workerFile_; 77 } 78 apply(compiler) { 79 if (fs.existsSync(path.resolve(arkDir, 'build-win'))) { 80 isWin = true; 81 } else if (fs.existsSync(path.resolve(arkDir, 'build-mac'))) { 82 isMac = true; 83 } else if (!fs.existsSync(path.resolve(arkDir, 'build'))) { 84 console.error(red, 'ERROR find build fail', reset); 85 process.exitCode = FAIL; 86 return; 87 } 88 89 if (!checkNodeModules()) { 90 process.exitCode = FAIL; 91 return; 92 } 93 94 // for preview mode max listeners 95 events.EventEmitter.defaultMaxListeners = 100; 96 97 compiler.hooks.emit.tap('GenAbcPlugin', (compilation) => { 98 const assets = compilation.assets; 99 const keys = Object.keys(assets); 100 buildPathInfo = output; 101 keys.forEach(key => { 102 // choice *.js 103 if (output && path.extname(key) === '.js') { 104 let newContent = assets[key].source(); 105 if (checkWorksFile(key, workerFile) && key !== 'commons.js' && key !== 'vendors.js') { 106 newContent = forward + newContent + last; 107 } 108 if (key === 'commons.js' || key === 'vendors.js' || !checkWorksFile(key, workerFile)) { 109 newContent = `\n\n\n\n\n\n\n\n\n\n\n\n\n\n` + newContent; 110 } 111 const keyPath = key.replace(/\.js$/, ".temp.js"); 112 writeFileSync(newContent, output, keyPath, key, true); 113 } else if (output && path.extname(key) === '.json' && 114 process.env.DEVICE_LEVEL === 'card' && process.env.configOutput && !checkI18n(key)) { 115 writeFileSync(assets[key].source(), output, key, key, false); 116 } 117 }) 118 }); 119 compiler.hooks.afterEmit.tap('GenAbcPluginMultiThread', () => { 120 if (intermediateJsBundle.length === 0) { 121 return; 122 } 123 buildPathInfo = output; 124 clearWebpackCacheByBuildInfo(); 125 setPrebuildInfo(); 126 processMultiThreadEntry(); 127 }); 128 } 129} 130 131function processMultiThreadEntry() { 132 if (isTs2Abc() || process.env.minPlatformVersion === "8") { 133 invokeWorkerToGenAbc(); 134 } else if (isEs2Abc()) { 135 generateAbcByEs2AbcOfBundleMode(intermediateJsBundle); 136 } else { 137 console.debug(red, `ERROR please set panda module`, reset); 138 } 139} 140 141function checkI18n(key) { 142 const outI18nPath = path.resolve(process.env.configOutput, key); 143 const projectI18nPath = outI18nPath.replace(output, process.env.projectPath); 144 if (projectI18nPath.indexOf( 145 path.resolve(__dirname, process.env.projectPath, 'i18n')) > -1) { 146 return true; 147 } 148 return false; 149} 150 151function checkWorksFile(assetPath, workerFile) { 152 if (workerFile === null) { 153 if (assetPath.search("./workers/") !== 0) { 154 return true; 155 } else { 156 return false; 157 } 158 } else { 159 for (const key in workerFile) { 160 let keyExt = key + '.js'; 161 if (keyExt === assetPath) { 162 return false; 163 } 164 } 165 } 166 167 return true; 168} 169 170function writeFileSync(inputString, buildPath, keyPath, jsBundleFile, isToBin) { 171 let output = path.resolve(buildPath, keyPath); 172 validateFilePathLength(output); 173 let parent = path.join(output, '..'); 174 if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) { 175 mkDir(parent); 176 } 177 if (!isToBin) { 178 fs.writeFileSync(output, inputString); 179 return; 180 } 181 let cacheOutputPath = ""; 182 if (process.env.cachePath) { 183 let buildDirArr = buildPathInfo.split(path.sep); 184 let abilityDir = buildDirArr[buildDirArr.length - 1]; 185 cacheOutputPath = path.join(process.env.cachePath, TEMPORARY, abilityDir, keyPath); 186 } else { 187 cacheOutputPath = output; 188 } 189 validateFilePathLength(cacheOutputPath); 190 parent = path.join(cacheOutputPath, '..'); 191 if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) { 192 mkDir(parent); 193 } 194 fs.writeFileSync(cacheOutputPath, inputString); 195 if (fs.existsSync(cacheOutputPath)) { 196 let fileSize = fs.statSync(cacheOutputPath).size; 197 output = toUnixPath(output); 198 cacheOutputPath = toUnixPath(cacheOutputPath); 199 intermediateJsBundle.push({path: output, size: fileSize, cacheOutputPath: cacheOutputPath}); 200 } else { 201 console.debug(red, `ERROR Failed to convert file ${jsBundleFile} to bin. ${output} is lost`, reset); 202 process.exitCode = FAIL; 203 } 204} 205 206function mkDir(path_) { 207 const parent = path.join(path_, '..'); 208 if (!(fs.existsSync(parent) && !fs.statSync(parent).isFile())) { 209 mkDir(parent); 210 } 211 fs.mkdirSync(path_); 212} 213 214function getSmallestSizeGroup(groupSize) { 215 let groupSizeArray = Array.from(groupSize); 216 groupSizeArray.sort(function(g1, g2) { 217 return g1[1] - g2[1]; // sort by size 218 }); 219 return groupSizeArray[0][0]; 220} 221 222function splitJsBundlesBySize(bundleArray, groupNumber) { 223 let result = []; 224 if (bundleArray.length < groupNumber) { 225 for (let value of bundleArray) { 226 result.push([value]); 227 } 228 return result; 229 } 230 231 bundleArray.sort(function(f1, f2) { 232 return f2.size - f1.size; 233 }); 234 let groupFileSize = new Map(); 235 for (let i = 0; i < groupNumber; ++i) { 236 result.push([]); 237 groupFileSize.set(i, 0); 238 } 239 240 let index = 0; 241 while(index < bundleArray.length) { 242 let smallestGroup = getSmallestSizeGroup(groupFileSize); 243 result[smallestGroup].push(bundleArray[index]); 244 let sizeUpdate = groupFileSize.get(smallestGroup) + bundleArray[index].size; 245 groupFileSize.set(smallestGroup, sizeUpdate); 246 index++; 247 } 248 return result; 249} 250 251function invokeWorkerToGenAbc() { 252 if (process.env.isPreview === "true") { 253 process.exitCode = SUCCESS; 254 } 255 let maxWorkerNumber = isEs2Abc() ? os.cpus().length : 3; 256 const abcArgs = initAbcEnv(); 257 let cmdPrefix = initCmdPrefix(abcArgs); 258 259 filterIntermediateJsBundleByHashJson(buildPathInfo, intermediateJsBundle); 260 const splitedBundles = splitJsBundlesBySize(fileterIntermediateJsBundle, maxWorkerNumber); 261 const workerNumber = maxWorkerNumber < splitedBundles.length ? maxWorkerNumber : splitedBundles.length; 262 263 try { 264 if (process.env.isPreview === 'true') { 265 processWorkersOfPreviewMode(splitedBundles, cmdPrefix, workerNumber); 266 } else { 267 processWorkersOfBuildMode(splitedBundles, cmdPrefix, workerNumber); 268 } 269 } catch (e) { 270 console.debug(red, `ERROR failed to generate abc. Error message: ${e} `, reset); 271 process.env.abcCompileSuccess = 'false'; 272 if (process.env.isPreview !== 'true') { 273 process.exit(FAIL); 274 } 275 } 276} 277 278function clearGlobalInfo() { 279 if (process.env.isPreview !== "true") { 280 intermediateJsBundle = []; 281 } 282 fileterIntermediateJsBundle = []; 283 hashJsonObject = {}; 284} 285 286function filterIntermediateJsBundleByHashJson(buildPath, inputPaths) { 287 inputPaths = removeDuplicateInfoOfBundleList(inputPaths); 288 289 for (let i = 0; i < inputPaths.length; ++i) { 290 fileterIntermediateJsBundle.push(inputPaths[i]); 291 } 292 const hashFilePath = genHashJsonPath(buildPath); 293 if (hashFilePath.length == 0) { 294 return; 295 } 296 let updateJsonObject = {}; 297 let jsonObject = {}; 298 let jsonFile = ""; 299 if (fs.existsSync(hashFilePath)) { 300 jsonFile = fs.readFileSync(hashFilePath).toString(); 301 jsonObject = JSON.parse(jsonFile); 302 fileterIntermediateJsBundle = []; 303 for (let i = 0; i < inputPaths.length; ++i) { 304 const cacheOutputPath = inputPaths[i].cacheOutputPath; 305 const cacheAbcFilePath = cacheOutputPath.replace(/\.temp\.js$/, '.abc'); 306 if (!fs.existsSync(cacheOutputPath)) { 307 console.debug(red, `ERROR ${cacheOutputPath} is lost`, reset); 308 process.exitCode = FAIL; 309 break; 310 } 311 312 if (fs.existsSync(cacheAbcFilePath)) { 313 const hashInputContentData = toHashData(cacheOutputPath); 314 const hashAbcContentData = toHashData(cacheAbcFilePath); 315 if (jsonObject[cacheOutputPath] === hashInputContentData && jsonObject[cacheAbcFilePath] === hashAbcContentData) { 316 updateJsonObject[cacheOutputPath] = hashInputContentData; 317 updateJsonObject[cacheAbcFilePath] = hashAbcContentData; 318 } else { 319 fileterIntermediateJsBundle.push(inputPaths[i]); 320 } 321 } else { 322 fileterIntermediateJsBundle.push(inputPaths[i]); 323 } 324 } 325 } 326 327 hashJsonObject = updateJsonObject; 328} 329 330function writeHashJson() { 331 for (let i = 0; i < fileterIntermediateJsBundle.length; ++i) { 332 const cacheOutputPath = fileterIntermediateJsBundle[i].cacheOutputPath; 333 const cacheAbcFilePath = cacheOutputPath.replace(/\.temp\.js$/, '.abc'); 334 if (!fs.existsSync(cacheOutputPath) || !fs.existsSync(cacheAbcFilePath)) { 335 console.debug(red, `ERROR ${cacheOutputPath} is lost`, reset); 336 process.exitCode = FAIL; 337 break; 338 } 339 const hashInputContentData = toHashData(cacheOutputPath); 340 const hashAbcContentData = toHashData(cacheAbcFilePath); 341 hashJsonObject[cacheOutputPath] = hashInputContentData; 342 hashJsonObject[cacheAbcFilePath] = hashAbcContentData; 343 } 344 const hashFilePath = genHashJsonPath(buildPathInfo); 345 if (hashFilePath.length == 0) { 346 return; 347 } 348 fs.writeFileSync(hashFilePath, JSON.stringify(hashJsonObject)); 349} 350 351function genHashJsonPath(buildPath) { 352 buildPath = toUnixPath(buildPath); 353 if (process.env.cachePath) { 354 if (!fs.existsSync(process.env.cachePath) || !fs.statSync(process.env.cachePath).isDirectory()) { 355 return ''; 356 } 357 let buildDirArr = buildPathInfo.split(path.sep); 358 let abilityDir = buildDirArr[buildDirArr.length - 1]; 359 let hashJsonPath = path.join(process.env.cachePath, TEMPORARY, abilityDir, hashFile); 360 validateFilePathLength(hashJsonPath); 361 let parent = path.join(hashJsonPath, '..'); 362 if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) { 363 mkDir(parent); 364 } 365 return hashJsonPath; 366 } else if (buildPath.indexOf(ARK) >= 0) { 367 const dataTmps = buildPath.split(ARK); 368 const hashPath = path.join(dataTmps[0], ARK); 369 if (!fs.existsSync(hashPath) || !fs.statSync(hashPath).isDirectory()) { 370 return ''; 371 } 372 let hashJsonPath = path.join(hashPath, hashFile); 373 validateFilePathLength(hashJsonPath); 374 return hashJsonPath; 375 } else { 376 return ''; 377 } 378} 379 380function toUnixPath(data) { 381 if (/^win/.test(require('os').platform())) { 382 const fileTmps = data.split(path.sep); 383 const newData = path.posix.join(...fileTmps); 384 return newData; 385 } 386 return data; 387} 388 389function toHashData(path) { 390 const content = fs.readFileSync(path); 391 const hash = crypto.createHash('sha256'); 392 hash.update(content); 393 return hash.digest('hex'); 394} 395 396module.exports = { 397 GenAbcPlugin: GenAbcPlugin, 398 checkWorksFile: checkWorksFile 399} 400 401function copyFileCachePathToBuildPath() { 402 for (let i = 0; i < intermediateJsBundle.length; ++i) { 403 const abcFile = intermediateJsBundle[i].path.replace(/\.temp\.js$/, ".abc"); 404 const cacheOutputPath = intermediateJsBundle[i].cacheOutputPath; 405 const cacheAbcFilePath = intermediateJsBundle[i].cacheOutputPath.replace(/\.temp\.js$/, ".abc"); 406 if (!fs.existsSync(cacheAbcFilePath)) { 407 console.debug(red, `ERROR ${cacheAbcFilePath} is lost`, reset); 408 process.exitCode = FAIL; 409 break; 410 } 411 let parent = path.join(abcFile, '..'); 412 if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) { 413 mkDir(parent); 414 } 415 // for preview mode, cache path and old abc file both exist, should copy abc file for updating 416 if (process.env.cachePath !== undefined) { 417 fs.copyFileSync(cacheAbcFilePath, abcFile); 418 } 419 if (process.env.cachePath === undefined && fs.existsSync(cacheOutputPath)) { 420 fs.unlinkSync(cacheOutputPath); 421 } 422 } 423} 424 425function processExtraAssetForBundle() { 426 writeHashJson(); 427 copyFileCachePathToBuildPath(); 428 clearGlobalInfo(); 429} 430 431function checkNodeModules() { 432 if (process.env.panda === TS2ABC) { 433 let arkEntryPath = path.join(arkDir, 'build'); 434 if (isWin) { 435 arkEntryPath = path.join(arkDir, 'build-win'); 436 } else if (isMac) { 437 arkEntryPath = path.join(arkDir, 'build-mac'); 438 } 439 let nodeModulesPath = path.join(arkEntryPath, NODE_MODULES); 440 validateFilePathLength(nodeModulesPath); 441 if (!(fs.existsSync(nodeModulesPath) && fs.statSync(nodeModulesPath).isDirectory())) { 442 console.error(red, `ERROR: node_modules for ark compiler not found. 443 Please make sure switch to non-root user before runing "npm install" for safity requirements and try re-run "npm install" under ${arkEntryPath}`, reset); 444 return false; 445 } 446 } 447 448 return true; 449} 450 451function initAbcEnv() { 452 let args = []; 453 if (process.env.minPlatformVersion === "8") { 454 process.env.panda = TS2ABC; 455 let js2abc = path.join(arkDir, 'build', 'legacy_api8', 'src', 'index.js'); 456 if (isWin) { 457 js2abc = path.join(arkDir, 'build-win', 'legacy_api8', 'src', 'index.js'); 458 } else if (isMac) { 459 js2abc = path.join(arkDir, 'build-mac', 'legacy_api8', 'src', 'index.js'); 460 } 461 validateFilePathLength(js2abc); 462 463 js2abc = '"' + js2abc + '"'; 464 args = [ 465 '--expose-gc', 466 js2abc 467 ]; 468 if (isDebug) { 469 args.push('--debug'); 470 } 471 } else if (process.env.panda === TS2ABC) { 472 let js2abc = path.join(arkDir, 'build', 'src', 'index.js'); 473 if (isWin) { 474 js2abc = path.join(arkDir, 'build-win', 'src', 'index.js'); 475 } else if (isMac) { 476 js2abc = path.join(arkDir, 'build-mac', 'src', 'index.js'); 477 } 478 validateFilePathLength(js2abc); 479 480 js2abc = '"' + js2abc + '"'; 481 args = [ 482 '--expose-gc', 483 js2abc 484 ]; 485 if (isDebug) { 486 args.push('--debug'); 487 } 488 } else if (process.env.panda === ES2ABC || process.env.panda === 'undefined' || process.env.panda === undefined) { 489 let es2abc = path.join(arkDir, 'build', 'bin', 'es2abc'); 490 if (isWin) { 491 es2abc = path.join(arkDir, 'build-win', 'bin', 'es2abc.exe'); 492 } else if (isMac) { 493 es2abc = path.join(arkDir, 'build-mac', 'bin', 'es2abc'); 494 } 495 validateFilePathLength(es2abc); 496 497 args = [ 498 '"' + es2abc + '"' 499 ]; 500 if (isDebug) { 501 args.push('--debug-info'); 502 } 503 } else { 504 console.debug(red, `ERROR: please set panda module`, reset); 505 } 506 507 return args; 508} 509 510export function isWindows() { 511 return os.type() === WINDOWS; 512} 513 514export function isLinux() { 515 return os.type() === LINUX; 516} 517 518export function isMacOs() { 519 return os.type() === MAC; 520} 521 522export function maxFilePathLength() { 523 if (isWindows()) { 524 return 32766; 525 } else if (isLinux()) { 526 return 4095; 527 } else if (isMacOs()) { 528 return 1016; 529 } else { 530 return -1; 531 } 532} 533 534export function validateFilePathLength(filePath) { 535 if (maxFilePathLength() < 0) { 536 console.error("Unknown OS platform"); 537 process.exitCode = FAIL; 538 return false; 539 } else if (filePath.length > 0 && filePath.length <= maxFilePathLength()) { 540 return true; 541 } else if (filePath.length > maxFilePathLength()) { 542 console.error(`The length of ${filePath} exceeds the limitation of current platform, which is ` + 543 `${maxFilePathLength()}. Please try moving the project folder to avoid deeply nested file path and try again`); 544 process.exitCode = FAIL; 545 return false; 546 } else { 547 console.error("Validate file path failed"); 548 process.exitCode = FAIL; 549 return false; 550 } 551} 552 553export function isEs2Abc() { 554 return process.env.panda === ES2ABC || process.env.panda === 'undefined' || process.env.panda === undefined; 555} 556 557export function isTs2Abc() { 558 return process.env.panda === TS2ABC; 559} 560 561function generateAbcByEs2AbcOfBundleMode(inputPaths) { 562 filterIntermediateJsBundleByHashJson(buildPathInfo, inputPaths); 563 if (fileterIntermediateJsBundle.length === 0) { 564 processExtraAssetForBundle() 565 return; 566 } 567 let filesInfoPath = generateFileOfBundle(fileterIntermediateJsBundle); 568 const fileThreads = os.cpus().length < 16 ? os.cpus().length : 16; 569 let genAbcCmd = 570 `${initAbcEnv().join(' ')} "@${filesInfoPath}" --file-threads "${fileThreads}"`; 571 572 console.debug('gen abc cmd is: ', genAbcCmd); 573 try { 574 if (process.env.isPreview === 'true') { 575 childProcess.execSync(genAbcCmd); 576 processExtraAssetForBundle(); 577 } else { 578 const child = childProcess.exec(genAbcCmd); 579 child.on('exit', (code) => { 580 if (code === FAIL) { 581 console.debug(red, "ERROR failed to execute es2abc", reset); 582 process.exit(FAIL); 583 } 584 if (process.env.cachePath === undefined) { 585 unlinkSync(filesInfoPath); 586 } 587 processExtraAssetForBundle(); 588 }); 589 590 child.on('error', (err) => { 591 console.debug(red, err.toString(), reset); 592 process.exit(FAIL); 593 }); 594 595 child.stderr.on('data', (data) => { 596 console.debug(red, data.toString(), reset); 597 }); 598 } 599 } catch (e) { 600 console.debug(red, `ERROR failed to generate abc with filesInfo ${filesInfoPath}. Error message: ${e} `, reset); 601 process.env.abcCompileSuccess = 'false'; 602 if (process.env.isPreview !== 'true') { 603 process.exit(FAIL); 604 } 605 } finally { 606 if (process.env.isPreview === 'true') { 607 if (process.env.cachePath === undefined) { 608 unlinkSync(filesInfoPath); 609 } 610 } 611 } 612} 613 614function generateFileOfBundle(inputPaths) { 615 let filesInfoPath = buildCachePath(FILESINFO_TXT); 616 inputPaths = removeDuplicateInfoOfBundleList(inputPaths); 617 618 let filesInfo = ''; 619 inputPaths.forEach(info => { 620 const cacheOutputPath = info.cacheOutputPath; 621 const recordName = 'null_recordName'; 622 const moduleType = 'script'; 623 const sourceFile = info.path.replace(/\.temp\.js$/, "_.js"); 624 const abcFilePath = cacheOutputPath.replace(/\.temp\.js$/, ".abc"); 625 filesInfo += `${cacheOutputPath};${recordName};${moduleType};${sourceFile};${abcFilePath}\n`; 626 }); 627 fs.writeFileSync(filesInfoPath, filesInfo, 'utf-8'); 628 629 return filesInfoPath; 630} 631 632function removeDuplicateInfoOfBundleList(inputPaths) { 633 let tempInputPaths = []; 634 inputPaths.forEach((item) => { 635 const check = tempInputPaths.every((newItem) => { 636 return item.path !== newItem.path; 637 }); 638 if (check) { 639 tempInputPaths.push(item); 640 } 641 }); 642 inputPaths = tempInputPaths; 643 644 return inputPaths; 645} 646 647function buildCachePath(tailName) { 648 let pathName = process.env.cachePath !== undefined ? 649 path.join(process.env.cachePath, tailName) : path.join(buildPathInfo, tailName); 650 validateFilePathLength(pathName); 651 652 return pathName; 653} 654 655function unlinkSync(filePath) { 656 if (fs.existsSync(filePath)) { 657 fs.unlinkSync(filePath); 658 } 659} 660 661function initCmdPrefix(abcArgs) { 662 let cmdPrefix = ""; 663 if (process.env.panda === TS2ABC) { 664 cmdPrefix = `${nodeJs} ${abcArgs.join(' ')}`; 665 } else if (process.env.panda === ES2ABC || process.env.panda === 'undefined' || process.env.panda === undefined) { 666 cmdPrefix = `${abcArgs.join(' ')}`; 667 } else { 668 console.debug(red, `ERROR please set panda module`, reset); 669 } 670 671 return cmdPrefix; 672} 673 674function processWorkersOfPreviewMode(splittedData, cmdPrefix, workerNumber) { 675 let processEnv = Object.assign({}, process.env); 676 let arkEnvParams = { 677 'splittedData': JSON.stringify(splittedData), 678 'cmdPrefix': cmdPrefix, 679 'workerNumber': workerNumber.toString() 680 }; 681 processEnv.arkEnvParams = JSON.stringify(arkEnvParams); 682 683 let genAbcCmd = `${nodeJs} "${path.resolve(__dirname, manageBunldeWorkersScript)}"`; 684 childProcess.execSync(genAbcCmd, {env: processEnv}); 685 processExtraAssetForBundle(); 686} 687 688function processWorkersOfBuildMode(splittedData, cmdPrefix, workerNumber) { 689 const clusterNewApiVersion = 16; 690 const currentNodeVersion = parseInt(process.version.split(".")[0]); 691 const useNewApi = currentNodeVersion >= clusterNewApiVersion; 692 693 if (useNewApi && cluster.isPrimary || !useNewApi && cluster.isMaster) { 694 if (useNewApi) { 695 cluster.setupPrimary({ 696 exec: path.resolve(__dirname, genAbcScript) 697 }); 698 } else { 699 cluster.setupMaster({ 700 exec: path.resolve(__dirname, genAbcScript) 701 }); 702 } 703 704 for (let i = 0; i < workerNumber; ++i) { 705 let workerData = { 706 'inputs': JSON.stringify(splittedData[i]), 707 'cmd': cmdPrefix 708 }; 709 cluster.fork(workerData); 710 } 711 712 cluster.on('exit', (worker, code, signal) => { 713 if (code === FAIL) { 714 process.exitCode = FAIL; 715 } 716 console.debug(`worker ${worker.process.pid} finished`); 717 }); 718 719 process.on('exit', (code) => { 720 if (process.exitCode !== FAIL && process.env.isPreview !== 'true') { 721 processExtraAssetForBundle(); 722 } 723 }); 724 } 725} 726 727function clearWebpackCacheByBuildInfo() { 728 if (!process.env.cachePath) { 729 return; 730 } 731 732 // clear&update cache dir when build info is different from last time 733 const cachePrebuildInfoPath = path.join(process.env.cachePath, PREBUILDINFO_JSON); 734 if (fs.existsSync(cachePrebuildInfoPath)) { 735 let cachedJson = undefined; 736 try { 737 cachedJson = JSON.parse(fs.readFileSync(cachePrebuildInfoPath).toString()); 738 } catch { 739 removeHashJsonFile(); 740 return; 741 } 742 // api version is 8 or 9 743 if (cachedJson && cachedJson.minAPIVersion && 744 cachedJson.minAPIVersion.toString() !== process.env.minPlatformVersion) { 745 removeHashJsonFile(); 746 } 747 } 748} 749 750function setPrebuildInfo() { 751 if (process.env.cachePath && process.env.minPlatformVersion) { 752 let cachedJson = {}; 753 const cachePrebuildInfoPath = path.join(process.env.cachePath, PREBUILDINFO_JSON); 754 validateFilePathLength(cachePrebuildInfoPath); 755 cachedJson.minAPIVersion = process.env.minPlatformVersion; 756 fs.writeFile(cachePrebuildInfoPath, JSON.stringify(cachedJson, null, 2), 'utf-8', 757 (err) => { 758 if (err) { 759 logger.error(red, `ArkTS:ERROR Failed to write bundle build info.`, reset); 760 } 761 } 762 ); 763 } 764} 765 766function removeHashJsonFile() { 767 const hashFilePath = genHashJsonPath(buildPathInfo); 768 if (hashFilePath.length !== 0 && fs.existsSync(hashFilePath)) { 769 fs.unlinkSync(hashFilePath); 770 } 771} 772