【鸿蒙南向开发】OpenHarmony应用构建工具Hvigor的构建流程

前言

OpenHarmony 应用和服务使用 Hvigor 作为工程的构建工具。 本篇文章将介绍 Hvigor 的构建流程,通过修改脚本配置使 Hvigor 执行自定义任务。

Hvigor 的构建流程

1.加载命令行参数和环境变量;
2.初始化项目结构,创建 Project 和 Module 实例;
3.配置项目插件和任务流;
4.执行任务流;

// hvigor/index.js
// LiftOff 命令行辅助工具
const cli = new LiftOff({
    name: 'hvigor',
    processTitle: make_title.makeTitle('hvigor', process.argv.slice(2)),
    moduleName: exports.hvigorPath,// @ohos/hvigor-base
    configName: "hvigorFile",
    v8flags: v8flags,
    extensions: interpret.jsVariants
});
// cli options定义所有的可支持的命令行
const parser = yargs.usage("Usage", cli_options.cliOptions);
// 解析命令行
const opts = parser.argv;
function run() {
    cli.prepare({
        cwd: opts.cwd,
        require: opts.require,
        completion: opts.completion,
    }, function (env) {
        // help 指令
        if (opts.help) {
            yargs.usage('Usage: hvigor [options]')
                .example('hvigor assembleApp', 'Do assembleApp task')
                .help('h')
                .alias('h', 'help')
                .epilog('copyright 2021')
                .argv;
            exit.exit(0);
        }
        // version 指令
        if (opts.version) {
            _log.info('CLI version:', cliVersion);
            _log.info('Local version:', env.modulePackage.version || 'Unknown');
            exit.exit(0);
        }
        // 设置日志等级
        evaluateLogLevel();

        // 判断当前 nodejs工具版本信息
        const LOWEST_VERSION = "v14.18.3";
        if (process.version < LOWEST_VERSION) {
            _log.warn(`node version: ${process.version}`);
            _log.warn(`node version cannot be lower than ${LOWEST_VERSION}`);
            process.exit(-1);
        }
        // 1. 加载命令行参数和环境变量
        init_env_config_props.initEnvConfigProps(env, opts);
        cli.execute(env, env.nodeFlags, function () {
            return __awaiter(this, void 0, void 0, function* () {
                const taskBeginTime = process.hrtime();
                // 执行具体的 Hvigor 任务
                yield process_utils.processUtils(opts, env);
                const taskEndTime = process.hrtime(taskBeginTime);
                const realTime = pretty_hrtime.default)(taskEndTime);
                if (0 == profile_js.profile.executed) {
                    _log.error(`No task found to execute in project!`);
                }
                _log.info(`BUILD SUCCESSFUL in ${realTime}`);
            });
        });
    });
}
​

执行具体的 Hvigor 的任务

// hvigor/src/process-utils.js
function processUtils(opts, env) {
    ···
    // 2. 初始化项目结构,创建 Project 和 Module 实例;
    init.init(env);
    // 3. 配置项目插件和任务流;
    const project = configuration.configuration(env);
    // 4. 执行任务流;
    const executeMode = env.configProps.get(modeAlias);
    switch (executeMode) {
       ···
    }
}

1. 加载命令行参数和环境变量

读取命令行参数,并把参数和配置文件的路径放入全局配置项中。

// hvigor/src/init-env-config-props.js
function initEnvConfigProps(env, opts) {
    ···
    // 获取项目级别 build-profile.json5 文件路径,[项目路径]/build-profile.json5
    const configFilePath = path.resolve(process.cwd(), hvigor_base.HvigorCommonConst.PROJECT_CONFIG_FILE);
    ···
    const properties = new Map();
    // 获取命令行 prop(p) 参数,放入 Map 中
    if (opts.prop !== undefined) {
        [].concat(opts.prop).forEach((value) => {
            const arr = value.split('=');
            properties.set(arr[0], arr[1]);
        });
    }
    // 把"项目级别 build-profile.json5 文件路径"、"命令行 prop(p) 参数集合"和"命令行 mode(m) 模式参数"配置进环境变量中
    env.configProps = new Map([
        [configFileName, configFilePath],
        [propertiesAlias, properties],
        [modeAlias, opts.mode]
    ]);
    return configFilePath;
}
​

2. 初始化项目结构,创建 Project 和 Module 实例

工程结构实例化。

