• 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 fs from 'fs';
17import path from 'path';
18
19import { ModuleMode } from './module_mode';
20import {
21  blue,
22  reset,
23  MODULES_ABC,
24  SOURCEMAPS,
25  SYMBOLMAP
26} from '../common/ark_define';
27import { isJsonSourceFile } from '../utils';
28import { newSourceMaps } from '../transform';
29import {
30  mkdirsSync,
31  toUnixPath,
32  validateFilePathLength
33} from '../../../utils';
34import {
35  createAndStartEvent,
36  stopEvent
37} from '../../../ark_utils';
38
39let isFirstBuild: boolean = true;
40
41export class ModuleHotreloadMode extends ModuleMode {
42  symbolMapFilePath: string;
43  constructor(rollupObject: Object) {
44    super(rollupObject);
45    if (this.projectConfig.oldMapFilePath) {
46      this.symbolMapFilePath = path.join(this.projectConfig.oldMapFilePath, SYMBOLMAP);
47    } else {
48      this.throwArkTsCompilerError('ArkTS:ERROR oldMapFilePath is not specified, hotReload Fail');
49    }
50  }
51
52  generateAbc(rollupObject: Object, parentEvent: Object): void {
53    if (isFirstBuild) {
54      this.compileAllFiles(rollupObject, parentEvent);
55      isFirstBuild = false;
56    } else {
57      this.compileChangeListFiles(rollupObject, parentEvent);
58    }
59  }
60
61  addHotReloadArgs() {
62    if (isFirstBuild) {
63      this.cmdArgs.push('--dump-symbol-table');
64      this.cmdArgs.push(`"${this.symbolMapFilePath}"`);
65      return;
66    }
67    this.addCacheFileArgs();
68    this.cmdArgs.push('--input-symbol-table');
69    this.cmdArgs.push(`"${this.symbolMapFilePath}"`);
70    this.cmdArgs.push('--hot-reload');
71  }
72
73  private compileAllFiles(rollupObject: Object, parentEvent: Object): void {
74    this.prepareForCompilation(rollupObject, parentEvent);
75    this.buildModuleSourceMapInfo(parentEvent);
76    this.generateAbcByEs2abc(parentEvent);
77  }
78
79  private compileChangeListFiles(rollupObject: Object, parentEvent: Object): void {
80    if (!fs.existsSync(this.projectConfig.changedFileList)) {
81      this.logger.debug(blue, `ArkTS: Cannot find file: ${
82        this.projectConfig.changedFileList}, skip hot reload build`, reset);
83      return;
84    }
85
86    const changedFileListJson: string = fs.readFileSync(this.projectConfig.changedFileList).toString();
87    const changedFileList: Array<string> = JSON.parse(changedFileListJson).modifiedFiles;
88    if (typeof changedFileList === 'undefined' || changedFileList.length === 0) {
89      this.logger.debug(blue, `ArkTS: No changed files found, skip hot reload build`, reset);
90      return;
91    }
92
93    let needHotreloadBuild: boolean = true;
94    let changedFileListInAbsolutePath: Array<string> = changedFileList.map((file) => {
95      if (isJsonSourceFile(file)) {
96        this.logger.debug(blue, `ARKTS: json source file: ${file} changed, skip hot reload build!`, reset);
97        needHotreloadBuild = false;
98      }
99      return path.join(this.projectConfig.projectPath, file);
100    });
101
102    if (!needHotreloadBuild) {
103      return;
104    }
105
106    const eventCollectModuleFileList = createAndStartEvent(parentEvent, 'collect module file list');
107    this.collectModuleFileList(rollupObject, changedFileListInAbsolutePath[Symbol.iterator]());
108    stopEvent(eventCollectModuleFileList);
109
110    if (!fs.existsSync(this.projectConfig.patchAbcPath)) {
111      mkdirsSync(this.projectConfig.patchAbcPath);
112    }
113
114    this.updateSourceMapFromFileList(changedFileList, parentEvent);
115    const outputABCPath: string = path.join(this.projectConfig.patchAbcPath, MODULES_ABC);
116    validateFilePathLength(outputABCPath, this.logger);
117    this.moduleAbcPath = outputABCPath;
118    this.generateAbcByEs2abc(parentEvent);
119  }
120
121  private updateSourceMapFromFileList(fileList: Array<string>, parentEvent: Object): void {
122    const eventUpdateSourceMapFromFileList = createAndStartEvent(parentEvent, 'update source map from file list');
123    const relativeProjectPath: string = this.projectConfig.projectPath.slice(
124      this.projectConfig.projectRootPath.length + path.sep.length);
125    let hotReloadSourceMap: Object = {};
126    for (const file of fileList) {
127      const sourceMapPath: string = toUnixPath(path.join(relativeProjectPath, file));
128      validateFilePathLength(sourceMapPath, this.logger);
129      hotReloadSourceMap[sourceMapPath] = newSourceMaps[sourceMapPath];
130    }
131    this.modifySourceMapKeyToCachePath(hotReloadSourceMap);
132    const sourceMapFilePath: string = path.join(this.projectConfig.patchAbcPath, SOURCEMAPS);
133    validateFilePathLength(sourceMapFilePath, this.logger);
134    fs.writeFileSync(sourceMapFilePath,
135      JSON.stringify(hotReloadSourceMap, null, 2), 'utf-8');
136    stopEvent(eventUpdateSourceMapFromFileList);
137  }
138
139  private generateAbcByEs2abc(parentEvent: Object): void {
140    this.generateEs2AbcCmd();
141    this.addHotReloadArgs();
142    this.generateMergedAbcOfEs2Abc(parentEvent);
143  }
144}
145