hilla maven 插件原理简单说明

hilla maven 插件的源码是分散在不同的代码库中,hilla 中包含一部分,flow 也包含一部分

插件参考使用

  • 参考使用
<plugin>
    <groupId>dev.hilla</groupId>
    <artifactId>hilla-maven-plugin</artifactId>
    <version>${hilla.version}</version>
    <executions>
        <execution>
            <goals>
                <goal>prepare-frontend</goal>
            </goals>
        </execution>
    </executions>
</plugin>
  • 支持的goals
    prepare-frontend,build-frontend,dance,clean-frontend

生成c/s 通信部分代码

就是一个标准的maven plugin 开发
代码位置:packages/java/maven-plugin/src/main/java/dev/hilla/maven/EndpointCodeGeneratorMojo.java
具体是基于openapi 然后生成typescript 定义 
java openapi java 代码生成部分

 
private String parseJavaCode() throws EndpointCodeGeneratorMojoException {
    try {
       //  hilla 设计提供了扩展点,可以基于插件扩展,同时基于类注解扫描只处理自己关心的类
        var executor = new ParserProcessor(project, getLog());
 
        parser.getClassPath().ifPresent(executor::classPath);
        parser.getEndpointAnnotation()
                .ifPresent(executor::endpointAnnotation);
        parser.getPlugins().ifPresent(executor::plugins);
        parser.getOpenAPIPath().ifPresent(executor::openAPIBase);
 
        return executor.process();
    } catch (ParserException e) {
        throw new EndpointCodeGeneratorMojoException(
                "Java code parsing failed", e);
    }
}

默认包含的插件
packages/java/maven-plugin/src/main/java/dev/hilla/maven/ParserConfiguration.java

 
 static class PluginsProcessor extends ConfigList.Processor<Plugin> {
        private static final Set<Plugin> defaults = Set.of(
                new Plugin(BackbonePlugin.class.getName()),
                new Plugin(NonnullPlugin.class.getName()),
                new Plugin(ModelPlugin.class.getName()));
 
        public PluginsProcessor() {
            super(defaults);
        }
    } 

openapi 处理部分
packages/java/maven-plugin/src/main/java/dev/hilla/maven/ParserProcessor.java

 
public String process() {
        var builder = new ParserConfig.Builder().classPath(classPath)
                .endpointAnnotation(endpointAnnotationName);
 
        preparePlugins(builder);
        prepareOpenAPIBase(builder);
 
        try {
            logger.debug("Starting JVM Parser");
            // 此处使用了core 部分的代码 packages/java/parser-jvm-core/src/main/java/dev/hilla/parser/core/Parser.java
            var openAPI = new Parser(builder.finish()).execute();
            var openAPIJSONString = new OpenAPIPrinter().writeAsString(openAPI);
 
            logger.debug("OpenAPI (JSON): " + openAPIJSONString);
 
            return openAPIJSONString;
        } catch (IOException e) {
            throw new ParserException(
                    "Failed processing OpenAPI generated from parsed Java code",
                    e);
        }
    }

typescript 生成部分
packages/java/maven-plugin/src/main/java/dev/hilla/maven/EndpointCodeGeneratorMojo.java

 
private void generateTypeScriptCode(String openAPI)
        throws EndpointCodeGeneratorMojoException {
    var logger = getLog();
    try {
        var executor = new GeneratorProcessor(project, logger)
                .input(openAPI).verbose(logger.isDebugEnabled());
 
        generator.getOutputDir().ifPresent(executor::outputDir);
        generator.getPlugins().ifPresent(executor::plugins);
 
        executor.process();
    } catch (IOException | InterruptedException | GeneratorException e) {
        throw new EndpointCodeGeneratorMojoException(
                "TS code generation failed", e);
    }
}

GeneratorProcessor 实际上是利用了openapi 以及nodejs 处理的
核心处理部分
packages/java/maven-plugin/src/main/java/dev/hilla/maven/GeneratorShellRunner.java

 
public GeneratorShellRunner(File baseDir, Log logger) {
    this.logger = logger;
 
    if (IS_WINDOWS) {
        arguments.add("cmd.exe");
        arguments.add("/c");
    } else if (IS_UNIX) {
        // TODO: Mac does not need that. Need to check if Unix does.
        arguments.add("/bin/bash");
        arguments.add("-c");
    }
 
    if (IS_WINDOWS) {
        arguments.add(Paths.get(baseDir.getAbsolutePath(), "node_modules",
                ".bin", "tsgen.cmd").toString());
    } else {
        arguments.add(Paths.get(baseDir.getAbsolutePath(), "node_modules",
                ".bin", "tsgen").toString());
    }
}
 

tsgen 代码
具体在packages/ts/generator-typescript-cli 中
hilla 自己基于nodejs 包装了一个基于openapi 生成ts 类型的cli,详细的可以参考此子模块代码

说明

如果只看hilla源码插件其他的能力是看不到的(build-frontend 等操作),需要在flow 代码的 flow-plugins/flow-maven-plugin 子模块中
还是比较期待官方对于插件代码更加明确,毕竟hilla 核心还是利用了一些其他的现有开源工具,并不算一个完整的框架

posted on 2022-03-13 10:37  荣锋亮  阅读(78)  评论(0编辑  收藏  举报

导航