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