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