目录

性能优化:自定义插件和任务优化实践

概述

开发者可通过自定义插件和任务扩展构建能力,实现自动化构建步骤、定制化资源处理等需求。本文主要内容如下:

  1. 通过自定义插件示例分析可能的性能问题并给出优化方案。
  2. 通过自定义任务示例分析可能的性能问题并给出优化方案。

优化自定义插件

[h2]示例

开发者可以通过实现HvigorPlugin接口的方式开发自定义插件。下面示例在entry/hvigorfile.ts中定义一个插件,模拟开发者在构建Hap开始阶段下载必要资源的场景。

// entry/hvigorfile.ts
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
import { HvigorPlugin, HvigorNode } from '@ohos/hvigor';

class MyCustomPlugin implements HvigorPlugin {
  pluginId = 'customPlugin';

  async apply(node: HvigorNode): Promise<void> {
    console.log('download start at', new Date());
    await new Promise<void>((resolve) => {
      setTimeout(() => {
        // 使用延时模拟耗时操作
        console.log('download end at', new Date());
        resolve();
      }, 5000);
    });
  }
}

export default {
  system: hapTasks,
  plugins: [new MyCustomPlugin()]
}

点击ReBuild Project构建工程,构建窗口输出日志如下:

执行Sync时,也会触发下载操作。

[h2]问题分析

HvigorPlugin的apply方法运行在构建生命周期的配置阶段(内部生命周期函数,开发者无法使用)。上述示例中,耗时的业务下载逻辑直接在apply方法中执行,apply方法无增量跳过机制,导致每次构建都必须执行,并且耗时的操作会阻塞主线程逻辑,影响开发效率。

[h2]优化方案

业务耗时的逻辑应避免直接在apply方法中执行,建议:

下面示例对上面实现进行改造,使用HvigorTask任务承载业务逻辑:

// entry/hvigorfile.ts
import { hapTasks, OhosPluginId, OhosHapContext, Target } from '@ohos/hvigor-ohos-plugin';
import { HvigorPlugin, HvigorNode, hvigor } from '@ohos/hvigor';

class MyCustomPlugin implements HvigorPlugin {
  pluginId = 'customPlugin';

  async apply(node: HvigorNode): Promise<void> {
    const hapContext = node?.getContext(OhosPluginId.OHOS_HAP_PLUGIN) as OhosHapContext;
    hapContext?.targets((target: Target) => {
      const targetName = target.getTargetName();
      // 把业务逻辑封装到任务里面,apply方法中不再执行下载操作,下载操作推迟到任务执行阶段
      node?.registerTask({
        name: `${targetName}@DownloadTask`,
        async run() {
          console.log('download start at', new Date());
          await new Promise<void>((resolve) => {
            setTimeout(() => {
              // 使用延时模拟耗时操作
              console.log('download end at', new Date());
              resolve();
            }, 5000);
          });
        },
        // 设置前置依赖任务,PreBuild任务会先于本任务执行
        dependencies: [`${targetName}@PreBuild`],
        // 设置后置依赖任务,本任务会先于CreateModuleInfo任务执行
        postDependencies: [`${targetName}@CreateModuleInfo`]
      });
    });
  }
}

export default {
  system: hapTasks,
  plugins: [new MyCustomPlugin()]
}

改造之后,Sync流程不会触发下载操作:

用户的业务逻辑在任务执行阶段执行:

还可以进一步利用任务的增量机制优化增量构建场景,请参考下文介绍。

优化自定义任务

[h2]示例

开发者可以在hvigorfile.ts中通过registerTask接口注册HvigorTask的方式开发自定义任务。每个模块级hvigorfile.ts可注册多个任务,任务之间通过dependencies(前置依赖)和postDependencies(后置依赖)声明依赖关系。

下面示例在entry/hvigorfile.ts中注册两个HvigorTask任务,模拟开发者操作编译产物的场景。

// entry/hvigorfile.ts
// 注册两个自定义任务操作输出目录
import { hapTasks, OhosPluginId, OhosHapContext, Target } from '@ohos/hvigor-ohos-plugin';
import { getNode, hvigor, HvigorNode } from '@ohos/hvigor';

hvigor.nodesEvaluated(() => {
  const node: HvigorNode | undefined = getNode(__filename);
  const hapContext = node?.getContext(OhosPluginId.OHOS_HAP_PLUGIN) as OhosHapContext;
  hapContext?.targets((target: Target) => {
    const targetName = target.getTargetName();
    const buildTargetOutputPath = target.getBuildTargetOutputPath();
    // 注册自定义任务CustomTask0
    node?.registerTask({
      name: `${targetName}@CustomTask0`,
      async run() {
        await new Promise<void>((resolve) => {
          setTimeout(() => {
            // 使用延时模拟耗时操作
            console.log(`${this.name} Processing files in the directory:`, buildTargetOutputPath);
            resolve();
          }, 5000);
        });
      },
      // 设置前置依赖任务,SignHap任务会先于本任务执行
      dependencies: [`${targetName}@SignHap`],
      // 设置后置依赖任务,本任务会先于assembleHap任务执行
      postDependencies: ['assembleHap']
    });
    // 注册自定义任务CustomTask1
    node?.registerTask({
      name: `${targetName}@CustomTask1`,
      async run() {
        await new Promise<void>((resolve) => {
          setTimeout(() => {
            console.log(`${this.name} Processing files in the directory:`, buildTargetOutputPath);
            resolve();
          }, 5000);
        });
      },
      dependencies: [`${targetName}@SignHap`],
      postDependencies: ['assembleHap']
    });
  });
});

export default {
  system: hapTasks,
  plugins: []
}

点击ReBuild Project构建工程,构建窗口输出日志如下,端到端全量构建约15s。

[h2]问题分析

以上示例代码存在两个问题,重复构建和串行构建。

[h2]优化方案

针对上述问题,建议按照以下方案进行优化。

总结

开发自定义插件和任务时,可从以下几方面实践并验证优化性能问题。

  1. 将复杂耗时的业务逻辑封装为独立的HvigorTask,并在插件的apply方法中进行注册。
  2. 插件用于组织和管理HvigorTask,不过度参与具体执行。
  3. 避免在hvigorfile.ts全局作用域编写同步执行代码,而是使用生命周期钩子函数(如nodesEvaluated)控制执行时机。
  4. 自定义任务配置input,声明依赖文件;或者配置output,声明输出文件;连续构建时,确认未变化的任务已被跳过,构建结果显示“UP-TO-DATE”。
  5. 耗时任务通过submitWorker分发到worker执行,通过Build Analyzer验证任务并行执行。