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 核心还是利用了一些其他的现有开源工具,并不算一个完整的框架