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