// hvigor/src/lifecycle/init.js
function init(env) {
    // env.modulePath 是在命令行辅助工具 LiftOff 中加载的模块函数,"modulePath": "[项目路径]/node_modules/@ohos/hvigor-base/index.js",
    const vigorConfigInst = require(env.modulePath).vigorConfigInst;
    // 把从命令行加载来的 prop(p) 参数放入 vigorConfigInst 实体的 ExtraConfig 中
    vigorConfigInst.setExtraConfig(env.configProps.get(propertiesAlias));
    // 初始化项目,参数:[项目路径]/build-profile.json5,[项目路径]
    vigorConfigInst.initRootProject(path.resolve(env.cwd, hvigor_base.HvigorCommonConst.PROJECT_CONFIG_FILE), env.cwd);
}
​
// hvigor-base/index.js
exports.vigorConfigInst = new VigorConfig();
class VigorConfig {
    constructor() {
        this._log = hvigor_log_js.HvigorLogger.getLogger(VigorConfig.name);
        this._project = undefined;
        this._projectDir = "";
        this._projectConfigFile = "";
        this._extraConfig = new Map();
    }
    ···
    // 初始化项目,参数:[项目路径]/build-profile.json5,[项目路径]
    initRootProject(projectConfigFile, projectRootDir) {
        // 配置项目级别 build-profile.json5 文件路径
        this._projectConfigFile = projectConfigFile;
        // 配置项目根路径
        this._projectDir = projectRootDir;
        // 创建项目实例,参数:[项目名称],[项目路径]
        const projectImpl = new project_impl_js.ProjectImpl(path.basename(projectRootDir), projectRootDir);
        // 读取 [项目路径]/build-profile.json5 配置数据
        const projectStructureOpt = json5_reader_js.Json5Reader.getJson5Obj(this._projectConfigFile);
        ···
        // 从配置文件中读取项目下的全部 Modules 
        projectStructureOpt.modules?.forEach(module => {
            // 校验 Module 配置参数
            validate_util_js.ValidateUtil.validateModule(module);
            // 添加子项目,根据配置文件中 Modules 循环创建 Module 实例,参数:项目实例,Module 名称,Module 的路径
            projectImpl.addSubProject(new module_impl_js.ModuleImpl(projectImpl, module.name, module.srcPath));
        });
        this._project = projectImpl;
        return projectImpl;
    }
}
class ValidateUtil {
    static validateModule(module) {
        if (module.name === undefined) {
            this.logger.errorMessageExit(`Project level build-profile.json5 lose required property: module-name`);
        }
        if (module.srcPath === undefined) {
            this.logger.errorMessageExit(`Project level build-profile.json5 lose required property: module-srcPath`);
        }
    }
}
​

Project 实现类

// hvigor-base/src/impl/project-impl.js
class ProjectImpl extends default_module_impl.DefaultModuleImpl {
    constructor(moduleName, moduleDir) {
        super(moduleName, moduleDir);
        // 配置项目级别 build-profile.json5 文件路径
        this._projectStructureFile = path.resolve(moduleDir, common_const.HvigorCommonConst.PROJECT_CONFIG_FILE);
        this._subProjects = new Map();
    }
    ···
}

Module 实现类

// hvigor-base/src/impl/module-impl.js
class ModuleImpl extends default_module_impl.DefaultModuleImpl {
    constructor(project, moduleName, moduleDir) {
        super(moduleName, moduleDir);
        this._project = project;
    }
    ···
}
​

默认 Module 实现类

// hvigor-base/src/impl/default-module-impl.js
class DefaultModuleImpl {
    constructor(moduleName, modulePath) {
        this._moduleName = moduleName;
        this._modulePath = modulePath;
        // 获取项目和模块的 package.json 文件路径
        this._packageJsonPath = path.resolve(modulePath, "package.json");
        // 获取项目和模块的 hvigorfile.js 文件路径
        this._buildFilePath = path.resolve(modulePath, common_const.HvigorCommonConst.BUILD_FILE_NAME);
    }
    ···
}
​

3. 配置项目插件和任务流

加载 hvigorfile.js 文件中配置的任务脚本。

// hvigor/src/lifecycle/configuration.js
function configuration(env) {
    // 整个项目的结构在 init 中初始化完成,读取 vigorConfigInst
    const vigorConfigInst = require(env.modulePath).vigorConfigInst;
    // 通过 vigorConfigInst 获取项目实例
    const project = vigorConfigInst.getProject();
    // 获取项目全部的 Module 实例,遍历加载任务脚本
    for (const subModule of project.getAllSubProjects()) {
        // 获取 Module 的 hvigorfile.js 文件路径
        const subModuleVigorFileJs = subModule.getBuildFilePath();
        // 加载任务脚本
        configModule(subModule, subModuleVigorFileJs);
    }
    // 获取 Project 的 hvigorfile.js 文件路径
    const projectVigorFileJs = path.resolve(env.cwd, hvigor_base.HvigorCommonConst.BUILD_FILE_NAME);
    // 加载任务脚本
    configModule(project, projectVigorFileJs);
    return project;
}

function configModule(module, hvigorFilePath) {
    // FA 模型
    // 工程级别
    // module.exports = require('@ohos/hvigor-ohos-plugin').legacyAppTasks
    // 模块级别
    // module.exports = require('@ohos/hvigor-ohos-plugin').legacyHapTasks
    // module.e
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值