Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Breaking][Requires Quarkus 3.12+] Use new generated static resources #686

Merged
merged 2 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.*;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Miss .* import

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am fixing in another PR

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