• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 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 path from 'path';
17
18import {
19  ESMODULE,
20  GEN_ABC_PLUGIN_NAME
21} from './common/ark_define';
22import { ModuleSourceFile } from './module/module_source_file';
23import {
24  isAotMode,
25  isCommonJsPluginVirtualFile,
26  isDebug,
27  isJsonSourceFile,
28  isJsSourceFile,
29  isTsOrEtsSourceFile,
30  shouldETSOrTSFileTransformToJS
31} from './utils';
32import {
33  toUnixPath,
34  emitLogInfo,
35  getTransformLog
36} from '../../utils';
37import {
38  resetReExportCheckLog,
39  reExportNoCheckMode,
40  processJsCodeLazyImport,
41  reExportCheckLog,
42  LazyImportOptions
43} from '../../process_lazy_import';
44import { SourceMapGenerator } from './generate_sourcemap';
45import { MemoryMonitor } from '../meomry_monitor/rollup-plugin-memory-monitor';
46import { MemoryDefine } from '../meomry_monitor/memory_define';
47import {
48  getHookEventFactory,
49  createAndStartEvent,
50  stopEvent,
51  CompileEvent
52} from '../../performance';
53
54/**
55 * rollup transform hook
56 * @param {string} code: transformed source code of an input file
57 * @param {string} id: absolute path of an input file
58 */
59export function transformForModule(code: string, id: string): string {
60  const hookEventFactory: CompileEvent | undefined = getHookEventFactory(this.share, 'genAbc', 'transform');
61  const eventTransformForModule = createAndStartEvent(hookEventFactory, 'transform for module');
62  const {
63    autoLazyImport,
64    reExportCheckMode
65  }: LazyImportOptions = {
66    autoLazyImport: this.share.projectConfig?.autoLazyImport ?? false,
67    reExportCheckMode: this.share.projectConfig?.reExportCheckMode ?? reExportNoCheckMode
68  };
69  if (this.share.projectConfig.compileMode === ESMODULE) {
70    const metaInfo: Object = this.getModuleInfo(id).meta;
71    const projectConfig: Object = Object.assign(this.share.arkProjectConfig, this.share.projectConfig);
72    if (isTsOrEtsSourceFile(id) && shouldETSOrTSFileTransformToJS(id, projectConfig, metaInfo)) {
73      preserveSourceMap(id, this.getCombinedSourcemap(), projectConfig, metaInfo, eventTransformForModule);
74      // when ets/ts -> js, we need to convert lazy-import based on the js code generated after tsc conversion
75      code = processJsCodeLazyImport(id, code, autoLazyImport, reExportCheckMode);
76      const newSourceFileRecordInfo = MemoryMonitor.recordStage(MemoryDefine.MODULE_SOURCE_FILE_NEW_SOURCE_FILE);
77      ModuleSourceFile.newSourceFile(id, code, metaInfo, projectConfig.singleFileEmit);
78      MemoryMonitor.stopRecordStage(newSourceFileRecordInfo);
79    }
80
81    if (isJsSourceFile(id) || isJsonSourceFile(id)) {
82      let code: string = this.getModuleInfo(id).originalCode;
83      if (isJsSourceFile(id)) {
84        code = processJsCodeLazyImport(id, code, autoLazyImport, reExportCheckMode);
85        if (projectConfig.compatibleSdkVersion <= 10) {
86          const transformedResult: object = transformJsByBabelPlugin(code, eventTransformForModule);
87          code = transformedResult.code;
88          preserveSourceMap(id, transformedResult.map, projectConfig, metaInfo, eventTransformForModule);
89        } else {
90          // preserve sourceMap of js file without transforming
91          preserveSourceMap(id, this.getCombinedSourcemap(), projectConfig, metaInfo, eventTransformForModule);
92        }
93      }
94      const recordInfo = MemoryMonitor.recordStage(MemoryDefine.MODULE_SOURCE_FILE_NEW_SOURCE_FILE);
95      ModuleSourceFile.newSourceFile(id, code, metaInfo, projectConfig.singleFileEmit);
96      MemoryMonitor.stopRecordStage(recordInfo);
97    }
98  }
99  stopEvent(eventTransformForModule);
100
101  if (reExportCheckLog && reExportCheckLog.errors.length &&
102    reExportCheckMode !== reExportNoCheckMode && !this.share.projectConfig.ignoreWarning) {
103    emitLogInfo(this.share.getLogger(GEN_ABC_PLUGIN_NAME), [...getTransformLog(reExportCheckLog)], true, id);
104    resetReExportCheckLog();
105  }
106
107  // if we perform lazy-import conversion, we need to return the converted js code
108  return code;
109}
110
111function preserveSourceMap(sourceFilePath: string, sourcemap: Object, projectConfig: Object, metaInfo: Object, parentEvent: CompileEvent): void {
112  if (isCommonJsPluginVirtualFile(sourceFilePath)) {
113    // skip automatic generated files like 'jsfile.js?commonjs-exports'
114    return;
115  }
116
117  const eventAddSourceMapInfo = createAndStartEvent(parentEvent, 'preserve source map for ts/ets files');
118  const relativeSourceFilePath = sourceFilePath.startsWith(projectConfig.projectRootPath) ?
119    toUnixPath(sourceFilePath.replace(projectConfig.projectRootPath + path.sep, '')) :
120    toUnixPath(sourceFilePath.replace(metaInfo.belongProjectPath + path.sep, ''));
121  sourcemap.sources = [relativeSourceFilePath];
122  sourcemap.file = path.basename(relativeSourceFilePath);
123  sourcemap.sourcesContent && delete sourcemap.sourcesContent;
124  const sourceMapGenerator = SourceMapGenerator.getInstance();
125  const key = sourceMapGenerator.isNewSourceMaps() ? sourceFilePath : relativeSourceFilePath;
126  sourceMapGenerator.fillSourceMapPackageInfo(sourceFilePath, sourcemap);
127  sourceMapGenerator.updateSourceMap(key, sourcemap);
128  stopEvent(eventAddSourceMapInfo);
129}
130
131function transformJsByBabelPlugin(code: string, parentEvent: CompileEvent): Object {
132  const eventTransformByBabel = createAndStartEvent(parentEvent, 'transform Js by babel plugin');
133  const transformed: Object = require('@babel/core').transformSync(code,
134    {
135      plugins: [
136        [require("@babel/plugin-proposal-class-properties"), { "loose": true }]
137      ],
138      compact: false,
139      sourceMaps: true
140    }
141  );
142  stopEvent(eventTransformByBabel);
143  return transformed;
144}