Skip to content

Commit

Permalink
Use new generated static resources (#686)
Browse files Browse the repository at this point in the history
Co-authored-by: Melloware <[email protected]>
  • Loading branch information
ia3andy and melloware authored Jun 13, 2024
1 parent cbbf5f6 commit 5ca8d25
Show file tree
Hide file tree
Showing 19 changed files with 112 additions and 315 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import static io.quarkiverse.quinoa.QuinoaRecorder.QUINOA_ROUTE_ORDER;
import static io.quarkiverse.quinoa.QuinoaRecorder.QUINOA_SPA_ROUTE_ORDER;
import static io.quarkiverse.quinoa.deployment.config.QuinoaConfig.isDevServerMode;
import static io.quarkiverse.quinoa.deployment.config.QuinoaConfig.toHandlerConfig;
import static io.quarkiverse.quinoa.deployment.config.QuinoaConfig.toDevProxyHandlerConfig;
import static io.quarkiverse.quinoa.deployment.packagemanager.PackageManagerRunner.DEV_PROCESS_THREAD_PREDICATE;
import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT;
import static io.quarkus.deployment.dev.testing.MessageFormat.RESET;
Expand All @@ -28,7 +28,7 @@

import org.jboss.logging.Logger;

import io.quarkiverse.quinoa.QuinoaHandlerConfig;
import io.quarkiverse.quinoa.QuinoaDevProxyHandlerConfig;
import io.quarkiverse.quinoa.QuinoaRecorder;
import io.quarkiverse.quinoa.deployment.config.DevServerConfig;
import io.quarkiverse.quinoa.deployment.config.QuinoaConfig;
Expand Down Expand Up @@ -204,7 +204,7 @@ public void runtimeInit(
return;
}
LOG.infof("Quinoa is forwarding unhandled requests to port: %d", devProxy.get().getPort());
final QuinoaHandlerConfig handlerConfig = toHandlerConfig(quinoaConfig, true, httpBuildTimeConfig);
final QuinoaDevProxyHandlerConfig handlerConfig = toDevProxyHandlerConfig(quinoaConfig, httpBuildTimeConfig);
routes.produce(RouteBuildItem.builder().orderedRoute("/*", QUINOA_ROUTE_ORDER)
.handler(recorder.quinoaProxyDevHandler(handlerConfig, vertx.getVertx(), devProxy.get().getHost(),
devProxy.get().getPort(),
Expand All @@ -216,7 +216,7 @@ public void runtimeInit(
if (quinoaConfig.enableSPARouting()) {
resumeOn404.produce(new ResumeOn404BuildItem());
routes.produce(RouteBuildItem.builder().orderedRoute("/*", QUINOA_SPA_ROUTE_ORDER)
.handler(recorder.quinoaSPARoutingHandler(handlerConfig))
.handler(recorder.quinoaSPARoutingHandler(handlerConfig.ignoredPathPrefixes))
.build());
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package io.quarkiverse.quinoa.deployment;

import static io.quarkiverse.quinoa.QuinoaRecorder.META_INF_WEB_UI;
import static io.quarkiverse.quinoa.QuinoaRecorder.QUINOA_ROUTE_ORDER;
import static io.quarkiverse.quinoa.QuinoaRecorder.QUINOA_SPA_ROUTE_ORDER;
import static io.quarkiverse.quinoa.deployment.config.QuinoaConfig.isDevServerMode;
import static io.quarkiverse.quinoa.deployment.config.QuinoaConfig.isEnabled;
import static io.quarkiverse.quinoa.deployment.config.QuinoaConfig.toHandlerConfig;
import static io.quarkiverse.quinoa.deployment.config.QuinoaConfig.*;
import static io.quarkiverse.quinoa.deployment.framework.FrameworkType.overrideConfig;
import static io.quarkiverse.quinoa.deployment.packagemanager.PackageManagerRunner.autoDetectPackageManager;
import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT;
Expand All @@ -30,7 +26,6 @@

import org.jboss.logging.Logger;

import io.quarkiverse.quinoa.QuinoaHandlerConfig;
import io.quarkiverse.quinoa.QuinoaRecorder;
import io.quarkiverse.quinoa.deployment.config.QuinoaConfig;
import io.quarkiverse.quinoa.deployment.framework.FrameworkType;
Expand All @@ -42,23 +37,19 @@
import io.quarkiverse.quinoa.deployment.packagemanager.PackageManagerRunner;
import io.quarkiverse.quinoa.deployment.packagemanager.types.PackageManagerType;
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.IsNormal;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.GeneratedResourceBuildItem;
import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem;
import io.quarkus.deployment.builditem.LaunchModeBuildItem;
import io.quarkus.deployment.builditem.LiveReloadBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem;
import io.quarkus.deployment.util.FileUtil;
import io.quarkus.resteasy.reactive.server.spi.ResumeOn404BuildItem;
import io.quarkus.runtime.LaunchMode;
import io.quarkus.runtime.configuration.ConfigurationException;
import io.quarkus.vertx.http.deployment.RouteBuildItem;
import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig;
import io.quarkus.vertx.http.deployment.spi.GeneratedStaticResourceBuildItem;

public class QuinoaProcessor {

Expand Down Expand Up @@ -198,28 +189,12 @@ && isDevServerMode(configuredQuinoa.resolvedConfig())) {
return new TargetDirBuildItem(targetBuildDir);
}

@BuildStep(onlyIf = IsNormal.class)
public BuiltResourcesBuildItem prepareResourcesForNormalMode(
Optional<TargetDirBuildItem> targetDir,
BuildProducer<GeneratedResourceBuildItem> generatedResources,
BuildProducer<NativeImageResourceBuildItem> nativeImageResources) throws IOException {
if (targetDir.isEmpty()) {
return null;
}
return new BuiltResourcesBuildItem(
prepareBuiltResources(generatedResources, nativeImageResources, targetDir.get().getBuildDirectory()));
}

@BuildStep(onlyIfNot = IsNormal.class)
public BuiltResourcesBuildItem prepareResourcesForOtherMode(
Optional<TargetDirBuildItem> targetDir,
BuildProducer<GeneratedResourceBuildItem> generatedResources) throws IOException {
@BuildStep
public BuiltResourcesBuildItem prepareBuiltResources(Optional<TargetDirBuildItem> targetDir) throws IOException {
if (targetDir.isEmpty()) {
return null;
}
final HashSet<BuiltResourcesBuildItem.BuiltResource> entries = prepareBuiltResources(generatedResources,
null, targetDir.get().getBuildDirectory());
return new BuiltResourcesBuildItem(targetDir.get().getBuildDirectory(), entries);
return new BuiltResourcesBuildItem(lookupBuiltResources(targetDir.get().getBuildDirectory()));
}

@BuildStep(onlyIf = IsDevelopment.class)
Expand All @@ -240,60 +215,56 @@ void watchChanges(
scan(quinoaDir.get().uiDir(), quinoaDir.get().uiDir(), watchedPaths);
}

@BuildStep
public void produceGeneratedStaticResources(
ConfiguredQuinoaBuildItem configuredQuinoa,
BuildProducer<GeneratedStaticResourceBuildItem> generatedStaticResourceProducer,
Optional<BuiltResourcesBuildItem> uiResources) throws IOException {
if (configuredQuinoa != null && configuredQuinoa.resolvedConfig().justBuild()) {
LOG.info("Quinoa is in build only mode");
return;
}
if (uiResources.isPresent() && !uiResources.get().resources().isEmpty()) {
for (BuiltResourcesBuildItem.BuiltResource resource : uiResources.get().resources()) {
generatedStaticResourceProducer
.produce(new GeneratedStaticResourceBuildItem(resource.name(), resource.content()));
}
}
}

@BuildStep
@Record(RUNTIME_INIT)
public void runtimeInit(
ConfiguredQuinoaBuildItem configuredQuinoa,
HttpBuildTimeConfig httpBuildTimeConfig,
LaunchModeBuildItem launchMode,
Optional<BuiltResourcesBuildItem> uiResources,
QuinoaRecorder recorder,
BuildProducer<RouteBuildItem> routes,
BuildProducer<ResumeOn404BuildItem> resumeOn404) throws IOException {
Optional<BuiltResourcesBuildItem> uiResources) throws IOException {
if (configuredQuinoa != null && configuredQuinoa.resolvedConfig().justBuild()) {
LOG.info("Quinoa is in build only mode");
return;
}
if (uiResources.isPresent() && !uiResources.get().getNames().isEmpty()) {
String directory = null;
if (uiResources.get().getDirectory().isPresent()) {
directory = uiResources.get().getDirectory().get().toAbsolutePath().toString();
}
final QuinoaHandlerConfig handlerConfig = toHandlerConfig(configuredQuinoa.resolvedConfig(),
launchMode.getLaunchMode() == LaunchMode.DEVELOPMENT,
httpBuildTimeConfig);
resumeOn404.produce(new ResumeOn404BuildItem());
routes.produce(RouteBuildItem.builder().orderedRoute("/*", QUINOA_ROUTE_ORDER)
.handler(recorder.quinoaHandler(handlerConfig, directory,
uiResources.get().getNames()))
.build());
if (uiResources.isPresent() && !uiResources.get().resources().isEmpty()) {
if (configuredQuinoa.resolvedConfig().enableSPARouting()) {
routes.produce(RouteBuildItem.builder().orderedRoute("/*", QUINOA_SPA_ROUTE_ORDER)
.handler(recorder.quinoaSPARoutingHandler(handlerConfig))
.handler(recorder
.quinoaSPARoutingHandler(getNormalizedIgnoredPathPrefixes(configuredQuinoa.resolvedConfig())))
.build());
}
}
}

private HashSet<BuiltResourcesBuildItem.BuiltResource> prepareBuiltResources(
BuildProducer<GeneratedResourceBuildItem> generatedResources,
BuildProducer<NativeImageResourceBuildItem> nativeImageResources,
Path targetDir) throws IOException {
final List<Path> files = Files.walk(targetDir, FileVisitOption.FOLLOW_LINKS).filter(Files::isRegularFile)
.collect(Collectors.toList());
final HashSet<BuiltResourcesBuildItem.BuiltResource> entries = new HashSet<>(files.size());
LOG.infof("Quinoa target directory: '%s'", targetDir);
for (Path file : files) {
final String name = "/" + targetDir.relativize(file).toString().replace('\\', '/');
LOG.infof("Quinoa generated resource: '%s'", name);
generatedResources.produce(new GeneratedResourceBuildItem(META_INF_WEB_UI + name, Files.readAllBytes(file), true));
if (nativeImageResources != null) {
nativeImageResources
.produce(new NativeImageResourceBuildItem(META_INF_WEB_UI + name));
private HashSet<BuiltResourcesBuildItem.BuiltResource> lookupBuiltResources(Path targetDir) throws IOException {
try (Stream<Path> paths = Files.walk(targetDir, FileVisitOption.FOLLOW_LINKS).filter(Files::isRegularFile)) {
final var files = paths.toList();
final HashSet<BuiltResourcesBuildItem.BuiltResource> entries = new HashSet<>(files.size());
LOG.infof("Quinoa target directory: '%s'", targetDir);
for (Path file : files) {
final String name = "/" + targetDir.relativize(file).toString().replace('\\', '/');
LOG.infof("Quinoa generated resource: '%s'", name);
entries.add(new BuiltResourcesBuildItem.BuiltResource(name, Files.readAllBytes(file)));
}
entries.add(new BuiltResourcesBuildItem.BuiltResource(name));
return entries;
}
return entries;

}

private void scan(Path uiDir, Path directory, BuildProducer<HotDeploymentWatchedFileBuildItem> watchedPaths)
Expand Down Expand Up @@ -454,4 +425,4 @@ public Path getUIDir() {
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public interface DevServerConfig {
/**
* Set this value if the index page is different for the dev-server
*/
@ConfigDocDefault("auto-detected falling back to the quinoa.index-page")
@ConfigDocDefault("auto-detected falling back to index.html")
Optional<String> indexPage();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;

import io.quarkiverse.quinoa.QuinoaHandlerConfig;
import io.quarkiverse.quinoa.QuinoaDevProxyHandlerConfig;
import io.quarkus.runtime.annotations.ConfigDocDefault;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
Expand Down Expand Up @@ -78,12 +78,6 @@ public interface QuinoaConfig {
*/
PackageManagerCommandConfig packageManagerCommand();

/**
* Name of the index page.
*/
@WithDefault(DEFAULT_INDEX_PAGE)
String indexPage();

/**
* Indicate if the Web UI should also be tested during the build phase (i.e: npm test).
* To be used in a {@link io.quarkus.test.junit.QuarkusTestProfile} to have Web UI test running during a
Expand Down Expand Up @@ -120,7 +114,7 @@ public interface QuinoaConfig {
boolean enableSPARouting();

/**
* List of path prefixes to be ignored by Quinoa.
* List of path prefixes to be ignored by Quinoa (SPA Handler and Dev-Proxy).
*/
@ConfigDocDefault("ignore values configured by 'quarkus.resteasy-reactive.path', 'quarkus.resteasy.path' and 'quarkus.http.non-application-root-path'")
Optional<List<String>> ignoredPathPrefixes();
Expand All @@ -135,28 +129,21 @@ static List<String> getNormalizedIgnoredPathPrefixes(QuinoaConfig config) {
Config allConfig = ConfigProvider.getConfig();
List<String> defaultIgnore = new ArrayList<>();
readExternalConfigPath(allConfig, "quarkus.resteasy.path").ifPresent(defaultIgnore::add);
readExternalConfigPath(allConfig, "quarkus.rest.path").ifPresent(defaultIgnore::add);
readExternalConfigPath(allConfig, "quarkus.resteasy-reactive.path").ifPresent(defaultIgnore::add);
readExternalConfigPath(allConfig, "quarkus.http.non-application-root-path").ifPresent(defaultIgnore::add);
return defaultIgnore;
}).stream().map(s -> s.startsWith("/") ? s : "/" + s).collect(toList());
}

static QuinoaHandlerConfig toHandlerConfig(QuinoaConfig config, boolean devMode,
static QuinoaDevProxyHandlerConfig toDevProxyHandlerConfig(final QuinoaConfig config,
final HttpBuildTimeConfig httpBuildTimeConfig) {
final Set<String> compressMediaTypes = httpBuildTimeConfig.compressMediaTypes.map(Set::copyOf).orElse(Set.of());
final String indexPage = resolveIndexPage(config, devMode);
return new QuinoaHandlerConfig(getNormalizedIgnoredPathPrefixes(config), indexPage, devMode,
return new QuinoaDevProxyHandlerConfig(getNormalizedIgnoredPathPrefixes(config),
config.devServer().indexPage().orElse(DEFAULT_INDEX_PAGE),
httpBuildTimeConfig.enableCompression, compressMediaTypes, config.devServer().directForwarding());
}

private static String resolveIndexPage(QuinoaConfig config, boolean devMode) {
if (!devMode) {
// Make sure we never return the devServer.indexPage() in non-dev mode
return config.indexPage();
}
return isDevServerMode(config) ? config.devServer().indexPage().orElse(config.indexPage()) : config.indexPage();
}

private static Optional<String> readExternalConfigPath(Config config, String key) {
return config.getOptionalValue(key, String.class)
.filter(s -> !Objects.equals(s, "/"))
Expand Down Expand Up @@ -193,9 +180,6 @@ static boolean isEqual(QuinoaConfig q1, QuinoaConfig q2) {
if (!PackageManagerCommandConfig.isEqual(q1.packageManagerCommand(), q2.packageManagerCommand())) {
return false;
}
if (!Objects.equals(q1.indexPage(), q2.indexPage())) {
return false;
}
if (!Objects.equals(q1.runTests(), q2.runTests())) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,6 @@ public PackageManagerCommandConfig packageManagerCommand() {
return delegate.packageManagerCommand();
}

@Override
public String indexPage() {
return delegate.indexPage();
}

@Override
public boolean runTests() {
return delegate.runTests();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package io.quarkiverse.quinoa.deployment.items;

import java.nio.file.Path;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

Expand All @@ -27,38 +25,10 @@ public Optional<Path> getDirectory() {
return directory;
}

public Set<String> getNames() {
Set<String> names = new HashSet<>(resources.size());
for (BuiltResource entry : resources) {
names.add(entry.getName());
}
return names;
public Set<BuiltResource> resources() {
return resources;
}

public static class BuiltResource {
private final String name;

public BuiltResource(String name) {
this.name = name;
}

public String getName() {
return name;
}

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
BuiltResource entry = (BuiltResource) o;
return name.equals(entry.name);
}

@Override
public int hashCode() {
return Objects.hash(name);
}
public record BuiltResource(String name, byte[] content) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ public class QuinoaAbsoluteUIDirTest {
assertThat(l)
.anyMatch(s -> s.getMessage().equals("Running Quinoa package manager build command: %s") &&
s.getParameters()[0].equals(systemBinary("npm") + " run build"));
assertThat(l)
.anyMatch(s -> s.getMessage().equals("Quinoa is ignoring paths starting with: /q/"));
});

static {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ public class QuinoaDefaultConfigTest {
assertThat(l)
.anyMatch(s -> s.getMessage().equals("Running Quinoa package manager build command: %s") &&
s.getParameters()[0].equals(systemBinary("npm") + " run build"));
assertThat(l)
.anyMatch(s -> s.getMessage().equals("Quinoa is ignoring paths starting with: /q/"));
});

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ public class QuinoaIgnorePathPrefixesConfigTest {
@RegisterExtension
static final QuarkusUnitTest config = QuinoaQuarkusUnitTest.create(NAME).toQuarkusUnitTest()
.overrideConfigKey("quarkus.quinoa.ignored-path-prefixes", "/foo/bar,/api,q,a/b")
.overrideConfigKey("quarkus.quinoa.enable-spa-routing", "true")
.assertLogRecords(l -> assertThat(l)
.anyMatch(s -> s.getMessage().equals("Quinoa is ignoring paths starting with: /foo/bar, /api, /q, /a/b")));
.anyMatch(s -> s.getMessage()
.equals("Quinoa SPA routing handler is ignoring paths starting with: /foo/bar, /api, /q, /a/b")));

@Test
public void testQuinoa() {
Expand Down
Loading

0 comments on commit 5ca8d25

Please sign in to comment.