HarmonyOS编译插件开发实战系列(二)

164 阅读3分钟

第2章:核心概念详解

1. Node节点体系

1.1 Node概述

Node是Hvigor构建系统中的基本单位,代表一个构建模块(如HAP/HAR/HSP)。每个Node都可以:

  • 持有自己的构建配置
  • 管理任务集合
  • 维护与其他Node的依赖关系

1.2 HvigorNode API

interface HvigorNode {
  // 获取节点名称
  getNodeName(): string;
  
  // 获取节点路径
  getNodePath(): string;
  
  // 获取上下文
  getContext(pluginId: string): any;
  
  // 注册任务
  registerTask(taskOptions: TaskOptions): void;
  
  // 获取任务
  getTaskByName(name: string): Task | undefined;
  
  // 遍历子节点
  subNodes(callback: (node: HvigorNode) => void): void;
}

1.3 节点生命周期

export function myPlugin(): HvigorPlugin {
  return {
    pluginId: 'my-plugin',
    apply(node: HvigorNode) {
      // 配置评估阶段
      hvigor.configurationEvaluated(() => {
        console.log('配置评估完成');
      });
      
      // 节点评估阶段
      hvigor.nodesEvaluated(() => {
        console.log('所有节点评估完成');
      });
      
      // 构建完成阶段
      hvigor.buildFinished(() => {
        console.log('构建完成');
      });
    }
  };
}

2. Context上下文系统

2.1 Context类型

Hvigor提供了三种主要的上下文类型:

// HAP模块上下文
interface OhosHapContext {
  getModuleName(): string;
  getModulePath(): string;
  targets(callback: (target: Target) => void): void;
}

// HAR模块上下文
interface OhosHarContext {
  getModuleName(): string;
  getModulePath(): string;
}

// HSP模块上下文
interface OhosHspContext {
  getModuleName(): string;
  getModulePath(): string;
}

2.2 上下文使用示例

export function contextPlugin(): HvigorPlugin {
  return {
    pluginId: 'context-plugin',
    apply(node: HvigorNode) {
      // 获取HAP上下文
      const hapContext = node.getContext(OhosPluginId.OHOS_HAP_PLUGIN) as OhosHapContext;
      if (hapContext) {
        // 获取模块信息
        const moduleName = hapContext.getModuleName();
        const modulePath = hapContext.getModulePath();
        
        // 处理构建目标
        hapContext.targets((target: Target) => {
          const targetName = target.getTargetName();
          const outputPath = target.getBuildTargetOutputPath();
          console.log(`处理构建目标: ${targetName}, 输出路径: ${outputPath}`);
        });
      }
    }
  };
}

3. Task任务系统

3.1 任务定义

interface TaskOptions {
  // 任务名称
  name: string;
  
  // 任务执行函数
  run: () => void | Promise<void>;
  
  // 依赖任务
  dependencies?: string[];
  
  // 后置任务
  postDependencies?: string[];
  
  // 是否启用
  enabled?: boolean;
}

3.2 任务注册与配置

export function taskPlugin(): HvigorPlugin {
  return {
    pluginId: 'task-plugin',
    apply(node: HvigorNode) {
      // 注册自定义任务
      node.registerTask({
        name: 'customBuild',
        // 任务执行逻辑
        run: async () => {
          console.log('开始自定义构建...');
          // 执行构建逻辑
          await someAsyncBuildOperation();
          console.log('自定义构建完成');
        },
        // 前置依赖
        dependencies: ['preBuild'],
        // 后置依赖
        postDependencies: ['postBuild']
      });
      
      // 禁用某个任务
      node.getTaskByName('someTask')?.setEnable(false);
    }
  };
}

3.3 任务执行流程

  1. 依赖分析
  2. 拓扑排序
  3. 并行执行
  4. 错误处理

4. 最佳实践

4.1 插件设计原则

4.1.1 单一职责原则
  • 每个插件专注于解决一个特定问题
  • 通过组合多个小插件实现复杂功能
  • 避免插件功能之间的耦合
// 好的实践
export function styleCheckPlugin(): HvigorPlugin { ... }
export function resourceOptimizePlugin(): HvigorPlugin { ... }

// 避免这样
export function styleAndResourcePlugin(): HvigorPlugin { ... }
4.1.2 可配置性设计
  • 提供合理的默认配置
  • 支持外部覆盖配置
  • 配置项类型安全
