Skip to content

Commit

Permalink
Some updates to the Dev UI (#198)
Browse files Browse the repository at this point in the history
* Some updates to the Dev UI

Signed-off-by: Phillip Kruger <[email protected]>

* Use Scanned Web Dependencies and fix root path for assets

* Add generated entrypoints and mixed static output

* Fix quarkus version

* fix entrypoints size

---------

Signed-off-by: Phillip Kruger <[email protected]>
Co-authored-by: Andy Damevin <[email protected]>
  • Loading branch information
phillip-kruger and ia3andy authored May 3, 2024
1 parent f7c2fec commit 5fb6f87
Show file tree
Hide file tree
Showing 20 changed files with 718 additions and 70 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,4 @@ pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
release.properties
nbactions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ void collect(ProjectResourcesScannerBuildItem scanner,
for (WebAsset webAsset : assets) {
BundleType bundleType = entryPoint
// If it's not the entry point we consider it as a manual asset (imported by the entry point)
.map(ep -> webAsset.equals(ep) ? BundleType.ENTRYPOINT : BundleType.MANUAL)
.map(ep -> webAsset.equals(ep) ? BundleType.INDEX : BundleType.MANUAL)
// When there is no entry point we consider it as a auto asset unless it's a sass import file (_*.sass)
.orElse(isImportSassFile(webAsset.resourceName()) ? BundleType.MANUAL : BundleType.AUTO);
bundleAssets.get(entryPointKey).add(new BundleWebAsset(webAsset, bundleType));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
public record BundleWebAsset(WebAsset webAsset, BundleType type) implements WebAsset {

public enum BundleType {
ENTRYPOINT("entry-point"), // index.js, index.ts, index.jsx, index.tsx
GENERATED_ENTRY_POINT("generated entry-point"), // a named generated entry-point main.js, page1.js
INDEX("custom index"), // index.js, index.ts, index.jsx, index.tsx
MANUAL("available for import"), // Add this to the working directory but do not bundle it (the entrypoint may import it)
AUTO("auto-imported") // Add this to the working directory and index it automatically as part of the bundle
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.quarkiverse.web.bundler.deployment.items.QuteTemplatesBuildItem;
import io.quarkiverse.web.bundler.deployment.items.WebAsset;
import io.quarkiverse.web.bundler.deployment.web.GeneratedWebResourceBuildItem;
import io.quarkiverse.web.bundler.deployment.web.GeneratedWebResourceBuildItem.SourceType;
import io.quarkiverse.web.bundler.runtime.Bundle;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
Expand Down Expand Up @@ -72,7 +73,7 @@ public Set<String> names() {
final byte[] bytes = webAsset.contentOrReadFromFile();
final String content = engine.parse(new String(bytes, webAsset.charset())).render();
makeWebAssetPublic(staticResourceProducer, prefixWithSlash(webAsset.pathFromWebRoot(config.webRoot())),
HtmlPageWebAsset.of(webAsset, content));
HtmlPageWebAsset.of(webAsset, content), SourceType.BUILD_TIME_TEMPLATE);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.quarkiverse.web.bundler.deployment.items.StaticAssetsBuildItem;
import io.quarkiverse.web.bundler.deployment.items.WebAsset;
import io.quarkiverse.web.bundler.deployment.web.GeneratedWebResourceBuildItem;
import io.quarkiverse.web.bundler.deployment.web.GeneratedWebResourceBuildItem.SourceType;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;

Expand All @@ -20,35 +21,38 @@ void processStaticWebAssets(WebBundlerConfig config,
BuildProducer<GeneratedWebResourceBuildItem> staticResourceProducer) {
for (WebAsset webAsset : staticAssets.getWebAssets()) {
final String publicPath = webAsset.pathFromWebRoot(config.webRoot());
makeWebAssetPublic(staticResourceProducer, prefixWithSlash(publicPath), webAsset);
makeWebAssetPublic(staticResourceProducer, prefixWithSlash(publicPath), webAsset, SourceType.STATIC_ASSET);
}
}

static void makeWebAssetPublic(
BuildProducer<GeneratedWebResourceBuildItem> staticResourceProducer,
String publicPath,
WebAsset webAsset) {
WebAsset webAsset,
SourceType sourceType) {
handleStaticResource(
staticResourceProducer,
publicPath,
webAsset.contentOrReadFromFile());
webAsset.contentOrReadFromFile(),
sourceType);
}

static void makePublic(BuildProducer<GeneratedWebResourceBuildItem> staticResourceProducer, String publicPath,
Path file) {
Path file, SourceType sourceType) {
if (!Files.exists(file)) {
return;
}
handleStaticResource(staticResourceProducer, publicPath, readTemplateContent(file));
handleStaticResource(staticResourceProducer, publicPath, readTemplateContent(file), sourceType);
}

private static void handleStaticResource(
BuildProducer<GeneratedWebResourceBuildItem> staticResourceProducer,
String publicPath,
byte[] content) {
byte[] content,
SourceType sourceType) {
staticResourceProducer.produce(new GeneratedWebResourceBuildItem(
publicPath,
content));
content, sourceType));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static io.quarkiverse.web.bundler.deployment.BundleWebAssetsScannerProcessor.MAIN_ENTRYPOINT_KEY;
import static io.quarkiverse.web.bundler.deployment.StaticWebAssetsProcessor.makePublic;
import static io.quarkiverse.web.bundler.deployment.items.BundleWebAsset.BundleType.GENERATED_ENTRY_POINT;
import static io.quarkiverse.web.bundler.deployment.items.BundleWebAsset.BundleType.MANUAL;
import static io.quarkiverse.web.bundler.deployment.util.PathUtils.join;
import static io.quarkiverse.web.bundler.deployment.util.PathUtils.prefixWithSlash;
Expand All @@ -12,6 +13,7 @@

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand Down Expand Up @@ -40,14 +42,10 @@
import io.mvnpm.esbuild.model.EsBuildConfig;
import io.mvnpm.esbuild.model.EsBuildConfigBuilder;
import io.quarkiverse.web.bundler.deployment.WebBundlerConfig.LoadersConfig;
import io.quarkiverse.web.bundler.deployment.items.BundleConfigAssetsBuildItem;
import io.quarkiverse.web.bundler.deployment.items.BundleWebAsset;
import io.quarkiverse.web.bundler.deployment.items.EntryPointBuildItem;
import io.quarkiverse.web.bundler.deployment.items.GeneratedBundleBuildItem;
import io.quarkiverse.web.bundler.deployment.items.WebAsset;
import io.quarkiverse.web.bundler.deployment.items.WebDependenciesBuildItem;
import io.quarkiverse.web.bundler.deployment.items.*;
import io.quarkiverse.web.bundler.deployment.items.WebDependenciesBuildItem.Dependency;
import io.quarkiverse.web.bundler.deployment.web.GeneratedWebResourceBuildItem;
import io.quarkiverse.web.bundler.deployment.web.GeneratedWebResourceBuildItem.SourceType;
import io.quarkiverse.web.bundler.runtime.Bundle;
import io.quarkiverse.web.bundler.runtime.BundleRedirectHandlerRecorder;
import io.quarkiverse.web.bundler.runtime.WebBundlerBuildRecorder;
Expand Down Expand Up @@ -103,6 +101,7 @@ void bundle(WebBundlerConfig config,
Optional<BundleConfigAssetsBuildItem> bundleConfig,
BuildProducer<GeneratedWebResourceBuildItem> staticResourceProducer,
BuildProducer<GeneratedBundleBuildItem> generatedBundleProducer,
BuildProducer<GeneratedEntryPointBuildItem> generatedEntryPointProducer,
LiveReloadBuildItem liveReload,
LaunchModeBuildItem launchMode,
OutputTargetBuildItem outputTarget) throws BuildException {
Expand All @@ -123,6 +122,7 @@ void bundle(WebBundlerConfig config,
final boolean isLiveReload = liveReload.isLiveReload()
&& bundlesBuildContext != null
&& bundlesBuildContext.bundleDistDir() != null;
final Path targetDir = outputTarget.getOutputDirectory().resolve(TARGET_DIR_NAME);
if (isLiveReload
&& Objects.equals(webDependencies.list(), bundlesBuildContext.dependencies())
&& !liveReload.getChangedResources().contains(config.fromWebRoot("tsconfig.json"))
Expand All @@ -134,9 +134,10 @@ void bundle(WebBundlerConfig config,
LOGGER.debug("Bundling not needed for live reload");
handleBundleDistDir(config, generatedBundleProducer, staticResourceProducer, bundlesBuildContext.bundleDistDir(),
null, false);
processGeneratedEntryPoints(config, targetDir, generatedEntryPointProducer);
return;
}
final Path targetDir = outputTarget.getOutputDirectory().resolve(TARGET_DIR_NAME);

final Path nodeModulesDir = resolveNodeModulesDir(config, outputTarget);
try {
if (!isLiveReload) {
Expand Down Expand Up @@ -253,6 +254,7 @@ void bundle(WebBundlerConfig config,

handleBundleDistDir(config, generatedBundleProducer, staticResourceProducer, result.dist(), startedBundling,
true);
processGeneratedEntryPoints(config, targetDir, generatedEntryPointProducer);
liveReload.setContextObject(BundlesBuildContext.class,
new BundlesBuildContext(webDependencies.list(), entryPoints, result.dist()));

Expand All @@ -264,6 +266,25 @@ void bundle(WebBundlerConfig config,
}
}

private void processGeneratedEntryPoints(WebBundlerConfig config, Path targetDir,
BuildProducer<GeneratedEntryPointBuildItem> generatedEntryPointProducer) {
try (Stream<Path> generatedEPStream = Files.find(targetDir, 1, (path, basicFileAttributes) -> Files.isRegularFile(path)
&& path.getFileName().toString().toLowerCase().endsWith(".js"))) {
generatedEPStream
.forEach(p -> {
final String key = p.getFileName().toString().replace(".js", "");
final DefaultWebAsset wa = new DefaultWebAsset(join(config.webRoot(), p.getFileName().toString()), p,
Charset.defaultCharset());
generatedEntryPointProducer
.produce(new GeneratedEntryPointBuildItem(key, new BundleWebAsset(wa, GENERATED_ENTRY_POINT)));
});

} catch (IOException e) {
throw new UncheckedIOException(e);
}

}

private static Path resolveNodeModulesDir(WebBundlerConfig config, OutputTargetBuildItem outputTarget) {
if (config.dependencies().nodeModules().isEmpty()) {
return outputTarget.getOutputDirectory().resolve(BundleOptions.NODE_MODULES);
Expand Down Expand Up @@ -321,7 +342,7 @@ void handleBundleDistDir(WebBundlerConfig config, BuildProducer<GeneratedBundleB
if (config.shouldQuarkusServeBundle()) {
// The root-path will already be added by the static resources handler
final String resourcePath = surroundWithSlashes(config.bundlePath()) + relativePath;
makePublic(staticResourceProducer, resourcePath, path.normalize());
makePublic(staticResourceProducer, resourcePath, path.normalize(), SourceType.BUNDLED_ASSET);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ private void checkScope(LaunchModeBuildItem launchMode, ResolvedDependency d, We

private static Dependency toWebDep(ResolvedDependency d) {
return d.getResolvedPaths().stream().filter(p -> p.getFileName().toString().endsWith(".jar")).findFirst()
.map(j -> new Dependency(d.toCompactCoords(), j, resolveType(d.toCompactCoords()).orElseThrow(), d.isDirect()))
.map(j -> new Dependency(d, d.toCompactCoords(), j, resolveType(d.toCompactCoords()).orElseThrow(),
d.isDirect()))
.orElse(null);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.quarkiverse.web.bundler.deployment.devui;

import java.util.List;

import io.quarkus.builder.item.SimpleBuildItem;

public final class DevUIWebDependenciesBuildItem extends SimpleBuildItem {
private final List<DevUIWebDependency> webDependencies;

public DevUIWebDependenciesBuildItem(List<DevUIWebDependency> webDependencies) {

this.webDependencies = webDependencies;
}

public List<DevUIWebDependency> getWebDependencies() {
return this.webDependencies;
}

record WebDependencyAsset(String name,
List<WebDependencyAsset> children,
boolean fileAsset,
String urlPart) {
}

public record DevUIWebDependency(String type,
String webDependencyName,
String version,
WebDependencyAsset rootAsset) {
}
}
Original file line number Diff line number Diff line change
@@ -1,86 +1,112 @@
package io.quarkiverse.web.bundler.deployment.devui;

import static io.quarkiverse.web.bundler.deployment.devui.WebBundlerDevUIWebDependenciesProcessor.resolveFromRootPath;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import io.quarkiverse.web.bundler.deployment.WebBundlerConfig;
import io.quarkiverse.web.bundler.deployment.items.*;
import io.quarkiverse.web.bundler.deployment.web.GeneratedWebResourceBuildItem;
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.devui.spi.page.CardPageBuildItem;
import io.quarkus.devui.spi.page.Page;
import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig;

public class WebBundlerDevUIProcessor {

@BuildStep(onlyIf = IsDevelopment.class)
public void createPages(WebBundlerConfig config,
HttpBuildTimeConfig httpConfig,
BuildProducer<CardPageBuildItem> cardPageProducer,
List<EntryPointBuildItem> entryPoints,
List<GeneratedEntryPointBuildItem> generatedEntryPoints,
WebDependenciesBuildItem webDependencies,
StaticAssetsBuildItem staticAssets,
QuteTemplatesBuildItem htmlAssets) {
List<GeneratedWebResourceBuildItem> generatedWebResources,
DevUIWebDependenciesBuildItem devUIWebDependencies) {

CardPageBuildItem cardPageBuildItem = new CardPageBuildItem();

if (!webDependencies.isEmpty()) {
cardPageBuildItem.addBuildTimeData("webDependencies", webDependencies.list());
cardPageBuildItem.addPage(Page.tableDataPageBuilder("Web Dependencies")
.icon("font-awesome-solid:table")
.showColumn("id")
.showColumn("type")
.showColumn("direct")
.staticLabel(String.valueOf(webDependencies.list().size()))
.buildTimeDataKey("webDependencies"));
// Web Dependency Libraries
cardPageBuildItem.addBuildTimeData("webDependencies", devUIWebDependencies.getWebDependencies());

cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.componentLink("qwc-web-bundler-web-dependencies.js")
.title("Web Dependencies")
.icon("font-awesome-brands:square-js")
.staticLabel(String.valueOf(webDependencies.list().size())));

}
final Map<String, EntryPointItem> generatedEntryPointsMap = generatedEntryPoints.stream()
.collect(
Collectors.toMap(GeneratedEntryPointBuildItem::key,
e -> new EntryPointItem(e.webAsset().pathFromWebRoot(config.webRoot()),
e.webAsset().type().label(), new String(e.webAsset().contentOrReadFromFile())),
(a, b) -> b));

if (!entryPoints.isEmpty()) {
final List<EntryPoint> entryPointsForDevUI = entryPoints.stream()
.map(e -> new EntryPoint(e.getEntryPointKey(), getEntryPointItems(config, generatedEntryPointsMap, e)))
.toList();

cardPageBuildItem.addBuildTimeData("entryPoints",
entryPoints.stream().map(e -> new EntryPoint(e.getEntryPointKey(), e.getWebAssets().stream()
.map(a -> new EntryPointItem(a.webAsset().pathFromWebRoot(config.webRoot()), a.type().label()))
.toList()))
.toList());
entryPointsForDevUI);

cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.componentLink("qwc-web-bundler-entry-points.js")
.title("Entry Points")
.icon("font-awesome-solid:folder-tree")
.staticLabel(String.valueOf(webDependencies.list().size())));
.staticLabel(String.valueOf(entryPointsForDevUI.size())));

}

if (!htmlAssets.getWebAssets().isEmpty()) {
cardPageBuildItem.addBuildTimeData("htmlAssets", htmlAssets.getWebAssets().stream()
.map(s -> new WebAsset(s.pathFromWebRoot(config.webRoot()))).toList());
cardPageBuildItem.addPage(Page.tableDataPageBuilder("Html templates")
.icon("font-awesome-solid:table")
.showColumn("path")
.staticLabel(String.valueOf(htmlAssets.getWebAssets().size()))
.buildTimeDataKey("htmlAssets"));
if (!generatedWebResources.isEmpty()) {
final List<WebAsset> assets = generatedWebResources.stream()
.sorted(Comparator.comparing(w -> w.type().order()))
.map(w -> new WebAsset(resolveFromRootPath(httpConfig, w.publicPath()), w.type().label(),
new String(w.content())))

}

if (!staticAssets.getWebAssets().isEmpty()) {
cardPageBuildItem.addBuildTimeData("staticAssets", staticAssets.getWebAssets().stream()
.map(s -> new WebAsset(s.pathFromWebRoot(config.webRoot()))).toList());
cardPageBuildItem.addPage(Page.tableDataPageBuilder("Static Assets")
.icon("font-awesome-solid:table")
.showColumn("path")
.staticLabel(String.valueOf(staticAssets.getWebAssets().size()))
.buildTimeDataKey("staticAssets"));
.toList();

cardPageBuildItem.addBuildTimeData("staticAssets", assets);
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.componentLink("qwc-web-bundler-output.js")
.title("Static Output")
.icon("font-awesome-solid:arrow-right-from-bracket")
.staticLabel(String.valueOf(assets.size())));
}

cardPageProducer.produce(cardPageBuildItem);
}

record WebAsset(String path) {
private static List<EntryPointItem> getEntryPointItems(WebBundlerConfig config,
Map<String, EntryPointItem> generatedEntryPoints, EntryPointBuildItem e) {
final List<EntryPointItem> list = new ArrayList<>();
if (generatedEntryPoints.containsKey(e.getEntryPointKey())) {
list.add(generatedEntryPoints.get(e.getEntryPointKey()));
}
list.addAll(e.getWebAssets().stream()
.map(a -> new EntryPointItem(
a.webAsset().pathFromWebRoot(config.webRoot()),
a.type().label(),
new String(a.webAsset().contentOrReadFromFile())))
.toList());
return list;
}

record WebAsset(String path, String type, String content) {
}

record EntryPoint(String key, List<EntryPointItem> items) {
}

record EntryPointItem(String path, String type) {
record EntryPointItem(String path, String type, String content) {
}

}
Loading

0 comments on commit 5fb6f87

Please sign in to comment.