diff --git a/compiler/src/gen_abc_plugin.ts b/compiler/src/gen_abc_plugin.ts index 26bc3e3..1ddd849 100644 --- a/compiler/src/gen_abc_plugin.ts +++ b/compiler/src/gen_abc_plugin.ts @@ -17,9 +17,15 @@ import * as fs from 'fs'; import * as path from 'path'; import cluster from 'cluster'; import process from 'process'; +import * as child_process from 'child_process' import Compiler from 'webpack/lib/Compiler'; import { logger } from './compile_info'; -import { toUnixPath, toHashData } from './utils'; +import { + toUnixPath, + toHashData, + genTemporaryPath } from './utils'; +import { Compilation } from 'webpack'; +import { projectConfig } from '../main'; const firstFileEXT: string = '_.js'; const genAbcScript = 'gen_abc.js'; @@ -65,6 +71,28 @@ export class GenAbcPlugin { } } + compiler.hooks.compilation.tap("GenAbcPlugin", (compilation) => { + compilation.hooks.finishModules.tap("finishModules", handleFinishModules.bind(this)); + }); + + compiler.hooks.compilation.tap("GenAbcPlugin", (compilation) => { + compilation.hooks.afterOptimizeTree.tap("afterOptimizeModules", (chunks, modules) => { + modules.forEach(module => { + if (module != undefined && module.resourceResolveData != undefined) { + let filePath: string = module.resourceResolveData.path; + console.error(filePath); + } + }); + }); + + compilation.hooks.processAssets.tap("processAssets", (assets) => { + Object.keys(compilation.assets).forEach(key => { + delete assets[key]; + }) + }) + + }) + compiler.hooks.emit.tap('GenAbcPlugin', (compilation) => { Object.keys(compilation.assets).forEach(key => { // choose *.js @@ -80,9 +108,90 @@ export class GenAbcPlugin { buildPathInfo = output; invokeWorkersToGenAbc(); }); + + } } +function handleFinishModules(modules, callback) { + modules.forEach(module => { + if (module != undefined && module.resourceResolveData != undefined) { + let filePath: string = module.resourceResolveData.path; + console.error(filePath); + if (filePath.endsWith('ets')) { + let tempFilePath = genTemporaryPath(filePath, projectConfig.projectPath, projectConfig.buildPath); + tempFilePath = tempFilePath.replace(/\.ets$/, '.ets.js'); + tempFilePath = toUnixPath(tempFilePath); + const abcFilePath = genAbcFileName(tempFilePath); + processToAbcFile(tempFilePath, abcFilePath); + } else if (filePath.endsWith('ts')) { + let tempFilePath = genTemporaryPath(filePath, projectConfig.projectPath, projectConfig.buildPath); + tempFilePath = tempFilePath.replace(/\.ts$/, '.ts.js'); + tempFilePath = toUnixPath(tempFilePath); + const abcFilePath = genAbcFileName(tempFilePath); + processToAbcFile(tempFilePath, abcFilePath); + } else if (filePath.endsWith('js')) { + if (filePath.indexOf("node_modules") !== -1) { + let tempFilePath = genTemporaryPath(filePath, projectConfig.projectPath, projectConfig.buildPath); + tempFilePath = toUnixPath(tempFilePath); + const parent: string = path.join(tempFilePath, '..'); + if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) { + mkDir(parent); + } + fs.copyFileSync(filePath, tempFilePath); + const abcFilePath = genAbcFileName(tempFilePath); + processToAbcFile(tempFilePath, abcFilePath); + } else { + let tempFilePath = genTemporaryPath(filePath, projectConfig.projectPath, projectConfig.buildPath); + tempFilePath = toUnixPath(tempFilePath); + const parent: string = path.join(tempFilePath, '..'); + if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) { + mkDir(parent); + } + // fs.copyFileSync(filePath, tempFilePath); + const abcFilePath = genAbcFileName(tempFilePath); + processToAbcFile(tempFilePath, abcFilePath); + } + } else { + console.error("=========================handleFinishModules else==================="); + console.error(filePath); + } + } + }) +} + +function genAbcFileName(temporaryFile: string): string { + let abcFile: string = temporaryFile; + if (temporaryFile.endsWith('ts')) { + abcFile = temporaryFile.replace(/\.ts$/, '.abc'); + } else { + abcFile = temporaryFile.replace(/\.js$/, '.abc'); + } + return abcFile; +} + +function processToAbcFile(tempFilePath, outPutFile) { + let js2abc: string = path.join(arkDir, 'build', 'src', 'index.js'); + if (isWin) { + js2abc = path.join(arkDir, 'build-win', 'src', 'index.js'); + } else if (isMac) { + js2abc = path.join(arkDir, 'build-mac', 'src', 'index.js'); + } + + const args: string[] = [ + '--expose-gc', + js2abc, + '-o', + outPutFile + ]; + if (isDebug) { + args.push('--debug'); + } + args.push(tempFilePath); + + child_process.execFileSync(nodeJs, args); +} + function writeFileSync(inputString: string, output: string, jsBundleFile: string): void { const parent: string = path.join(output, '..'); if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) { diff --git a/compiler/src/process_js_ast.ts b/compiler/src/process_js_ast.ts new file mode 100644 index 0000000..b46290f --- /dev/null +++ b/compiler/src/process_js_ast.ts @@ -0,0 +1,35 @@ +/* + * 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 ts from 'typescript'; +import path from 'path'; +import { BUILD_ON } from './pre_define'; +import { writeFileSyncByNode } 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) { + if (process.env.processTs && process.env.processTs === 'false') { + writeFileSyncByNode(node, false); + } + return node; + } else { + return node; + } + + } + } +} \ No newline at end of file diff --git a/compiler/src/process_js_file.ts b/compiler/src/process_js_file.ts new file mode 100644 index 0000000..1a1b1a8 --- /dev/null +++ b/compiler/src/process_js_file.ts @@ -0,0 +1,8 @@ +import { writeFileSyncByString } from './utils'; + +module.exports = function processjs2file(source: string): string { + if (process.env.compilerType && process.env.compilerType === 'ark'){ + writeFileSyncByString(this.resourcePath, source, false); + } + return source; + } \ No newline at end of file diff --git a/compiler/src/process_ui_syntax.ts b/compiler/src/process_ui_syntax.ts index 04fb029..b3c8ef2 100644 --- a/compiler/src/process_ui_syntax.ts +++ b/compiler/src/process_ui_syntax.ts @@ -49,7 +49,8 @@ import { LogInfo, LogType, hasDecorator, - FileLog + FileLog, + writeFileSyncByNode } from './utils'; import { processComponentBlock, @@ -82,6 +83,9 @@ export function processUISyntax(program: ts.Program, ut = false): Function { if (process.env.compiler === BUILD_ON) { if (!ut && (path.basename(node.fileName) === 'app.ets' || /\.ts$/.test(node.fileName))) { node = ts.visitEachChild(node, processResourceNode, context); + if (process.env.processTs && process.env.processTs === 'true') { + writeFileSyncByNode(node, true); + } return node; } transformLog.sourceFile = node; @@ -97,6 +101,9 @@ export function processUISyntax(program: ts.Program, ut = false): Function { }); node = ts.factory.updateSourceFile(node, statements); INTERFACE_NODE_SET.clear(); + if (process.env.processTs && process.env.processTs === 'true') { + writeFileSyncByNode(node, true); + } return node; } else { return node; diff --git a/compiler/src/utils.ts b/compiler/src/utils.ts index 97e0a2f..b47450f 100644 --- a/compiler/src/utils.ts +++ b/compiler/src/utils.ts @@ -13,16 +13,22 @@ * limitations under the License. */ -import ts from 'typescript'; import path from 'path'; +import ts from 'typescript'; import fs from 'fs'; +import { projectConfig } from '../main'; import { createHash } from 'crypto'; +import { processSystemApi } from './validate_ui_syntax'; export enum LogType { ERROR = 'ERROR', WARN = 'WARN', NOTE = 'NOTE' } +export const TEMPORARYS: string = 'temporarys'; +export const BUILD: string = 'build'; +export const SRC_MAIN: string = 'src/main'; +const TS_NOCHECK: string = '// @ts-nocheck'; export interface LogInfo { type: LogType, @@ -234,3 +240,108 @@ 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 { + filePath = toUnixPath(filePath); + projectPath = toUnixPath(projectPath); + + if (filePath.indexOf('node_modules') !== -1) { + const dataTmps = filePath.split('node_modules'); + const preStr = dataTmps[0]; + const sufStr = dataTmps[1]; + const output: string = path.join(buildPath, 'node_modules', sufStr); + return output; + } + + const sufStr = filePath.replace(projectPath, ""); + const output: string = path.join(buildPath, sufStr); + return output; +} + +export function mkdirsSync(dirname: string): boolean { + if (fs.existsSync(dirname)) { + return true; + } else { + if (mkdirsSync(path.dirname(dirname))) { + fs.mkdirSync(dirname); + return true; + } + } + return false; +} + +export function writeFileSyncByString(sourcePath: string, sourceCode: string, toTsFile: boolean) { + let temporaryFile: string = genTemporaryPath(sourcePath, projectConfig.projectPath, projectConfig.buildPath, toTsFile); + mkdirsSync(path.dirname(temporaryFile)); + fs.writeFileSync(temporaryFile, sourceCode); +} + +export function writeFileSyncByNode(node: ts.SourceFile, toTsFile: boolean) { + if (toTsFile) { + const newStatements = []; + const tsIgnoreNode: ts.Node = ts.factory.createExpressionStatement(ts.factory.createIdentifier(TS_NOCHECK)); + newStatements.push(tsIgnoreNode); + if (node.statements && node.statements.length) { + newStatements.push(...node.statements); + } + + node = ts.factory.updateSourceFile(node, newStatements); + } + const printer: ts.Printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); + let options : ts.CompilerOptions = { + sourceMap : true + }; + let mapOpions = { + sourceMap : true, + inlineSourceMap : false, + inlineSources : false, + sourceRoot : "", + mapRoot : "", + extendedDiagnostics : false + } + let host = ts.createCompilerHost(options); + let fileName = node.fileName; + // @ts-ignore + let sourceMapGenerator = ts.createSourceMapGenerator( + host, + // @ts-ignore + ts.getBaseFileName(fileName), + "", + "", + mapOpions + ); + // @ts-ignore + let writer = ts.createTextWriter( + // @ts-ignore + ts.getNewLineCharacter({newLine : ts.NewLineKind.LineFeed, removeComments : false})); + printer["writeFile"](node, writer, sourceMapGenerator); + let sourceMapJson = sourceMapGenerator.toJSON(); + sourceMapJson['sources'] = [fileName]; + const result: string = writer.getText(); + let content: string = result; + content = processSystemApi(content, true); + if (toTsFile) { + content = result.replace(`${TS_NOCHECK};`, TS_NOCHECK); + } + const sourceMapContent = JSON.stringify(sourceMapJson); + let temporaryFile: string = genTemporaryPath(node.fileName, projectConfig.projectPath, projectConfig.buildPath, toTsFile); + let temporarySourceMapFile: string = ""; + if (temporaryFile.endsWith("ets")) { + temporarySourceMapFile = temporaryFile.replace(/\.ets$/, '.ets.sourcemap'); + if (toTsFile) { + temporaryFile = temporaryFile.replace(/\.ets$/, '.ets.ts'); + } else { + temporaryFile = temporaryFile.replace(/\.ets$/, '.ets.js'); + } + } else { + if (!toTsFile) { + temporarySourceMapFile = temporaryFile.replace(/\.ts$/, '.ts.sourcemap'); + temporaryFile = temporaryFile.replace(/\.ts$/, '.ts.js'); + } + } + mkdirsSync(path.dirname(temporaryFile)); + fs.writeFileSync(temporaryFile, content); + if (temporarySourceMapFile.length > 0) { + + fs.writeFileSync(temporarySourceMapFile, sourceMapContent); + } +} diff --git a/compiler/webpack.config.js b/compiler/webpack.config.js index 144c862..6cf9052 100644 --- a/compiler/webpack.config.js +++ b/compiler/webpack.config.js @@ -34,7 +34,7 @@ const { ResultStates } = require('./lib/compile_info'); const { processUISyntax } = require('./lib/process_ui_syntax'); const { IGNORE_ERROR_CODE } = require('./lib/utils'); const { BUILD_SHARE_PATH } = require('./lib/pre_define'); - +const { processJs } = require('./lib/process_js_ast'); process.env.watchMode = (process.env.watchMode && process.env.watchMode === 'true') || 'false'; function initConfig(config) { @@ -80,7 +80,7 @@ function initConfig(config) { getCustomTransformers(program) { return { before: [processUISyntax(program)], - after: [] + after: [processJs(program)] }; }, ignoreDiagnostics: IGNORE_ERROR_CODE @@ -92,6 +92,7 @@ function initConfig(config) { { test: /\.js$/, use: [ + { loader: path.resolve(__dirname, 'lib/process_js_file.js')}, { loader: path.resolve(__dirname, 'lib/process_system_module.js') } ] } @@ -311,9 +312,13 @@ module.exports = (env, argv) => { const workerFile = readWorkerFile(); setOptimizationConfig(config, workerFile); setCopyPluginConfig(config); + + process.env.processTs = false; + if (env.isPreview !== "true") { loadWorker(projectConfig, workerFile); if (env.compilerType && env.compilerType === 'ark') { + process.env.compilerType = 'ark'; let arkDir = path.join(__dirname, 'bin', 'ark'); if (env.arkFrontendDir) { arkDir = env.arkFrontendDir;