interface StyleCheckConfig {
  rules: {
    [key: string]: 'error' | 'warn' | 'off';
  };
  ignorePatterns?: string[];
  fix?: boolean;
}

export function styleCheckPlugin(config?: Partial<StyleCheckConfig>): HvigorPlugin {
  const defaultConfig: StyleCheckConfig = {
    rules: {
      'no-console': 'warn',
      'no-unused-vars': 'error'
    },
    fix: false
  };

  const finalConfig = { ...defaultConfig, ...config };
  // 插件实现...
}
4.1.3 错误处理策略
  • 提供清晰的错误信息
  • 支持错误恢复机制
  • 区分致命错误和警告
class PluginError extends Error {
  constructor(
    message: string,
    public readonly severity: 'error' | 'warning' = 'error',
    public readonly code?: string
  ) {
    super(message);
  }
}

function handlePluginError(error: PluginError, node: HvigorNode) {
  if (error.severity === 'error') {
    node.fail(`[${error.code}] ${error.message}`);
  } else {
    node.warn(`[${error.code}] ${error.message}`);
  }
}
4.1.4 性能优化策略
  • 实现增量构建
  • 使用缓存机制
  • 并行处理
  • 懒加载资源
export class OptimizedPlugin {
  private cache = new Map<string, any>();

  async apply(node: HvigorNode) {
    // 增量构建检查
    const changedFiles = await this.getChangedFiles(node);
    if (changedFiles.length === 0) {
      console.log('No changes detected, skipping...');
      return;
    }

    // 并行处理
    await Promise.all(
      changedFiles.map(async file => {
        const cacheKey = this.getCacheKey(file);
        if (this.cache.has(cacheKey)) {
          return this.cache.get(cacheKey);
        }
        const result = await this.processFile(file);
        this.cache.set(cacheKey, result);
        return result;
      })
    );
  }
}

4.2 代码组织最佳实践

4.2.1 模块化组织
// plugins/
//   ├── core/
//   │   ├── types.ts
//   │   └── constants.ts
//   ├── tasks/
//   │   ├── styleCheck.ts
//   │   └── resourceOptimize.ts
//   ├── utils/
//   │   ├── logger.ts
//   │   └── cache.ts
//   └── index.ts

// 统一导出
export * from './core/types';
export * from './tasks/styleCheck';
export * from './tasks/resourceOptimize';
4.2.2 插件生命周期管理
export class BasePlugin {
  protected async beforeApply(node: HvigorNode) {
    // 前置处理
  }

  protected async afterApply(node: HvigorNode) {
    // 后置处理
  }

  async apply(node: HvigorNode) {
    try {
      await this.beforeApply(node);
      await this.executePlugin(node);
      await this.afterApply(node);
    } catch (error) {
      this.handleError(error);
    }
  }

  protected abstract executePlugin(node: HvigorNode): Promise<void>;
}
4.2.3 依赖注入模式
interface Services {
  logger: Logger;
  cache: Cache;
  config: Config;
}

export class ModernPlugin extends BasePlugin {
  constructor(private services: Services) {
    super();
  }

  protected async executePlugin(node: HvigorNode) {
    const { logger, cache, config } = this.services;
    // 使用注入的服务实现功能
  }
}

4.3 调试与测试实践

4.3.1 日志管理
export class PluginLogger {
  static debug(message: string, ...args: any[]) {
    if (process.env.DEBUG) {
      console.log(`[DEBUG] ${message}`, ...args);
    }
  }

  static info(message: string, ...args: any[]) {
    console.log(`[INFO] ${message}`, ...args);
  }

  static error(message: string, error?: Error) {
    console.error(`[ERROR] ${message}`, error?.stack);
  }
}
4.3.2 单元测试
describe('StyleCheckPlugin', () => {
  let plugin: StyleCheckPlugin;
  let mockNode: HvigorNode;

  beforeEach(() => {
    mockNode = createMockNode();
    plugin = new StyleCheckPlugin({
      rules: { 'no-console': 'error' }
    });
  });

  it('should detect style violations', async () => {
    const results = await plugin.checkStyle('test.ts');
    expect(results.violations).toHaveLength(1);
  });
});

参考资料