diff --git a/compiler/main.js b/compiler/main.js index 5d56baa..d9de016 100644 --- a/compiler/main.js +++ b/compiler/main.js @@ -374,6 +374,7 @@ function loadModuleInfo(projectConfig, envArgs) { projectConfig.modulePathMap = buildJsonInfo.modulePathMap; projectConfig.isOhosTest = buildJsonInfo.isOhosTest; projectConfig.processTs = false; + projectConfig.processMergeabc = false; projectConfig.buildArkMode = envArgs.buildMode; if (buildJsonInfo.compileMode === 'esmodule') { projectConfig.nodeModulesPath = buildJsonInfo.nodeModulesPath; diff --git a/compiler/src/gen_abc.ts b/compiler/src/gen_abc.ts index 83f79f8..0ba2c02 100644 --- a/compiler/src/gen_abc.ts +++ b/compiler/src/gen_abc.ts @@ -15,7 +15,6 @@ import * as childProcess from 'child_process'; import * as process from 'process'; -import * as fs from 'fs'; import cluster from 'cluster'; import { logger } from './compile_info'; import { diff --git a/compiler/src/gen_abc_plugin.ts b/compiler/src/gen_abc_plugin.ts index 196d489..4090838 100644 --- a/compiler/src/gen_abc_plugin.ts +++ b/compiler/src/gen_abc_plugin.ts @@ -44,14 +44,16 @@ import { EXTNAME_MJS, EXTNAME_CJS, EXTNAME_D_TS, - EXTNAME_ABC, FAIL, EXTNAME_JS_MAP, TS2ABC, ES2ABC, TEMPORARY, - SUCCESS + SUCCESS, + MODULELIST_JSON } from './pre_define'; +import { getOhmUrlByFilepath } from './resolve_ohm_url'; +import { generateMergedAbc } from './gen_merged_abc'; const genAbcScript: string = 'gen_abc.js'; const genModuleAbcScript: string = 'gen_module_abc.js'; @@ -78,6 +80,7 @@ let entryInfos: Map = new Map(); let hashJsonObject = {}; let moduleHashJsonObject = {}; let buildPathInfo: string = ''; +let buildMapFileList: Array = []; const red: string = '\u001b[31m'; const reset: string = '\u001b[39m'; @@ -85,12 +88,13 @@ const blue = '\u001b[34m'; const hashFile: string = 'gen_hash.json'; const ARK: string = '/ark/'; -class ModuleInfo { +export class ModuleInfo { filePath: string; tempFilePath: string; buildFilePath: string; abcFilePath: string; isCommonJs: boolean; + recordName: string; constructor(filePath: string, tempFilePath: string, buildFilePath: string, abcFilePath: string, isCommonJs: boolean) { this.filePath = filePath; @@ -98,10 +102,11 @@ class ModuleInfo { this.buildFilePath = buildFilePath; this.abcFilePath = abcFilePath; this.isCommonJs = isCommonJs; + this.recordName = getOhmUrlByFilepath(filePath); } } -class EntryInfo { +export class EntryInfo { npmInfo: string; abcFileName: string; buildPath: string; @@ -142,9 +147,15 @@ export class GenAbcPlugin { return; } + // case ESMODULE + // | --- merge -- debug -- not removeDir + // | --- merge -- release -- removeDir + // | --- unmerge -- removeDir if (projectConfig.compileMode === ESMODULE) { - removeDir(output); - removeDir(projectConfig.nodeModulesPath); + if (!projectConfig.processMergeabc || projectConfig.buildArkMode !== 'debug') { + removeDir(output); + removeDir(projectConfig.nodeModulesPath); + } } compiler.hooks.compilation.tap('GenAbcPlugin', (compilation) => { @@ -254,8 +265,7 @@ function processNodeModulesFile(filePath: string, tempFilePath: string, buildFil moduleInfos.push(tempModuleInfo); nodeModulesFile.push(tempFilePath); } - - return; + buildMapFileList.push(genSourceMapFileName(buildFilePath)); } function processEtsModule(filePath: string, tempFilePath: string, buildFilePath: string, nodeModulesFile: Array, module: any): void { @@ -273,6 +283,7 @@ function processEtsModule(filePath: string, tempFilePath: string, buildFilePath: const tempModuleInfo: ModuleInfo = new ModuleInfo(filePath, tempFilePath, buildFilePath, abcFilePath, false); moduleInfos.push(tempModuleInfo); } + buildMapFileList.push(genSourceMapFileName(buildFilePath)); } function processDtsModule(filePath: string, tempFilePath: string, buildFilePath: string, nodeModulesFile: Array, module: any): void { @@ -291,6 +302,7 @@ function processTsModule(filePath: string, tempFilePath: string, buildFilePath: const tempModuleInfo: ModuleInfo = new ModuleInfo(filePath, tempFilePath, buildFilePath, abcFilePath, false); moduleInfos.push(tempModuleInfo); } + buildMapFileList.push(genSourceMapFileName(buildFilePath)); } function processJsModule(filePath: string, tempFilePath: string, buildFilePath: string, nodeModulesFile: Array, module: any): void { @@ -308,6 +320,39 @@ function processJsModule(filePath: string, tempFilePath: string, buildFilePath: const tempModuleInfo: ModuleInfo = new ModuleInfo(filePath, tempFilePath, buildFilePath, abcFilePath, false); moduleInfos.push(tempModuleInfo); } + buildMapFileList.push(genSourceMapFileName(buildFilePath)); +} + + +function getCachedModuleList(): Array { + const CACHED_MODULELIST_FILE: string = path.join(process.env.cachePath, MODULELIST_JSON); + if (!fs.existsSync(CACHED_MODULELIST_FILE)) { + return []; + } + const data: any = JSON.parse(fs.readFileSync(CACHED_MODULELIST_FILE).toString()); + const moduleList: Array = data.list; + return moduleList; +} + +function updateCachedModuleList(moduleList: Array): void { + const CACHED_MODULELIST_FILE: string = path.join(process.env.cachePath, MODULELIST_JSON); + let cachedJson: Object = {}; + cachedJson["list"] = moduleList; + fs.writeFile(CACHED_MODULELIST_FILE, JSON.stringify(cachedJson, null, 2), 'utf-8', + (err)=>{ + if (err) { + logger.error(red, `ETS:ERROR Failed to write module list.`, reset); + } + } + ); +} + +function eliminateUnusedFiles(moduleList: Array): void{ + let cachedModuleList: Array = getCachedModuleList(); + if (cachedModuleList.length !== 0) { + const eliminateFiles: Array = cachedModuleList.filter(m => !moduleList.includes(m)); + eliminateFiles.forEach((file) => {fs.unlinkSync(file);}); + } } function handleFinishModules(modules, callback): any { @@ -337,8 +382,16 @@ function handleFinishModules(modules, callback): any { } }); - judgeModuleWorkersToGenAbc(invokeWorkersModuleToGenAbc); - processEntryToGenAbc(entryInfos); + if (projectConfig.processMergeabc) { + if (projectConfig.buildArkMode === 'debug') { + eliminateUnusedFiles(buildMapFileList); + updateCachedModuleList(buildMapFileList); + } + generateMergedAbc(moduleInfos, entryInfos); + } else { + judgeModuleWorkersToGenAbc(invokeWorkersModuleToGenAbc); + processEntryToGenAbc(entryInfos); + } } function processEntryToGenAbc(entryInfos: Map): void { @@ -433,7 +486,7 @@ function invokeWorkersModuleToGenAbc(moduleInfos: Array): void { invokeCluterModuleToAbc(); } -function initAbcEnv() : string[] { +export function initAbcEnv() : string[] { let args: string[] = []; if (process.env.panda === TS2ABC) { let js2abc: string = path.join(arkDir, 'build', 'src', 'index.js'); @@ -465,6 +518,9 @@ function initAbcEnv() : string[] { if (isDebug) { args.push('--debug-info'); } + if (projectConfig.processMergeabc) { + args.push('--merge-abc'); + } } else { logger.error(red, `ETS:ERROR please set panda module`, reset); } @@ -701,18 +757,18 @@ function filterIntermediateModuleByHashJson(buildPath: string, moduleInfos: Arra filterModuleInfos = []; for (let i = 0; i < moduleInfos.length; ++i) { const input: string = moduleInfos[i].tempFilePath; - const abcPath: string = moduleInfos[i].abcFilePath; + let outputPath: string = moduleInfos[i].abcFilePath; if (!fs.existsSync(input)) { logger.error(red, `ETS:ERROR ${input} is lost`, reset); process.exitCode = FAIL; break; } - if (fs.existsSync(abcPath)) { + if (fs.existsSync(outputPath)) { const hashInputContentData: any = toHashData(input); - const hashAbcContentData: any = toHashData(abcPath); - if (jsonObject[input] === hashInputContentData && jsonObject[abcPath] === hashAbcContentData) { + const hashAbcContentData: any = toHashData(outputPath); + if (jsonObject[input] === hashInputContentData && jsonObject[outputPath] === hashAbcContentData) { updateJsonObject[input] = hashInputContentData; - updateJsonObject[abcPath] = hashAbcContentData; + updateJsonObject[outputPath] = hashAbcContentData; mkdirsSync(path.dirname(moduleInfos[i].buildFilePath)); if (projectConfig.buildArkMode === 'debug' && fs.existsSync(moduleInfos[i].tempFilePath)) { fs.copyFileSync(moduleInfos[i].tempFilePath, moduleInfos[i].buildFilePath); @@ -736,16 +792,16 @@ function filterIntermediateModuleByHashJson(buildPath: string, moduleInfos: Arra function writeModuleHashJson(): void { for (let i = 0; i < filterModuleInfos.length; ++i) { const input: string = filterModuleInfos[i].tempFilePath; - const abcPath: string = filterModuleInfos[i].abcFilePath; - if (!fs.existsSync(input) || !fs.existsSync(abcPath)) { + let outputPath: string = filterModuleInfos[i].abcFilePath; + if (!fs.existsSync(input) || !fs.existsSync(outputPath)) { logger.error(red, `ETS:ERROR ${input} is lost`, reset); process.exitCode = FAIL; break; } const hashInputContentData: any = toHashData(input); - const hashAbcContentData: any = toHashData(abcPath); + const hashAbcContentData: any = toHashData(outputPath); moduleHashJsonObject[input] = hashInputContentData; - moduleHashJsonObject[abcPath] = hashAbcContentData; + moduleHashJsonObject[outputPath] = hashAbcContentData; mkdirsSync(path.dirname(filterModuleInfos[i].buildFilePath)); if (projectConfig.buildArkMode === 'debug' && fs.existsSync(filterModuleInfos[i].tempFilePath)) { fs.copyFileSync(filterModuleInfos[i].tempFilePath, filterModuleInfos[i].buildFilePath); @@ -909,4 +965,4 @@ function processExtraAssetForBundle() { writeHashJson(); copyFileCachePathToBuildPath(); clearGlobalInfo(); -} \ No newline at end of file +} diff --git a/compiler/src/gen_merged_abc.ts b/compiler/src/gen_merged_abc.ts new file mode 100644 index 0000000..974eb3a --- /dev/null +++ b/compiler/src/gen_merged_abc.ts @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as fs from 'fs'; +import * as path from 'path'; +import * as os from 'os'; +import * as childProcess from 'child_process'; +import * as process from 'process'; +import { logger } from './compile_info'; +import { projectConfig } from '../main'; +import { + FAIL, + FILESINFO_TXT, + MODULES_ABC, + MODULES_CACHE, + NPMENTRIES_TXT, + NODE_MODULES +} from './pre_define'; +import { EntryInfo, ModuleInfo, initAbcEnv } from './gen_abc_plugin'; +import { mkdirsSync, toUnixPath } from './utils'; + +const red: string = '\u001b[31m'; +const reset: string = '\u001b[39m'; + +function generateCompileFilesInfo(moduleInfos: Array) { + const filesInfoPath: string = path.join(process.env.cachePath, FILESINFO_TXT); + let filesInfo: string = ''; + moduleInfos.forEach(info => { + const moduleType: string = info.isCommonJs ? 'cjs' : 'esm'; + filesInfo += `${info.tempFilePath};${info.recordName};${moduleType}\n`; + }); + fs.writeFileSync(filesInfoPath, filesInfo, 'utf-8'); +} + +function generateNpmEntriesInfo(entryInfos: Map) { + const npmEntriesInfoPath: string = path.join(process.env.cachePath, NPMENTRIES_TXT); + let entriesInfo: string = ''; + for (const value of entryInfos.values()) { + const buildPath: string = value.buildPath.replace(toUnixPath(projectConfig.nodeModulesPath), ''); + const entryFile: string = toUnixPath(path.join(buildPath, value.entry)); + const entry: string = entryFile.substring(0, entryFile.lastIndexOf('.')); + entriesInfo += + `${toUnixPath(path.join(NODE_MODULES, buildPath))}:${toUnixPath(path.join(NODE_MODULES, entry))}\n`; + } + fs.writeFileSync(npmEntriesInfoPath, entriesInfo, 'utf-8'); +} + +export function generateMergedAbc(moduleInfos: Array, entryInfos: Map) { + generateCompileFilesInfo(moduleInfos); + generateNpmEntriesInfo(entryInfos); + + const filesInfoPath: string = path.join(process.env.cachePath, FILESINFO_TXT); + const npmEntriesInfoPath: string = path.join(process.env.cachePath, NPMENTRIES_TXT); + const cacheFilePath: string = path.join(process.env.cachePath, MODULES_CACHE); + const outputABCPath: string = path.join(projectConfig.buildPath, MODULES_ABC); + const fileThreads = os.cpus().length < 16 ? os.cpus().length : 16; + mkdirsSync(projectConfig.buildPath); + const gen_abc_cmd: string = + `${initAbcEnv().join(' ')} "@${filesInfoPath}" --npm-module-entry-list "${npmEntriesInfoPath}" --cache-file "${cacheFilePath}" --output "${outputABCPath}" --file-threads "${fileThreads}"`; + logger.debug('gen abc cmd is: ', gen_abc_cmd); + try { + const child = childProcess.exec(gen_abc_cmd); + child.on('exit', (code: any) => { + if (code === 1) { + logger.error(red, "ETS:ERROR failed to execute es2abc", reset); + } + }); + + child.on('error', (err: any) => { + logger.error(red, err.toString(), reset); + }); + } catch (e) { + logger.error(red, `ETS:ERROR failed to generate abc with filesInfo ${filesInfoPath} `, reset); + process.exit(FAIL); + } +} \ No newline at end of file diff --git a/compiler/src/pre_define.ts b/compiler/src/pre_define.ts index a1698ab..39439a7 100644 --- a/compiler/src/pre_define.ts +++ b/compiler/src/pre_define.ts @@ -243,9 +243,15 @@ export const COMPONENT_TOGGLE: string = 'Toggle'; export const TTOGGLE_CHECKBOX: string = 'Checkbox'; export const TOGGLE_SWITCH: string = 'Switch'; +export const ENTRY_TXT: string = 'entry.txt'; +export const FILESINFO_TXT: string = 'filesInfo.txt'; +export const NPMENTRIES_TXT: string = 'npmEntries.txt'; +export const MODULES_CACHE: string = 'modules.cache'; +export const MODULES_ABC: string = 'modules.abc'; +export const MODULELIST_JSON: string = 'moduleList.json'; + export const ESMODULE: string = 'esmodule'; export const JSBUNDLE: string = 'jsbundle'; -export const ENTRY_TXT: string = 'entry.txt'; export const ARK: string = 'ark'; export const TEMPORARY: string = 'temporary'; export const MAIN: string = 'main'; @@ -260,6 +266,7 @@ export const EXTNAME_MJS: string = '.mjs'; export const EXTNAME_CJS: string = '.cjs'; export const EXTNAME_D_TS: string = '.d.ts'; export const EXTNAME_ABC: string = '.abc'; +export const EXTNAME_PROTO_BIN: string = '.protoBin'; export const SUCCESS: number = 0; export const FAIL: number = 1; diff --git a/compiler/src/process_js_ast.ts b/compiler/src/process_js_ast.ts index 8b94e5c..5407024 100644 --- a/compiler/src/process_js_ast.ts +++ b/compiler/src/process_js_ast.ts @@ -17,13 +17,13 @@ import ts from 'typescript'; import { BUILD_ON } from './pre_define'; -import { writeFileSyncByNode } from './utils'; +import { generateSourceFilesToTemporary } from './utils'; export function processJs(program: ts.Program, ut = false): Function { return (context: ts.TransformationContext) => { return (node: ts.SourceFile) => { if (process.env.compiler === BUILD_ON) { - writeFileSyncByNode(node, false); + generateSourceFilesToTemporary(node); return node; } else { return node; diff --git a/compiler/src/process_js_file.ts b/compiler/src/process_js_file.ts index 1eaec24..982bfd2 100644 --- a/compiler/src/process_js_file.ts +++ b/compiler/src/process_js_file.ts @@ -8,7 +8,7 @@ import { module.exports = function processjs2file(source: string): string { if (projectConfig.compileMode === ESMODULE && projectConfig.processTs === false && process.env.compilerType && process.env.compilerType === ARK) { - writeFileSyncByString(this.resourcePath, source, false); + writeFileSyncByString(this.resourcePath, source); } return source; }; diff --git a/compiler/src/resolve_ohm_url.ts b/compiler/src/resolve_ohm_url.ts index f40c7d3..463a6f2 100644 --- a/compiler/src/resolve_ohm_url.ts +++ b/compiler/src/resolve_ohm_url.ts @@ -1,6 +1,8 @@ import * as fs from 'fs'; import * as path from 'path'; import { logger } from './compile_info'; +import { NODE_MODULES, ONE, ZERO } from './pre_define'; +import { toUnixPath, getPackageInfo } from './utils'; const { projectConfig } = require('../main'); const red: string = '\u001b[31m'; @@ -86,3 +88,40 @@ export function resolveSourceFile(ohmUrl: string): string { return file; } + +export function getOhmUrlByFilepath(filePath: string): string { + let unixFilePath: string = toUnixPath(filePath); + unixFilePath = unixFilePath.substring(0, filePath.lastIndexOf('.')); // remove extension + const REG_PROJECT_SRC: RegExp = /(\S+)\/src\/(?:main|ohosTest)\/(ets|js)\/(\S+)/; + + const packageInfo: string[] = getPackageInfo(projectConfig.aceModuleJsonPath); + const bundleName: string = packageInfo[0]; + const moduleName: string = packageInfo[1]; + const moduleRootPath: string = toUnixPath(projectConfig.modulePathMap[moduleName]); + const projectRootPath: string = toUnixPath(projectConfig.projectRootPath); + // case1: /entry/src/main/ets/xxx/yyy + // case2: /node_modules/xxx/yyy + // case3: /entry/node_modules/xxx/yyy + const projectFilePath: string = unixFilePath.replace(projectRootPath, ''); + + const result: RegExpMatchArray | null = projectFilePath.match(REG_PROJECT_SRC); + if (result && result[1].indexOf(NODE_MODULES) === -1) { + return `${bundleName}/${moduleName}/${result[2]}/${result[3]}`; + } + + if (projectFilePath.indexOf(NODE_MODULES) !== -1) { + + const tryProjectNPM: string = toUnixPath(path.join(projectRootPath, NODE_MODULES)); + if (unixFilePath.indexOf(tryProjectNPM) !== -1) { + return unixFilePath.replace(tryProjectNPM, `${NODE_MODULES}/${ONE}`); + } + + const tryModuleNPM: string = toUnixPath(path.join(moduleRootPath, NODE_MODULES)); + if (unixFilePath.indexOf(tryModuleNPM) !== -1) { + return unixFilePath.replace(tryModuleNPM, `${NODE_MODULES}/${ZERO}`); + } + } + + logger.error(red, `ETS:ERROR Failed to get an resolved OhmUrl by filepath "${filePath}"`, reset); + return filePath; +} \ No newline at end of file diff --git a/compiler/src/utils.ts b/compiler/src/utils.ts index 4a1a473..271ef17 100644 --- a/compiler/src/utils.ts +++ b/compiler/src/utils.ts @@ -33,7 +33,8 @@ import { EXTNAME_ABC, EXTNAME_ETS, EXTNAME_TS_MAP, - EXTNAME_JS_MAP + EXTNAME_JS_MAP, + ESMODULE } from './pre_define'; export enum LogType { @@ -261,7 +262,7 @@ export function writeFileSync(filePath: string, content: string): void { fs.writeFileSync(filePath, content); } -export function genTemporaryPath(filePath: string, projectPath: string, buildPath: string, toTsFile: boolean = true): string { +export function genTemporaryPath(filePath: string, projectPath: string, buildPath: string): string { filePath = toUnixPath(filePath); if (filePath.endsWith(EXTNAME_MJS)) { filePath = filePath.replace(/\.mjs$/, EXTNAME_JS); @@ -270,19 +271,17 @@ export function genTemporaryPath(filePath: string, projectPath: string, buildPat filePath = filePath.replace(/\.cjs$/, EXTNAME_JS); } projectPath = toUnixPath(projectPath); - const hapPath: string = toUnixPath(projectConfig.projectRootPath); - const tempFilePath: string = filePath.replace(hapPath, ''); if (checkNodeModulesFile(filePath, projectPath)) { - const fakeNodeModulesPath: string = toUnixPath(path.resolve(projectConfig.projectRootPath, NODE_MODULES)); - const dataTmps: string[] = tempFilePath.split(NODE_MODULES); + const fakeNodeModulesPath: string = toUnixPath(path.join(projectConfig.projectRootPath, NODE_MODULES)); let output: string = ''; if (filePath.indexOf(fakeNodeModulesPath) === -1) { - const sufStr: string = dataTmps[dataTmps.length - 1]; + const hapPath: string = toUnixPath(projectConfig.projectRootPath); + const tempFilePath: string = filePath.replace(hapPath, ''); + const sufStr: string = tempFilePath.substring(tempFilePath.indexOf(NODE_MODULES) + NODE_MODULES.length + 1); output = path.join(buildPath, TEMPORARY, NODE_MODULES, MAIN, sufStr); } else { - const sufStr: string = dataTmps[dataTmps.length - 1]; - output = path.join(buildPath, TEMPORARY, NODE_MODULES, AUXILIARY, sufStr); + output = filePath.replace(fakeNodeModulesPath, path.join(buildPath, TEMPORARY, NODE_MODULES, AUXILIARY)); } return output; } @@ -296,7 +295,7 @@ export function genTemporaryPath(filePath: string, projectPath: string, buildPat return ''; } -export function genBuildPath(filePath: string, projectPath: string, buildPath: string, toTsFile: boolean = true): string { +export function genBuildPath(filePath: string, projectPath: string, buildPath: string): string { filePath = toUnixPath(filePath); if (filePath.endsWith(EXTNAME_MJS)) { filePath = filePath.replace(/\.mjs$/, EXTNAME_JS); @@ -305,20 +304,18 @@ export function genBuildPath(filePath: string, projectPath: string, buildPath: s filePath = filePath.replace(/\.cjs$/, EXTNAME_JS); } projectPath = toUnixPath(projectPath); - const hapPath: string = toUnixPath(projectConfig.projectRootPath); - const tempFilePath: string = filePath.replace(hapPath, ''); if (checkNodeModulesFile(filePath, projectPath)) { filePath = toUnixPath(filePath); - const fakeNodeModulesPath: string = toUnixPath(path.resolve(projectConfig.projectRootPath, NODE_MODULES)); - const dataTmps: string[] = tempFilePath.split(NODE_MODULES); + const fakeNodeModulesPath: string = toUnixPath(path.join(projectConfig.projectRootPath, NODE_MODULES)); let output: string = ''; if (filePath.indexOf(fakeNodeModulesPath) === -1) { - const sufStr: string = dataTmps[dataTmps.length - 1]; + const hapPath: string = toUnixPath(projectConfig.projectRootPath); + const tempFilePath: string = filePath.replace(hapPath, ''); + const sufStr: string = tempFilePath.substring(tempFilePath.indexOf(NODE_MODULES) + NODE_MODULES.length + 1); output = path.join(projectConfig.nodeModulesPath, ZERO, sufStr); } else { - const sufStr: string = dataTmps[dataTmps.length - 1]; - output = path.join(projectConfig.nodeModulesPath, ONE, sufStr); + output = filePath.replace(fakeNodeModulesPath, path.join(projectConfig.nodeModulesPath, ONE)); } return output; } @@ -367,16 +364,89 @@ export function mkdirsSync(dirname: string): boolean { return false; } -export function writeFileSyncByString(sourcePath: string, sourceCode: string, toTsFile: boolean): void { - const temporaryFile: string = genTemporaryPath(sourcePath, projectConfig.projectPath, process.env.cachePath, toTsFile); - if (temporaryFile.length === 0) { +export function writeFileSyncByString(sourcePath: string, sourceCode: string): void { + const jsFilePath: string = genTemporaryPath(sourcePath, projectConfig.projectPath, process.env.cachePath); + if (jsFilePath.length === 0) { return; } - mkdirsSync(path.dirname(temporaryFile)); - fs.writeFileSync(temporaryFile, sourceCode); + mkdirsSync(path.dirname(jsFilePath)); + fs.writeFileSync(jsFilePath, sourceCode); return; } +export const packageCollection: Map> = new Map(); + +export function getPackageInfo(configFile: string): Array { + if (packageCollection.has(configFile)) { + return packageCollection.get(configFile); + } + const data: any = JSON.parse(fs.readFileSync(configFile).toString()); + const bundleName: string = data.app.bundleName; + const moduleName: string = data.module.name; + packageCollection.set(configFile, [bundleName, moduleName]); + return [bundleName, moduleName]; +} + +function replaceRelativeDependency(item:string, moduleRequest: string, sourcePath: string): string { + if (sourcePath && projectConfig.compileMode === ESMODULE) { + const filePath: string = path.resolve(path.dirname(sourcePath), moduleRequest); + const result: RegExpMatchArray | null = filePath.match(/(\S+)(\/|\\)src(\/|\\)(?:main|ohosTest)(\/|\\)(ets|js)(\/|\\)(\S+)/); + if (result && projectConfig.aceModuleJsonPath) { + const npmModuleIdx: number = result[1].search(/(\/|\\)node_modules(\/|\\)/); + const projectRootPath: string = projectConfig.projectRootPath; + if (npmModuleIdx === -1 || npmModuleIdx === projectRootPath.search(/(\/|\\)node_modules(\/|\\)/)) { + const packageInfo: string[] = getPackageInfo(projectConfig.aceModuleJsonPath); + const bundleName: string = packageInfo[0]; + const moduleName: string = packageInfo[1]; + moduleRequest = `@bundle:${bundleName}/${moduleName}/${result[5]}/${toUnixPath(result[7])}`; + item = item.replace(/['"](\S+)['"]/, '\"' + moduleRequest + '\"'); + } + } + } + return item; +} + +function generateSourceMap(jsFilePath: string, sourceMapContent: string): void { + let buildFilePath: string = genBuildPath(jsFilePath, projectConfig.projectPath, projectConfig.buildPath); + if (buildFilePath.length === 0) { + return; + } + if (buildFilePath.endsWith(EXTNAME_ETS)) { + buildFilePath = buildFilePath.replace(/\.ets$/, EXTNAME_JS); + } else { + buildFilePath = buildFilePath.replace(/\.ts$/, EXTNAME_JS); + } + let buildSourceMapFile: string = genSourceMapFileName(buildFilePath); + mkdirsSync(path.dirname(buildSourceMapFile)); + fs.writeFileSync(buildSourceMapFile, sourceMapContent); +} + +export function generateSourceFilesToTemporary(node: ts.SourceFile): void { + const mixedInfo: {content: string, sourceMapContent: string} = genContentAndSourceMapInfo(node, false); + let jsFilePath: string = genTemporaryPath(node.fileName, projectConfig.projectPath, process.env.cachePath); + if (jsFilePath.length === 0) { + return; + } + if (jsFilePath.endsWith(EXTNAME_ETS)) { + jsFilePath = jsFilePath.replace(/\.ets$/, EXTNAME_JS); + } else { + jsFilePath = jsFilePath.replace(/\.ts$/, EXTNAME_JS); + } + let sourceMapFile: string = genSourceMapFileName(jsFilePath); + mkdirsSync(path.dirname(jsFilePath)); + if (sourceMapFile.length > 0 && projectConfig.buildArkMode === 'debug') { + mixedInfo.content += '\n' + "//# sourceMappingURL=" + path.basename(sourceMapFile); + generateSourceMap(node.fileName, mixedInfo.sourceMapContent); + } + // replace relative moduleSpecifier with ohmURl + const REG_RELATIVE_DEPENDENCY: RegExp = /(?:import|from)(?:\s*)['"]((?:\.\/|\.\.\/).*)['"]/g; + mixedInfo.content = mixedInfo.content.replace(REG_RELATIVE_DEPENDENCY, (item, moduleRequest)=>{ + return replaceRelativeDependency(item, moduleRequest, node.fileName); + }); + + fs.writeFileSync(jsFilePath, mixedInfo.content); +} + export function writeFileSyncByNode(node: ts.SourceFile, toTsFile: boolean): void { if (toTsFile) { const newStatements: ts.Node[] = []; diff --git a/compiler/src/validate_ui_syntax.ts b/compiler/src/validate_ui_syntax.ts index 9701ce4..b62c9c3 100644 --- a/compiler/src/validate_ui_syntax.ts +++ b/compiler/src/validate_ui_syntax.ts @@ -70,7 +70,7 @@ import { componentInfo, addLog, hasDecorator, - toUnixPath + getPackageInfo } from './utils'; import { projectConfig, abilityPagesFullPath } from '../main'; import { collectExtend } from './process_ui_syntax'; @@ -135,7 +135,6 @@ export const localStoragePropCollection: Map>> = export const isStaticViewCollection: Map = new Map(); -export const packageCollection: Map> = new Map(); export const useOSFiles: Set = new Set(); export const sourcemapNamesCollection: Map> = new Map(); export const originalImportNamesMap: Map = new Map(); @@ -841,17 +840,6 @@ export function preprocessNewExtend(content: string, extendCollection?: Set { - if (packageCollection.has(configFile)) { - return packageCollection.get(configFile); - } - const data: any = JSON.parse(fs.readFileSync(configFile).toString()); - const bundleName: string = data.app.bundleName; - const moduleName: string = data.module.name; - packageCollection.set(configFile, [bundleName, moduleName]); - return [bundleName, moduleName]; -} - function replaceSystemApi(item: string, systemValue: string, moduleType: string, systemKey: string): string { if (NATIVE_MODULE.has(`${moduleType}.${systemKey}`)) { item = `var ${systemValue} = globalThis.requireNativeModule('${moduleType}.${systemKey}')`; @@ -967,26 +955,6 @@ function replaceOhmUrl(isSystemModule: boolean, item: string, importValue: strin return item; } -function replaceRelativePath(item:string, moduleRequest: string, sourcePath: string): string { - // Do not replace relativePath to ohmUrl when building bundle - if (sourcePath && projectConfig.compileMode === ESMODULE) { - const filePath: string = path.resolve(path.dirname(sourcePath), moduleRequest); - const result: RegExpMatchArray | null = filePath.match(/(\S+)(\/|\\)src(\/|\\)(?:main|ohosTest)(\/|\\)(ets|js)(\/|\\)(\S+)/); - if (result && projectConfig.aceModuleJsonPath) { - const npmModuleIdx: number = result[1].search(/(\/|\\)node_modules(\/|\\)/); - const projectRootPath: string = projectConfig.projectRootPath; - if (npmModuleIdx == -1 || npmModuleIdx == projectRootPath.search(/(\/|\\)node_modules(\/|\\)/)) { - const packageInfo: string[] = getPackageInfo(projectConfig.aceModuleJsonPath); - const bundleName: string = packageInfo[0]; - const moduleName: string = packageInfo[1]; - moduleRequest = `@bundle:${bundleName}/${moduleName}/${result[5]}/${toUnixPath(result[7])}`; - item = item.replace(/['"](\S+)['"]/, '\"' + moduleRequest + '\"'); - } - } - } - return item; -} - export function processSystemApi(content: string, isProcessAllowList: boolean = false, sourcePath: string = null, isSystemModule: boolean = false): string { if (isProcessAllowList && projectConfig.compileMode === ESMODULE) { @@ -1028,14 +996,11 @@ export function processSystemApi(content: string, isProcessAllowList: boolean = const moduleType: string = result[1]; const apiName: string = result[2]; return replaceSystemApi(item, importValue, moduleType, apiName); - } else if (/^(\.|\.\.)\//.test(moduleRequest)) { // relativePath - return replaceRelativePath(item, moduleRequest, sourcePath); } else if (/^lib(\S+)\.so$/.test(moduleRequest)) { // libxxx.so const result: RegExpMatchArray = moduleRequest.match(/^lib(\S+)\.so$/); const libSoKey: string = result[1]; return replaceLibSo(importValue, libSoKey, sourcePath); } - // node_modules return item; }); return processInnerModule(processedContent, systemValueCollection);