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 16import * as fs from 'fs'; 17import * as path from 'path'; 18import cluster from 'cluster'; 19import process from 'process'; 20import os from 'os'; 21import events from 'events'; 22import Compiler from 'webpack/lib/Compiler'; 23import { logger } from './compile_info'; 24import * as childProcess from 'child_process'; 25import { 26 toUnixPath, 27 toHashData, 28 genTemporaryPath, 29 mkdirsSync, 30 genSourceMapFileName, 31 isPackageModulesFile, 32 nodeLargeOrEqualTargetVersion, 33 removeDir, 34 validateFilePathLength, 35 unlinkSync 36} from './utils'; 37import { 38 buildCachePath, 39 genAbcFileName, 40 genBuildPath, 41 genMergeProtoFileName, 42 genProtoFileName, 43 getOhmUrlByFilepath, 44 getPackageInfo, 45 isEs2Abc, 46 isTs2Abc, 47 newSourceMaps, 48 removeDuplicateInfo 49} from './ark_utils'; 50import { projectConfig } from '../main'; 51import { 52 ESMODULE, 53 JSBUNDLE, 54 NODE_MODULES, 55 ES2ABC, 56 EXTNAME_D_ETS, 57 EXTNAME_D_TS, 58 EXTNAME_ETS, 59 EXTNAME_JS, 60 EXTNAME_TS, 61 EXTNAME_MJS, 62 EXTNAME_CJS, 63 EXTNAME_JSON, 64 EXTNAME_JS_MAP, 65 FAIL, 66 MODULELIST_JSON, 67 MODULES_ABC, 68 PREBUILDINFO_JSON, 69 SUCCESS, 70 SOURCEMAPS_JSON, 71 SOURCEMAPS, 72 TEMPORARY, 73 TS2ABC, 74 PROTO_FILESINFO_TXT, 75 NPMENTRIES_TXT, 76 EXTNAME_PROTO_BIN, 77 FILESINFO_TXT, 78 MANAGE_WORKERS_SCRIPT, 79 MAX_WORKER_NUMBER, 80 GEN_ABC_SCRIPT, 81 GEN_MODULE_ABC_SCRIPT, 82 AOT_FULL, 83 AOT_PARTIAL, 84 PACKAGES 85} from './pre_define'; 86import { 87 generateMergedAbc, 88 generateNpmEntriesInfo 89} from './gen_merged_abc'; 90import { 91 generateAot, 92 generateBuiltinAbc, 93 FaultHandler 94} from './gen_aot' 95import { Logger } from 'log4js'; 96 97let output: string; 98let isWin: boolean = false; 99let isMac: boolean = false; 100let isDebug: boolean = false; 101let arkDir: string; 102let nodeJs: string; 103 104interface File { 105 path: string, 106 size: number, 107 cacheOutputPath: string, 108 sourceFile: string 109} 110let intermediateJsBundle: Array<File> = []; 111let fileterIntermediateJsBundle: Array<File> = []; 112let moduleInfos: Array<ModuleInfo> = []; 113let filterModuleInfos: Array<ModuleInfo> = []; 114let commonJsModuleInfos: Array<ModuleInfo> = []; 115let ESMModuleInfos: Array<ModuleInfo> = []; 116let entryInfos: Map<string, EntryInfo> = new Map<string, EntryInfo>(); 117let hashJsonObject = {}; 118let moduleHashJsonObject = {}; 119let buildPathInfo: string = ''; 120let buildMapFileList: Set<string> = new Set<string>(); 121let isHotReloadFirstBuild: boolean = true; 122let protoFilePath: string = ''; 123 124const red: string = '\u001b[31m'; 125const reset: string = '\u001b[39m'; 126const blue = '\u001b[34m'; 127const hashFile: string = 'gen_hash.json'; 128const ARK: string = '/ark/'; 129 130export class ModuleInfo { 131 filePath: string; 132 tempFilePath: string; 133 buildFilePath: string; 134 abcFilePath: string; 135 isCommonJs: boolean; 136 recordName: string; 137 sourceFile: string; 138 packageName: string; 139 140 constructor(filePath: string, tempFilePath: string, buildFilePath: string, 141 abcFilePath: string, packageName: string, isCommonJs: boolean) { 142 this.filePath = filePath; 143 this.tempFilePath = tempFilePath; 144 this.buildFilePath = buildFilePath; 145 this.abcFilePath = abcFilePath; 146 this.packageName = packageName; 147 this.isCommonJs = isCommonJs; 148 this.recordName = getOhmUrlByFilepath(filePath, projectConfig, logger); 149 this.sourceFile = filePath.replace(projectConfig.projectRootPath + path.sep, ''); 150 } 151} 152 153export class EntryInfo { 154 npmInfo: string; 155 buildPath: string; 156 entry: string; 157 158 constructor(npmInfo: string, buildPath: string, entry: string) { 159 this.npmInfo = npmInfo; 160 this.buildPath = buildPath; 161 this.entry = entry; 162 } 163} 164 165export class GenAbcPlugin { 166 constructor(output_, arkDir_, nodeJs_, isDebug_) { 167 output = output_; 168 arkDir = arkDir_; 169 nodeJs = nodeJs_; 170 isDebug = isDebug_; 171 } 172 apply(compiler: Compiler) { 173 if (fs.existsSync(path.resolve(arkDir, 'build-win'))) { 174 isWin = true; 175 } else { 176 if (fs.existsSync(path.resolve(arkDir, 'build-mac'))) { 177 isMac = true; 178 } else { 179 if (!fs.existsSync(path.resolve(arkDir, 'build'))) { 180 logger.error(red, 'ArkTS:ERROR find build fail', reset); 181 process.exitCode = FAIL; 182 return; 183 } 184 } 185 } 186 187 if (!checkNodeModules()) { 188 process.exitCode = FAIL; 189 return; 190 } 191 192 if (projectConfig.compileMode === ESMODULE) { 193 if (projectConfig.cachePath && !projectConfig.xtsMode) { 194 let cachedJson: any = {}; 195 const cachePrebuildInfoPath: string = path.join(projectConfig.cachePath, PREBUILDINFO_JSON); 196 validateFilePathLength(cachePrebuildInfoPath, logger); 197 cachedJson.buildMode = projectConfig.buildArkMode; 198 cachedJson.bundleName = projectConfig.bundleName; 199 cachedJson.moduleName = projectConfig.moduleName; 200 fs.writeFile(cachePrebuildInfoPath, JSON.stringify(cachedJson, null, 2), 'utf-8', 201 (err) => { 202 if (err) { 203 logger.error(red, `ArkTS:ERROR Failed to write module build info.`, reset); 204 } 205 } 206 ); 207 } 208 209 // clear output dir 210 removeDir(output); 211 removeDir(projectConfig.nodeModulesPath); 212 } 213 214 if (projectConfig.compileMode === JSBUNDLE && process.env.minPlatformVersion) { 215 if (projectConfig.cachePath && !projectConfig.xtsMode) { 216 let cachedJson: any = {}; 217 const cachePrebuildInfoPath: string = path.join(projectConfig.cachePath, PREBUILDINFO_JSON); 218 validateFilePathLength(cachePrebuildInfoPath, logger); 219 cachedJson.minAPIVersion = process.env.minPlatformVersion; 220 fs.writeFile(cachePrebuildInfoPath, JSON.stringify(cachedJson, null, 2), 'utf-8', 221 (err) => { 222 if (err) { 223 logger.error(red, `ArkTS:ERROR Failed to write bundle build info.`, reset); 224 } 225 } 226 ); 227 } 228 } 229 230 // for preview mode max listeners 231 events.EventEmitter.defaultMaxListeners = 100; 232 233 compiler.hooks.compilation.tap('GenAbcPlugin', (compilation) => { 234 if (projectConfig.compileMode === JSBUNDLE || projectConfig.compileMode === undefined) { 235 return; 236 } 237 buildPathInfo = output; 238 compilation.hooks.finishModules.tap('finishModules', handleFinishModules.bind(this)); 239 }); 240 241 compiler.hooks.compilation.tap('GenAbcPlugin', (compilation) => { 242 compilation.hooks.processAssets.tap('processAssets', (assets) => { 243 if (projectConfig.compileMode === JSBUNDLE || projectConfig.compileMode === undefined) { 244 return; 245 } 246 Object.keys(compilation.assets).forEach(key => { 247 if (path.extname(key) === EXTNAME_JS || path.extname(key) === EXTNAME_JS_MAP) { 248 delete assets[key]; 249 } 250 }); 251 }); 252 }); 253 254 compiler.hooks.emit.tap('GenAbcPlugin', (compilation) => { 255 if (projectConfig.compileMode === ESMODULE) { 256 return; 257 } 258 Object.keys(compilation.assets).forEach(key => { 259 // choose *.js 260 if (output && path.extname(key) === EXTNAME_JS) { 261 const newContent: string = compilation.assets[key].source(); 262 const keyPath: string = key.replace(/\.js$/, ".temp.js"); 263 writeFileSync(newContent, output, keyPath, key); 264 } 265 }); 266 }); 267 268 compiler.hooks.afterEmit.tap('GenAbcPluginMultiThread', () => { 269 if (projectConfig.compileMode === ESMODULE) { 270 return; 271 } 272 if (intermediateJsBundle.length === 0) { 273 return; 274 } 275 buildPathInfo = output; 276 if (isTs2Abc(projectConfig) || process.env.minPlatformVersion === "8") { 277 invokeWorkersToGenAbc(); 278 } else if (isEs2Abc(projectConfig)){ 279 generateAbcByEs2AbcOfBundleMode(intermediateJsBundle); 280 } else { 281 logger.error(red, `ArkTS:ERROR please set panda module`, reset); 282 } 283 }); 284 } 285} 286 287function clearGlobalInfo() { 288 // fix bug of multi trigger 289 if (process.env.watchMode !== 'true') { 290 intermediateJsBundle = []; 291 moduleInfos = []; 292 entryInfos = new Map<string, EntryInfo>(); 293 } 294 fileterIntermediateJsBundle = []; 295 filterModuleInfos = []; 296 commonJsModuleInfos = []; 297 ESMModuleInfos = []; 298 hashJsonObject = {}; 299 moduleHashJsonObject = {}; 300 buildMapFileList = new Set<string>(); 301} 302 303function getEntryInfo(filePath: string, resourceResolveData: any): string { 304 if (!resourceResolveData.descriptionFilePath) { 305 return; 306 } 307 308 let isEntry: boolean = false; 309 let mainFileds: Set<string> = getEntryCandidatesFromPackageJson(resourceResolveData); 310 for (let value of mainFileds.values()) { 311 if (toUnixPath(filePath) === value) { 312 isEntry = true; 313 break; 314 } 315 } 316 const packageJsonPath: string = resourceResolveData.descriptionFilePath; 317 let npmInfoPath: string = path.resolve(packageJsonPath, '..'); 318 319 let entry: string = toUnixPath(filePath.replace(npmInfoPath, '')); 320 if (entry.startsWith('/')) { 321 entry = entry.slice(1, entry.length); 322 } 323 324 const fakeEntryPath: string = path.resolve(npmInfoPath, 'fake.js'); 325 const tempFakeEntryPath: string = genTemporaryPath(fakeEntryPath, projectConfig.projectPath, process.env.cachePath, 326 projectConfig); 327 const buildFakeEntryPath: string = genBuildPath(fakeEntryPath, projectConfig.projectPath, projectConfig.buildPath, 328 projectConfig); 329 npmInfoPath = toUnixPath(path.resolve(tempFakeEntryPath, '..')); 330 const buildNpmInfoPath: string = toUnixPath(path.resolve(buildFakeEntryPath, '..')); 331 if (!entryInfos.has(npmInfoPath) && isEntry) { 332 const entryInfo: EntryInfo = new EntryInfo(npmInfoPath, buildNpmInfoPath, entry); 333 entryInfos.set(npmInfoPath, entryInfo); 334 } 335 336 return buildNpmInfoPath; 337} 338 339function getEntryCandidatesFromPackageJson(resourceResolveData: any): Set<string>{ 340 let descriptionFileData: any = resourceResolveData.descriptionFileData; 341 let packagePath: string = path.resolve(resourceResolveData.descriptionFilePath, '..'); 342 let mainFileds: Set<string> = new Set<string>(); 343 if (descriptionFileData.browser) { 344 if (typeof descriptionFileData.browser === 'string') { 345 mainFileds.add(toUnixPath(path.join(packagePath, descriptionFileData.browser))); 346 } else { 347 Object.keys(descriptionFileData.browser).forEach(key => { 348 if (typeof key === 'string' && typeof descriptionFileData.browser[key] === 'string') { 349 mainFileds.add(toUnixPath(path.join(packagePath, descriptionFileData.browser[key]))); 350 } 351 }); 352 } 353 } 354 if (descriptionFileData.module) { 355 mainFileds.add(toUnixPath(path.join(packagePath, descriptionFileData.module))); 356 } 357 if (descriptionFileData.main) { 358 mainFileds.add(toUnixPath(path.join(packagePath, descriptionFileData.main))); 359 } 360 if (mainFileds.size === 0) { 361 mainFileds.add(toUnixPath(path.join(packagePath, 'index.js'))); 362 mainFileds.add(toUnixPath(path.join(packagePath, 'index.ets'))); 363 mainFileds.add(toUnixPath(path.join(packagePath, 'index.ts'))); 364 } 365 366 return mainFileds; 367} 368 369function processNodeModulesFile(filePath: string, tempFilePath: string, buildFilePath: string, abcFilePath: string, nodeModulesFile: Array<string>, module: any): void { 370 let npmPkgPath: string = getEntryInfo(filePath, module.resourceResolveData); 371 const buildNpmPkgPath: string = npmPkgPath.replace(toUnixPath(projectConfig.nodeModulesPath), ''); 372 const npmPkgName: string = toUnixPath(path.join(PACKAGES, buildNpmPkgPath)).replace(new RegExp(NODE_MODULES, 'g'), PACKAGES); 373 374 const descriptionFileData: any = module.resourceResolveData.descriptionFileData; 375 if (descriptionFileData && descriptionFileData['type'] && descriptionFileData['type'] === 'module') { 376 const tempModuleInfo: ModuleInfo = new ModuleInfo(filePath, tempFilePath, buildFilePath, abcFilePath, npmPkgName, false); 377 moduleInfos.push(tempModuleInfo); 378 nodeModulesFile.push(tempFilePath); 379 } else if (filePath.endsWith(EXTNAME_MJS)) { 380 const tempModuleInfo: ModuleInfo = new ModuleInfo(filePath, tempFilePath, buildFilePath, abcFilePath, npmPkgName, false); 381 moduleInfos.push(tempModuleInfo); 382 nodeModulesFile.push(tempFilePath); 383 } else { 384 const tempModuleInfo: ModuleInfo = new ModuleInfo(filePath, tempFilePath, buildFilePath, abcFilePath, npmPkgName, true); 385 moduleInfos.push(tempModuleInfo); 386 nodeModulesFile.push(tempFilePath); 387 } 388 if (!filePath.endsWith(EXTNAME_JSON)) { 389 buildMapFileList.add(toUnixPath(filePath.replace(projectConfig.projectRootPath + path.sep, ''))); 390 } 391} 392 393function processEtsModule(filePath: string, tempFilePath: string, buildFilePath: string, nodeModulesFile: Array<string>, module: any): void { 394 // skip declaration modules 395 if (filePath.endsWith(EXTNAME_D_ETS)) { 396 return; 397 } 398 if (projectConfig.processTs === true) { 399 tempFilePath = tempFilePath.replace(/\.ets$/, EXTNAME_TS); 400 buildFilePath = buildFilePath.replace(/\.ets$/, EXTNAME_TS); 401 } else { 402 tempFilePath = tempFilePath.replace(/\.ets$/, EXTNAME_JS); 403 buildFilePath = buildFilePath.replace(/\.ets$/, EXTNAME_JS); 404 } 405 const abcFilePath: string = genAbcFileName(tempFilePath); 406 if (isPackageModulesFile(filePath, projectConfig)) { 407 processNodeModulesFile(filePath, tempFilePath, buildFilePath, abcFilePath, nodeModulesFile, module); 408 } else { 409 const moduleName: string = getPackageInfo(projectConfig.aceModuleJsonPath)[1]; 410 const tempModuleInfo: ModuleInfo = new ModuleInfo(filePath, tempFilePath, buildFilePath, abcFilePath, moduleName, false); 411 moduleInfos.push(tempModuleInfo); 412 } 413 buildMapFileList.add(toUnixPath(filePath.replace(projectConfig.projectRootPath + path.sep, ''))); 414} 415 416function processTsModule(filePath: string, tempFilePath: string, buildFilePath: string, nodeModulesFile: Array<string>, module: any): void { 417 // skip declaration modules 418 if (filePath.endsWith(EXTNAME_D_TS)) { 419 return; 420 } 421 if (projectConfig.processTs === false) { 422 tempFilePath = tempFilePath.replace(/\.ts$/, EXTNAME_JS); 423 buildFilePath = buildFilePath.replace(/\.ts$/, EXTNAME_JS); 424 } 425 const abcFilePath: string = genAbcFileName(tempFilePath); 426 if (isPackageModulesFile(filePath, projectConfig)) { 427 processNodeModulesFile(filePath, tempFilePath, buildFilePath, abcFilePath, nodeModulesFile, module); 428 } else { 429 const moduleName: string = getPackageInfo(projectConfig.aceModuleJsonPath)[1]; 430 const tempModuleInfo: ModuleInfo = new ModuleInfo(filePath, tempFilePath, buildFilePath, abcFilePath, moduleName, false); 431 moduleInfos.push(tempModuleInfo); 432 } 433 buildMapFileList.add(toUnixPath(filePath.replace(projectConfig.projectRootPath + path.sep, ''))); 434} 435 436function processJsModule(filePath: string, tempFilePath: string, buildFilePath: string, nodeModulesFile: Array<string>, module: any): void { 437 const parent: string = path.join(tempFilePath, '..'); 438 if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) { 439 mkDir(parent); 440 } 441 if (filePath.endsWith(EXTNAME_MJS) || filePath.endsWith(EXTNAME_CJS)) { 442 fs.copyFileSync(filePath, tempFilePath); 443 } 444 const abcFilePath: string = genAbcFileName(tempFilePath); 445 if (isPackageModulesFile(filePath, projectConfig)) { 446 processNodeModulesFile(filePath, tempFilePath, buildFilePath, abcFilePath, nodeModulesFile, module); 447 } else { 448 const moduleName: string = getPackageInfo(projectConfig.aceModuleJsonPath)[1]; 449 const tempModuleInfo: ModuleInfo = new ModuleInfo(filePath, tempFilePath, buildFilePath, abcFilePath, moduleName, false); 450 moduleInfos.push(tempModuleInfo); 451 } 452 buildMapFileList.add(toUnixPath(filePath.replace(projectConfig.projectRootPath + path.sep, ''))); 453} 454 455function processJsonModule(filePath: string, tempFilePath: string, buildFilePath: string, nodeModulesFile: Array<string>, module: any): void { 456 const abcFilePath: string = "NA"; 457 if (isPackageModulesFile(filePath, projectConfig)) { 458 processNodeModulesFile(filePath, tempFilePath, buildFilePath, abcFilePath, nodeModulesFile, module); 459 } else { 460 const moduleName: string = getPackageInfo(projectConfig.aceModuleJsonPath)[1]; 461 const tempModuleInfo: ModuleInfo = new ModuleInfo(filePath, tempFilePath, buildFilePath, abcFilePath, moduleName, false); 462 moduleInfos.push(tempModuleInfo); 463 } 464} 465 466var cachedSourceMaps: Object; 467 468function updateCachedSourceMaps(): void { 469 const CACHED_SOURCEMAPS: string = path.join(process.env.cachePath, SOURCEMAPS_JSON); 470 validateFilePathLength(CACHED_SOURCEMAPS, logger); 471 if (!fs.existsSync(CACHED_SOURCEMAPS)) { 472 cachedSourceMaps = {}; 473 } else { 474 cachedSourceMaps = JSON.parse(fs.readFileSync(CACHED_SOURCEMAPS).toString()); 475 } 476 Object.keys(newSourceMaps).forEach(key => { 477 cachedSourceMaps[key] = newSourceMaps[key]; 478 }); 479} 480 481function getCachedModuleList(): Array<string> { 482 const CACHED_MODULELIST_FILE: string = path.join(process.env.cachePath, MODULELIST_JSON); 483 validateFilePathLength(CACHED_MODULELIST_FILE, logger); 484 if (!fs.existsSync(CACHED_MODULELIST_FILE)) { 485 return []; 486 } 487 const data: any = JSON.parse(fs.readFileSync(CACHED_MODULELIST_FILE).toString()); 488 const moduleList: Array<string> = data.list; 489 return moduleList; 490} 491 492function updateCachedModuleList(moduleList: Array<string>): void { 493 const CACHED_MODULELIST_FILE: string = path.join(process.env.cachePath, MODULELIST_JSON); 494 validateFilePathLength(CACHED_MODULELIST_FILE, logger); 495 const CACHED_SOURCEMAPS: string = path.join(process.env.cachePath, SOURCEMAPS_JSON); 496 validateFilePathLength(CACHED_SOURCEMAPS, logger); 497 let cachedJson: Object = {}; 498 cachedJson["list"] = moduleList; 499 fs.writeFile(CACHED_MODULELIST_FILE, JSON.stringify(cachedJson, null, 2), 'utf-8', 500 (err) => { 501 if (err) { 502 logger.error(red, `ArkTS:ERROR Failed to write module list.`, reset); 503 } 504 } 505 ); 506 fs.writeFile(CACHED_SOURCEMAPS, JSON.stringify(cachedSourceMaps, null, 2), 'utf-8', 507 (err) => { 508 if (err) { 509 logger.error(red, `ArkTS:ERROR Failed to write cache sourceMaps json.`, reset); 510 } 511 } 512 ); 513} 514 515function writeSourceMaps(): void { 516 mkdirsSync(projectConfig.buildPath); 517 let sourceMapFilePath: string = path.join(projectConfig.buildPath, SOURCEMAPS); 518 validateFilePathLength(sourceMapFilePath, logger); 519 fs.writeFile(sourceMapFilePath, JSON.stringify(cachedSourceMaps, null, 2), 'utf-8', 520 (err) => { 521 if (err) { 522 logger.error(red, `ArkTS:ERROR Failed to write sourceMaps.`, reset); 523 } 524 } 525 ); 526} 527 528function eliminateUnusedFiles(moduleList: Array<string>): void{ 529 let cachedModuleList: Array<string> = getCachedModuleList(); 530 if (cachedModuleList.length !== 0) { 531 const eliminateFiles: Array<string> = cachedModuleList.filter(m => !moduleList.includes(m)); 532 eliminateFiles.forEach((file) => { 533 delete cachedSourceMaps[file]; 534 }); 535 } 536} 537 538function handleFullModuleFiles(modules, callback): any { 539 const nodeModulesFile: Array<string> = []; 540 modules.forEach(module => { 541 if (module !== undefined && module.resourceResolveData !== undefined) { 542 const filePath: string = module.resourceResolveData.path; 543 let tempFilePath = genTemporaryPath(filePath, projectConfig.projectPath, process.env.cachePath, projectConfig); 544 if (tempFilePath.length === 0) { 545 return; 546 } 547 validateFilePathLength(tempFilePath, logger); 548 let buildFilePath: string = genBuildPath(filePath, projectConfig.projectPath, projectConfig.buildPath, 549 projectConfig); 550 validateFilePathLength(buildFilePath, logger); 551 tempFilePath = toUnixPath(tempFilePath); 552 buildFilePath = toUnixPath(buildFilePath); 553 554 switch (path.extname(filePath)) { 555 case EXTNAME_ETS: { 556 processEtsModule(filePath, tempFilePath, buildFilePath, nodeModulesFile, module); 557 break; 558 } 559 case EXTNAME_TS: { 560 processTsModule(filePath, tempFilePath, buildFilePath, nodeModulesFile, module); 561 break; 562 } 563 case EXTNAME_JS: 564 case EXTNAME_MJS: 565 case EXTNAME_CJS: { 566 processJsModule(filePath, tempFilePath, buildFilePath, nodeModulesFile, module); 567 break; 568 } 569 case EXTNAME_JSON: { 570 processJsonModule(filePath, tempFilePath, buildFilePath, nodeModulesFile, module); 571 break; 572 } 573 default: { 574 logger.error(red, `ArkTS:ERROR Cannot find resolve this file path: ${filePath}`, reset); 575 process.exitCode = FAIL; 576 } 577 } 578 } 579 }); 580 581 // for mergeabc source maps 582 if (projectConfig.buildArkMode === 'debug') { 583 const moduleList: Array<string> = Array.from(buildMapFileList); 584 updateCachedSourceMaps(); 585 eliminateUnusedFiles(moduleList); 586 updateCachedModuleList(moduleList); 587 writeSourceMaps(); 588 } 589 590 if (process.env.panda !== TS2ABC) { 591 const outputABCPath: string = path.join(projectConfig.buildPath, MODULES_ABC); 592 validateFilePathLength(outputABCPath, logger); 593 generateMergedAbc(moduleInfos, entryInfos, outputABCPath); 594 clearGlobalInfo(); 595 } else { 596 invokeWorkersModuleToGenAbc(moduleInfos); 597 } 598} 599 600function processEntryToGenAbc(entryInfos: Map<string, EntryInfo>): void { 601 if (entryInfos.size <= 0) { 602 return; 603 } 604 generateNpmEntriesInfo(entryInfos); 605 const npmEntriesInfoPath: string = path.join(process.env.cachePath, NPMENTRIES_TXT); 606 validateFilePathLength(npmEntriesInfoPath, logger); 607 let npmEntriesProtoFileName: string = "npm_entries" + EXTNAME_PROTO_BIN; 608 const npmEntriesProtoFilePath: string = path.join(process.env.cachePath, "protos", "npm_entries", npmEntriesProtoFileName); 609 validateFilePathLength(npmEntriesProtoFilePath, logger); 610 mkdirsSync(path.dirname(npmEntriesProtoFilePath)); 611 let js2Abc: string = path.join(arkDir, 'build', 'bin', 'js2abc'); 612 if (isWin) { 613 js2Abc = path.join(arkDir, 'build-win', 'bin', 'js2abc.exe'); 614 } else if (isMac) { 615 js2Abc = path.join(arkDir, 'build-mac', 'bin', 'js2abc'); 616 } 617 validateFilePathLength(js2Abc, logger); 618 const singleCmd: any = `"${js2Abc}" --compile-npm-entries "${npmEntriesInfoPath}" "${npmEntriesProtoFilePath}`; 619 try { 620 childProcess.execSync(singleCmd); 621 } catch (e) { 622 logger.debug(red, `ArkTS:ERROR Failed to generate npm proto file to abc, Error message: ${e}`, reset); 623 } 624} 625 626function writeFileSync(inputString: string, buildPath: string, keyPath: string, jsBundleFile: string): void { 627 let output = path.resolve(buildPath, keyPath); 628 validateFilePathLength(output, logger); 629 let parent: string = path.join(output, '..'); 630 if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) { 631 mkDir(parent); 632 } 633 let cacheOutputPath: string = ""; 634 if (process.env.cachePath) { 635 let buildDirArr: string[] = projectConfig.buildPath.split(path.sep); 636 let abilityDir: string = buildDirArr[buildDirArr.length - 1]; 637 cacheOutputPath = path.join(process.env.cachePath, TEMPORARY, abilityDir, keyPath); 638 } else { 639 cacheOutputPath = output; 640 } 641 validateFilePathLength(cacheOutputPath, logger); 642 parent = path.join(cacheOutputPath, '..'); 643 if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) { 644 mkDir(parent); 645 } 646 fs.writeFileSync(cacheOutputPath, inputString); 647 if (fs.existsSync(cacheOutputPath)) { 648 const fileSize: any = fs.statSync(cacheOutputPath).size; 649 let sourceFile: string = output.replace(/\.temp\.js$/, "_.js"); 650 if (!isDebug && projectConfig.projectRootPath) { 651 sourceFile = toUnixPath(sourceFile.replace(projectConfig.projectRootPath + path.sep, '')); 652 } else { 653 sourceFile = toUnixPath(sourceFile); 654 } 655 output = toUnixPath(output); 656 cacheOutputPath = toUnixPath(cacheOutputPath); 657 658 intermediateJsBundle.push({path: output, size: fileSize, cacheOutputPath: cacheOutputPath, sourceFile: sourceFile}); 659 } else { 660 logger.debug(red, `ArkTS:ERROR Failed to convert file ${jsBundleFile} to bin. ${output} is lost`, reset); 661 process.exitCode = FAIL; 662 } 663} 664 665function mkDir(path_: string): void { 666 const parent: string = path.join(path_, '..'); 667 if (!(fs.existsSync(parent) && !fs.statSync(parent).isFile())) { 668 mkDir(parent); 669 } 670 fs.mkdirSync(path_); 671} 672 673function getSmallestSizeGroup(groupSize: Map<number, number>): any { 674 const groupSizeArray: any = Array.from(groupSize); 675 groupSizeArray.sort(function(g1, g2) { 676 return g1[1] - g2[1]; // sort by size 677 }); 678 return groupSizeArray[0][0]; 679} 680 681function splitJsBundlesBySize(bundleArray: Array<File>, groupNumber: number): any { 682 const result: any = []; 683 if (bundleArray.length < groupNumber) { 684 for (const value of bundleArray) { 685 result.push([value]); 686 } 687 return result; 688 } 689 690 bundleArray.sort(function(f1: File, f2: File) { 691 return f2.size - f1.size; 692 }); 693 const groupFileSize: any = new Map(); 694 for (let i = 0; i < groupNumber; ++i) { 695 result.push([]); 696 groupFileSize.set(i, 0); 697 } 698 699 let index = 0; 700 while (index < bundleArray.length) { 701 const smallestGroup: any = getSmallestSizeGroup(groupFileSize); 702 result[smallestGroup].push(bundleArray[index]); 703 const sizeUpdate: any = groupFileSize.get(smallestGroup) + bundleArray[index].size; 704 groupFileSize.set(smallestGroup, sizeUpdate); 705 index++; 706 } 707 return result; 708} 709 710function invokeWorkersModuleToGenAbc(moduleInfos: Array<ModuleInfo>): void { 711 invokeClusterModuleToAbc(); 712} 713 714export function initAbcEnv() : string[] { 715 let args: string[] = []; 716 if (process.env.minPlatformVersion === "8") { 717 process.env.panda = TS2ABC; 718 let js2abc: string = path.join(arkDir, 'build', 'legacy_api8', 'src', 'index.js'); 719 if (isWin) { 720 js2abc = path.join(arkDir, 'build-win', 'legacy_api8', 'src', 'index.js'); 721 } else if (isMac) { 722 js2abc = path.join(arkDir, 'build-mac', 'legacy_api8', 'src', 'index.js'); 723 } 724 validateFilePathLength(js2abc, logger); 725 726 js2abc = '"' + js2abc + '"'; 727 args = [ 728 '--expose-gc', 729 js2abc 730 ]; 731 if (isDebug) { 732 args.push('--debug'); 733 } 734 } else if (process.env.panda === TS2ABC) { 735 let js2abc: string = path.join(arkDir, 'build', 'src', 'index.js'); 736 if (isWin) { 737 js2abc = path.join(arkDir, 'build-win', 'src', 'index.js'); 738 } else if (isMac) { 739 js2abc = path.join(arkDir, 'build-mac', 'src', 'index.js'); 740 } 741 validateFilePathLength(js2abc, logger); 742 743 js2abc = '"' + js2abc + '"'; 744 args = [ 745 '--expose-gc', 746 js2abc 747 ]; 748 if (isDebug) { 749 args.push('--debug'); 750 } 751 } else if (process.env.panda === ES2ABC || process.env.panda === 'undefined' || process.env.panda === undefined) { 752 let es2abc: string = path.join(arkDir, 'build', 'bin', 'es2abc'); 753 if (isWin) { 754 es2abc = path.join(arkDir, 'build-win', 'bin', 'es2abc.exe'); 755 } else if (isMac) { 756 es2abc = path.join(arkDir, 'build-mac', 'bin', 'es2abc'); 757 } 758 validateFilePathLength(es2abc, logger); 759 760 args = [ 761 '"' + es2abc + '"' 762 ]; 763 if (isDebug) { 764 args.push('--debug-info'); 765 } 766 if (projectConfig.compileMode === ESMODULE) { 767 args.push('--merge-abc'); 768 } 769 } else { 770 logger.error(red, `ArkTS:ERROR please set panda module`, reset); 771 } 772 773 return args; 774} 775 776function invokeClusterModuleToAbc(): void { 777 if (process.env.watchMode === 'true') { 778 process.exitCode = SUCCESS; 779 } 780 filterIntermediateModuleByHashJson(buildPathInfo, moduleInfos); 781 const abcArgs: string[] = initAbcEnv(); 782 783 const splitedModules: any[] = splitModulesByNumber(filterModuleInfos, MAX_WORKER_NUMBER); 784 let cmdPrefix: string = `${nodeJs} ${abcArgs.join(' ')}`; 785 const workerNumber: number = MAX_WORKER_NUMBER < splitedModules.length ? MAX_WORKER_NUMBER : splitedModules.length; 786 787 try { 788 if (process.env.watchMode === 'true') { 789 processWorkersOfPreviewMode(splitedModules, cmdPrefix, workerNumber); 790 } else { 791 processWorkersOfBuildMode(splitedModules, cmdPrefix, workerNumber); 792 } 793 } catch (e) { 794 logger.debug(red, `ArkTS:ERROR failed to generate abc. Error message: ${e}`, reset); 795 process.env.abcCompileSuccess = 'false'; 796 if (process.env.watchMode !== 'true') { 797 process.exit(FAIL); 798 } 799 } 800} 801 802function splitModulesByNumber(moduleInfos: Array<ModuleInfo>, workerNumber: number): any[] { 803 const result: any = []; 804 if (moduleInfos.length < workerNumber) { 805 for (const value of moduleInfos) { 806 result.push([value]); 807 } 808 return result; 809 } 810 811 for (let i = 0; i < workerNumber; ++i) { 812 result.push([]); 813 } 814 815 for (let i = 0; i < moduleInfos.length; i++) { 816 const chunk = i % workerNumber; 817 result[chunk].push(moduleInfos[i]); 818 } 819 820 return result; 821} 822 823function invokeWorkersToGenAbc(): void { 824 if (process.env.watchMode === 'true') { 825 process.exitCode = SUCCESS; 826 } 827 let cmdPrefix: string = ''; 828 829 const abcArgs: string[] = initAbcEnv(); 830 if (process.env.panda === TS2ABC) { 831 cmdPrefix = `${nodeJs} ${abcArgs.join(' ')}`; 832 } else { 833 logger.error(red, `ArkTS:ERROR please set panda module`, reset); 834 } 835 836 filterIntermediateJsBundleByHashJson(buildPathInfo, intermediateJsBundle); 837 const splitedBundles: any[] = splitJsBundlesBySize(fileterIntermediateJsBundle, MAX_WORKER_NUMBER); 838 const workerNumber: number = MAX_WORKER_NUMBER < splitedBundles.length ? MAX_WORKER_NUMBER : splitedBundles.length; 839 840 try { 841 if (process.env.watchMode === 'true') { 842 processWorkersOfPreviewMode(splitedBundles, cmdPrefix, workerNumber); 843 } else { 844 processWorkersOfBuildMode(splitedBundles, cmdPrefix, workerNumber); 845 } 846 } catch (e) { 847 logger.debug(red, `ArkTS:ERROR failed to generate abc. Error message: ${e}`, reset); 848 process.env.abcCompileSuccess = 'false'; 849 if (process.env.watchMode !== 'true') { 850 process.exit(FAIL); 851 } 852 } 853} 854 855function filterIntermediateModuleByHashJson(buildPath: string, moduleInfos: Array<ModuleInfo>): void { 856 const tempModuleInfos = Array<ModuleInfo>(); 857 moduleInfos.forEach((item) => { 858 const check = tempModuleInfos.every((newItem) => { 859 return item.tempFilePath !== newItem.tempFilePath; 860 }); 861 if (check) { 862 tempModuleInfos.push(item); 863 } 864 }); 865 moduleInfos = tempModuleInfos; 866 867 for (let i = 0; i < moduleInfos.length; ++i) { 868 filterModuleInfos.push(moduleInfos[i]); 869 } 870 const hashFilePath: string = genHashJsonPath(buildPath); 871 if (hashFilePath.length === 0) { 872 return; 873 } 874 const updateJsonObject: any = {}; 875 let jsonObject: any = {}; 876 let jsonFile: string = ''; 877 if (fs.existsSync(hashFilePath)) { 878 jsonFile = fs.readFileSync(hashFilePath).toString(); 879 jsonObject = JSON.parse(jsonFile); 880 filterModuleInfos = []; 881 for (let i = 0; i < moduleInfos.length; ++i) { 882 const input: string = moduleInfos[i].tempFilePath; 883 let outputPath: string = genProtoFileName(moduleInfos[i].tempFilePath); 884 if (!fs.existsSync(input)) { 885 logger.debug(red, `ArkTS:ERROR ${input} is lost`, reset); 886 process.exitCode = FAIL; 887 break; 888 } 889 if (fs.existsSync(outputPath)) { 890 const hashInputContentData: any = toHashData(input); 891 const hashAbcContentData: any = toHashData(outputPath); 892 if (jsonObject[input] === hashInputContentData && jsonObject[outputPath] === hashAbcContentData) { 893 updateJsonObject[input] = hashInputContentData; 894 updateJsonObject[outputPath] = hashAbcContentData; 895 } else { 896 filterModuleInfos.push(moduleInfos[i]); 897 } 898 } else { 899 filterModuleInfos.push(moduleInfos[i]); 900 } 901 } 902 } 903 904 moduleHashJsonObject = updateJsonObject; 905} 906 907function writeModuleHashJson(): void { 908 for (let i = 0; i < filterModuleInfos.length; ++i) { 909 const input: string = filterModuleInfos[i].tempFilePath; 910 let outputPath: string = genProtoFileName(filterModuleInfos[i].tempFilePath);; 911 if (!fs.existsSync(input) || !fs.existsSync(outputPath)) { 912 logger.debug(red, `ArkTS:ERROR ${input} is lost`, reset); 913 process.exitCode = FAIL; 914 break; 915 } 916 const hashInputContentData: any = toHashData(input); 917 const hashOutputContentData: any = toHashData(outputPath); 918 moduleHashJsonObject[input] = hashInputContentData; 919 moduleHashJsonObject[outputPath] = hashOutputContentData; 920 } 921 const hashFilePath: string = genHashJsonPath(buildPathInfo); 922 if (hashFilePath.length === 0) { 923 return; 924 } 925 // fix bug of multi trigger 926 fs.writeFileSync(hashFilePath, JSON.stringify(moduleHashJsonObject)); 927} 928 929function filterIntermediateJsBundleByHashJson(buildPath: string, inputPaths: File[]): void { 930 inputPaths = removeDuplicateInfoOfBundleList(inputPaths); 931 932 for (let i = 0; i < inputPaths.length; ++i) { 933 fileterIntermediateJsBundle.push(inputPaths[i]); 934 } 935 const hashFilePath: string = genHashJsonPath(buildPath); 936 if (hashFilePath.length === 0) { 937 return; 938 } 939 const updateJsonObject: any = {}; 940 let jsonObject: any = {}; 941 let jsonFile: string = ''; 942 if (fs.existsSync(hashFilePath)) { 943 jsonFile = fs.readFileSync(hashFilePath).toString(); 944 jsonObject = JSON.parse(jsonFile); 945 fileterIntermediateJsBundle = []; 946 for (let i = 0; i < inputPaths.length; ++i) { 947 const cacheOutputPath: string = inputPaths[i].cacheOutputPath; 948 const cacheAbcFilePath: string = cacheOutputPath.replace(/\.temp\.js$/, '.abc'); 949 if (!fs.existsSync(cacheOutputPath)) { 950 logger.debug(red, `ArkTS:ERROR ${cacheOutputPath} is lost`, reset); 951 process.exitCode = FAIL; 952 break; 953 } 954 if (fs.existsSync(cacheAbcFilePath)) { 955 const hashInputContentData: any = toHashData(cacheOutputPath); 956 const hashAbcContentData: any = toHashData(cacheAbcFilePath); 957 if (jsonObject[cacheOutputPath] === hashInputContentData && jsonObject[cacheAbcFilePath] === hashAbcContentData) { 958 updateJsonObject[cacheOutputPath] = hashInputContentData; 959 updateJsonObject[cacheAbcFilePath] = hashAbcContentData; 960 } else { 961 fileterIntermediateJsBundle.push(inputPaths[i]); 962 } 963 } else { 964 fileterIntermediateJsBundle.push(inputPaths[i]); 965 } 966 } 967 } 968 969 hashJsonObject = updateJsonObject; 970} 971 972function writeHashJson(): void { 973 for (let i = 0; i < fileterIntermediateJsBundle.length; ++i) { 974 const cacheOutputPath: string = fileterIntermediateJsBundle[i].cacheOutputPath; 975 const cacheAbcFilePath: string = cacheOutputPath.replace(/\.temp\.js$/, '.abc'); 976 if (!fs.existsSync(cacheOutputPath) || !fs.existsSync(cacheAbcFilePath)) { 977 logger.debug(red, `ArkTS:ERROR ${cacheOutputPath} is lost`, reset); 978 process.exitCode = FAIL; 979 break; 980 } 981 const hashInputContentData: any = toHashData(cacheOutputPath); 982 const hashAbcContentData: any = toHashData(cacheAbcFilePath); 983 hashJsonObject[cacheOutputPath] = hashInputContentData; 984 hashJsonObject[cacheAbcFilePath] = hashAbcContentData; 985 } 986 const hashFilePath: string = genHashJsonPath(buildPathInfo); 987 if (hashFilePath.length === 0) { 988 return; 989 } 990 fs.writeFileSync(hashFilePath, JSON.stringify(hashJsonObject)); 991} 992 993function genHashJsonPath(buildPath: string): string { 994 buildPath = toUnixPath(buildPath); 995 if (process.env.cachePath) { 996 if (!fs.existsSync(process.env.cachePath) || !fs.statSync(process.env.cachePath).isDirectory()) { 997 logger.debug(red, `ArkTS:ERROR hash path does not exist`, reset); 998 return ''; 999 } 1000 let buildDirArr: string[] = projectConfig.buildPath.split(path.sep); 1001 let abilityDir: string = buildDirArr[buildDirArr.length - 1]; 1002 let hashJsonPath: string = path.join(process.env.cachePath, TEMPORARY, abilityDir, hashFile); 1003 validateFilePathLength(hashJsonPath, logger) 1004 mkdirsSync(path.dirname(hashJsonPath)); 1005 return hashJsonPath; 1006 } else if (buildPath.indexOf(ARK) >= 0) { 1007 const dataTmps: string[] = buildPath.split(ARK); 1008 const hashPath: string = path.join(dataTmps[0], ARK); 1009 if (!fs.existsSync(hashPath) || !fs.statSync(hashPath).isDirectory()) { 1010 logger.debug(red, `ArkTS:ERROR hash path does not exist`, reset); 1011 return ''; 1012 } 1013 let hashJsonPath: string = path.join(hashPath, hashFile); 1014 validateFilePathLength(hashJsonPath, logger); 1015 return hashJsonPath; 1016 } else { 1017 logger.debug(red, `ArkTS:ERROR not cache exist`, reset); 1018 return ''; 1019 } 1020} 1021 1022function checkNodeModules() { 1023 if (process.env.panda === TS2ABC) { 1024 let arkEntryPath: string = path.join(arkDir, 'build'); 1025 if (isWin) { 1026 arkEntryPath = path.join(arkDir, 'build-win'); 1027 } else if (isMac) { 1028 arkEntryPath = path.join(arkDir, 'build-mac'); 1029 } 1030 let nodeModulesPath: string = path.join(arkEntryPath, NODE_MODULES); 1031 validateFilePathLength(nodeModulesPath, logger); 1032 if (!(fs.existsSync(nodeModulesPath) && fs.statSync(nodeModulesPath).isDirectory())) { 1033 logger.error(red, `ERROR: node_modules for ark compiler not found. 1034 Please make sure switch to non-root user before runing "npm install" for safity requirements and try re-run "npm install" under ${arkEntryPath}`, reset); 1035 return false; 1036 } 1037 } 1038 1039 return true; 1040} 1041 1042function copyFileCachePathToBuildPath() { 1043 for (let i = 0; i < intermediateJsBundle.length; ++i) { 1044 const abcFile: string = intermediateJsBundle[i].path.replace(/\.temp\.js$/, ".abc"); 1045 const cacheOutputPath: string = intermediateJsBundle[i].cacheOutputPath; 1046 const cacheAbcFilePath: string = intermediateJsBundle[i].cacheOutputPath.replace(/\.temp\.js$/, ".abc"); 1047 if (!fs.existsSync(cacheAbcFilePath)) { 1048 logger.debug(red, `ArkTS:ERROR ${cacheAbcFilePath} is lost`, reset); 1049 process.exitCode = FAIL; 1050 break; 1051 } 1052 let parent: string = path.join(abcFile, '..'); 1053 if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) { 1054 mkDir(parent); 1055 } 1056 // for preview mode, cache path and old abc file both exist, should copy abc file for updating 1057 if (process.env.cachePath !== undefined) { 1058 fs.copyFileSync(cacheAbcFilePath, abcFile); 1059 } 1060 if (process.env.cachePath === undefined && fs.existsSync(cacheOutputPath)) { 1061 fs.unlinkSync(cacheOutputPath); 1062 } 1063 } 1064} 1065 1066function processExtraAsset() { 1067 if (projectConfig.compileMode === JSBUNDLE || projectConfig.compileMode === undefined) { 1068 writeHashJson(); 1069 copyFileCachePathToBuildPath(); 1070 } else if (projectConfig.compileMode === ESMODULE) { 1071 processEntryToGenAbc(entryInfos); 1072 writeModuleHashJson(); 1073 copyModuleFileCachePathToBuildPath(); 1074 mergeProtoToAbc(); 1075 } 1076 clearGlobalInfo(); 1077} 1078 1079function handleHotReloadChangedFiles() { 1080 if (!fs.existsSync(projectConfig.changedFileList)) { 1081 logger.debug(blue, `ArkTS: Cannot find file: ${projectConfig.changedFileList}, skip hot reload build`, reset); 1082 return; 1083 } 1084 1085 let changedFileListJson: string = fs.readFileSync(projectConfig.changedFileList).toString(); 1086 let changedFileList: Array<string> = JSON.parse(changedFileListJson).modifiedFiles; 1087 if (typeof(changedFileList) == "undefined" || changedFileList.length == 0) { 1088 return; 1089 } 1090 1091 let relativeProjectPath = projectConfig.projectPath.slice(projectConfig.projectRootPath.length + path.sep.length); 1092 const nodeModulesFile: Array<string> = []; 1093 let hotReloadSourceMap: Object = {}; 1094 moduleInfos = []; 1095 1096 for (let file of changedFileList) { 1097 let filePath: string = path.join(projectConfig.projectPath, file); 1098 validateFilePathLength(filePath, logger); 1099 let tempFilePath: string = genTemporaryPath(filePath, projectConfig.projectPath, process.env.cachePath, projectConfig); 1100 if (tempFilePath.length === 0) { 1101 return; 1102 } 1103 validateFilePathLength(tempFilePath, logger); 1104 let buildFilePath: string = ""; 1105 tempFilePath = toUnixPath(tempFilePath); 1106 1107 switch (path.extname(filePath)) { 1108 case EXTNAME_ETS: { 1109 processEtsModule(filePath, tempFilePath, buildFilePath, nodeModulesFile, undefined); 1110 break; 1111 } 1112 case EXTNAME_TS: { 1113 processTsModule(filePath, tempFilePath, buildFilePath, nodeModulesFile, undefined); 1114 break; 1115 } 1116 case EXTNAME_JS: 1117 case EXTNAME_MJS: 1118 case EXTNAME_CJS: { 1119 processJsModule(filePath, tempFilePath, buildFilePath, nodeModulesFile, undefined); 1120 break; 1121 } 1122 case EXTNAME_JSON: { 1123 logger.debug(blue, `ArkTS: json source file: ${filePath} changed, skip hot reload build`, reset); 1124 return; 1125 } 1126 default: { 1127 logger.debug(blue, `ArkTS:ERROR Cannot resolve file path: ${filePath}, stop hot reload build`, reset); 1128 return; 1129 } 1130 } 1131 1132 let sourceMapPath: string = toUnixPath(path.join(relativeProjectPath, file)); 1133 validateFilePathLength(sourceMapPath, logger); 1134 hotReloadSourceMap[sourceMapPath] = newSourceMaps[sourceMapPath]; 1135 } 1136 1137 if (!fs.existsSync(projectConfig.patchAbcPath)) { 1138 mkdirsSync(projectConfig.patchAbcPath); 1139 } 1140 1141 const outputABCPath: string = path.join(projectConfig.patchAbcPath, MODULES_ABC); 1142 validateFilePathLength(outputABCPath, logger); 1143 generateMergedAbc(moduleInfos, entryInfos, outputABCPath); 1144 1145 // write source maps 1146 let sourceMapFilePath: string = path.join(projectConfig.patchAbcPath, SOURCEMAPS); 1147 validateFilePathLength(sourceMapFilePath, logger); 1148 fs.writeFileSync(sourceMapFilePath, 1149 JSON.stringify(hotReloadSourceMap, null, 2), 'utf-8'); 1150} 1151 1152function handleFinishModules(modules, callback) { 1153 if (projectConfig.hotReload && !isHotReloadFirstBuild) { 1154 handleHotReloadChangedFiles(); 1155 return; 1156 } 1157 1158 handleFullModuleFiles(modules, callback); 1159 1160 if (projectConfig.hotReload) { 1161 isHotReloadFirstBuild = false; 1162 } 1163} 1164 1165function copyModuleFileCachePathToBuildPath(): void { 1166 protoFilePath = path.join(process.env.cachePath, "protos", PROTO_FILESINFO_TXT); 1167 validateFilePathLength(protoFilePath, logger); 1168 mkdirsSync(path.dirname(protoFilePath)); 1169 let entriesInfo: string = ''; 1170 moduleInfos = removeDuplicateInfo(moduleInfos); 1171 moduleInfos.sort((m1: ModuleInfo, m2: ModuleInfo) => { 1172 return m1.tempFilePath < m2.tempFilePath ? 1 : -1; 1173 }); 1174 for (let i = 0; i < moduleInfos.length; ++i) { 1175 let protoTempPath: string = genProtoFileName(moduleInfos[i].tempFilePath); 1176 entriesInfo += `${toUnixPath(protoTempPath)}\n`; 1177 } 1178 if (entryInfos.size > 0) { 1179 let npmEntriesProtoFileName: string = "npm_entries" + EXTNAME_PROTO_BIN; 1180 const npmEntriesProtoFilePath: string = path.join(process.env.cachePath, "protos", "npm_entries", npmEntriesProtoFileName); 1181 entriesInfo += `${toUnixPath(npmEntriesProtoFilePath)}\n`; 1182 } 1183 fs.writeFileSync(protoFilePath, entriesInfo, 'utf-8'); 1184} 1185 1186function mergeProtoToAbc(): void { 1187 let mergeAbc: string = path.join(arkDir, 'build', 'bin', 'merge_abc'); 1188 if (isWin) { 1189 mergeAbc = path.join(arkDir, 'build-win', 'bin', 'merge_abc.exe'); 1190 } else if (isMac) { 1191 mergeAbc = path.join(arkDir, 'build-mac', 'bin', 'merge_abc'); 1192 } 1193 mkdirsSync(projectConfig.buildPath); 1194 const singleCmd: any = `"${mergeAbc}" --input "@${protoFilePath}" --outputFilePath "${projectConfig.buildPath}" --output ${MODULES_ABC} --suffix protoBin`; 1195 try { 1196 childProcess.execSync(singleCmd); 1197 } catch (e) { 1198 logger.debug(red, `ArkTS:ERROR Failed to merge proto file to abc. Error message: ${e}`, reset); 1199 } 1200} 1201 1202function generateAbcByEs2AbcOfBundleMode(inputPaths: File[]) { 1203 filterIntermediateJsBundleByHashJson(buildPathInfo, inputPaths); 1204 if (fileterIntermediateJsBundle.length === 0) { 1205 processExtraAsset(); 1206 return; 1207 } 1208 let filesInfoPath = generateFileOfBundle(fileterIntermediateJsBundle); 1209 const fileThreads = os.cpus().length < 16 ? os.cpus().length : 16; 1210 let genAbcCmd: string = 1211 `${initAbcEnv().join(' ')} "@${filesInfoPath}" --file-threads "${fileThreads}"`; 1212 logger.debug('gen abc cmd is: ', genAbcCmd); 1213 try { 1214 if (process.env.watchMode === 'true') { 1215 childProcess.execSync(genAbcCmd); 1216 processExtraAsset(); 1217 } else { 1218 const child = childProcess.exec(genAbcCmd); 1219 child.on('exit', (code: any) => { 1220 if (code === FAIL) { 1221 logger.debug(red, "ArkTS:ERROR failed to execute es2abc", reset); 1222 process.exit(FAIL); 1223 } 1224 if (process.env.cachePath === undefined) { 1225 unlinkSync(filesInfoPath); 1226 } 1227 processExtraAsset(); 1228 }); 1229 1230 child.on('error', (err: any) => { 1231 logger.debug(red, err.toString(), reset); 1232 process.exit(FAIL); 1233 }); 1234 1235 child.stderr.on('data', (data: any) => { 1236 logger.error(red, data.toString(), reset); 1237 }); 1238 } 1239 } catch (e) { 1240 logger.debug(red, `ArkTS:ERROR failed to generate abc with filesInfo ${filesInfoPath}. Error message: ${e} `, reset); 1241 process.env.abcCompileSuccess = 'false'; 1242 if (process.env.watchMode !== 'true') { 1243 process.exit(FAIL); 1244 } 1245 } finally { 1246 if (process.env.watchMode === 'true') { 1247 if (process.env.cachePath === undefined) { 1248 unlinkSync(filesInfoPath); 1249 } 1250 } 1251 } 1252} 1253 1254function generateFileOfBundle(inputPaths: File[]) { 1255 let filesInfoPath: string = buildCachePath(FILESINFO_TXT, projectConfig, Logger); 1256 inputPaths = removeDuplicateInfoOfBundleList(inputPaths); 1257 1258 let filesInfo: string = ''; 1259 inputPaths.forEach(info => { 1260 const cacheOutputPath: string = info.cacheOutputPath; 1261 const recordName: string = 'null_recordName'; 1262 const moduleType: string = 'script'; 1263 const sourceFile: string = info.sourceFile; 1264 const abcFilePath: string = cacheOutputPath.replace(/\.temp\.js$/, ".abc"); 1265 filesInfo += `${cacheOutputPath};${recordName};${moduleType};${sourceFile};${abcFilePath}\n`; 1266 }); 1267 fs.writeFileSync(filesInfoPath, filesInfo, 'utf-8'); 1268 1269 return filesInfoPath; 1270} 1271 1272function removeDuplicateInfoOfBundleList(inputPaths: File[]) { 1273 const tempInputPaths = Array<File>(); 1274 inputPaths.forEach((item) => { 1275 const check = tempInputPaths.every((newItem) => { 1276 return item.path !== newItem.path; 1277 }); 1278 if (check) { 1279 tempInputPaths.push(item); 1280 } 1281 }); 1282 inputPaths = tempInputPaths; 1283 1284 return inputPaths; 1285} 1286 1287function processWorkersOfPreviewMode(splittedData: any, cmdPrefix: string, workerNumber: number) { 1288 let processEnv: any = Object.assign({}, process.env); 1289 let arkEnvParams: any = { 1290 'splittedData': JSON.stringify(splittedData), 1291 'cmdPrefix': cmdPrefix, 1292 'workerNumber': workerNumber.toString(), 1293 }; 1294 if (projectConfig.compileMode === JSBUNDLE || projectConfig.compileMode === undefined) { 1295 arkEnvParams['mode'] = JSBUNDLE; 1296 } else if (projectConfig.compileMode === ESMODULE) { 1297 arkEnvParams['cachePath'] = process.env.cachePath; 1298 arkEnvParams['mode'] = ESMODULE; 1299 } 1300 processEnv.arkEnvParams = JSON.stringify(arkEnvParams); 1301 1302 let genAbcCmd: string = `${nodeJs} "${path.resolve(__dirname, MANAGE_WORKERS_SCRIPT)}"`; 1303 childProcess.execSync(genAbcCmd, {env: processEnv}); 1304 processExtraAsset(); 1305} 1306 1307function processWorkersOfBuildMode(splittedData: any, cmdPrefix: string, workerNumber: number) { 1308 const useNewApi: boolean = nodeLargeOrEqualTargetVersion(16); 1309 1310 if (useNewApi && cluster.isPrimary || !useNewApi && cluster.isMaster) { 1311 let genAbcScript: string = GEN_ABC_SCRIPT; 1312 if (projectConfig.compileMode === ESMODULE) { 1313 genAbcScript = GEN_MODULE_ABC_SCRIPT; 1314 } 1315 if (useNewApi) { 1316 cluster.setupPrimary({ 1317 exec: path.resolve(__dirname, genAbcScript) 1318 }); 1319 } else { 1320 cluster.setupMaster({ 1321 exec: path.resolve(__dirname, genAbcScript) 1322 }); 1323 } 1324 1325 for (let i = 0; i < workerNumber; ++i) { 1326 let workerData: any = { 1327 'inputs': JSON.stringify(splittedData[i]), 1328 'cmd': cmdPrefix 1329 }; 1330 if (projectConfig.compileMode === ESMODULE) { 1331 let sn: number = i + 1; 1332 let workerFileName: string = `filesInfo_${sn}.txt`; 1333 workerData['workerFileName'] = workerFileName; 1334 workerData['cachePath'] = process.env.cachePath; 1335 } 1336 cluster.fork(workerData); 1337 } 1338 1339 cluster.on('exit', (worker, code, signal) => { 1340 if (code === FAIL) { 1341 process.exitCode = FAIL; 1342 } 1343 logger.debug(`worker ${worker.process.pid} finished`); 1344 }); 1345 1346 process.on('exit', (code) => { 1347 if (process.exitCode !== FAIL && process.env.watchMode !== 'true') { 1348 processExtraAsset(); 1349 if (projectConfig.compileMode === ESMODULE && 1350 (projectConfig.anBuildMode === AOT_FULL || projectConfig.anBuildMode === AOT_PARTIAL)) { 1351 let faultHandler: FaultHandler = (error) => { logger.error(error); process.exit(FAIL); } 1352 let abcArgs: string[] = initAbcEnv(); 1353 abcArgs.unshift(nodeJs); 1354 const builtinAbcPath: string = generateBuiltinAbc(arkDir, abcArgs, process.env.cachePath, logger, faultHandler); 1355 generateAot(arkDir, builtinAbcPath, projectConfig, logger, faultHandler); 1356 } 1357 } 1358 }); 1359 } 1360} 1361