Skip to content

Commit

Permalink
Introduce source-map config
Browse files Browse the repository at this point in the history
  • Loading branch information
ia3andy committed Apr 26, 2024
1 parent 298c2f0 commit ed0ba51
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,9 @@ default String fromWebRoot(String dir) {
String bundlePath();

/**
* The config for esbuild loaders https://esbuild.github.io/content-types/
* Configure bundling options
*/
LoadersConfig loaders();

/**
* This defines the list of external paths for esbuild (https://esbuild.github.io/api/#external).
* Instead of being bundled, the import will be preserved.
*/
@ConfigDocDefault("{quarkus.http.root-path}static/*")
Optional<List<String>> externalImports();

/**
* Enable or disable bundle splitting (https://esbuild.github.io/api/#splitting)
* Code shared between multiple entry points is split off into a separate shared file (chunk) that both entry points import
*/
@WithDefault("true")
Boolean bundleSplitting();
BundlingConfig bundling();

/**
* Configure how dependencies are collected
Expand Down Expand Up @@ -115,6 +101,41 @@ default boolean shouldQuarkusServeBundle() {
return !isExternalBundlePath();
}

interface BundlingConfig {
/**
* Enable or disable bundle splitting (https://esbuild.github.io/api/#splitting)
* Code shared between multiple entry points is split off into a separate shared file (chunk) that both entry points
* import
*/
@WithDefault("true")
Boolean splitting();

/**
* The config for esbuild loaders https://esbuild.github.io/content-types/
*/
LoadersConfig loaders();

/**
* This defines the list of external paths for esbuild (https://esbuild.github.io/api/#external).
* Instead of being bundled, the import will be preserved.
*/
@ConfigDocDefault("{quarkus.http.root-path}static/*")
Optional<List<String>> external();

/**
* Configuration for source-map generation (https://esbuild.github.io/api/#sourcemap)
*/
@WithDefault("linked")
String sourceMap();

default boolean sourceMapEnabled() {
return "linked".equalsIgnoreCase(sourceMap())
|| "true".equalsIgnoreCase(sourceMap())
|| "yes".equalsIgnoreCase(sourceMap());
}

}

interface WebDependenciesConfig {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,16 @@ void bundle(WebBundlerConfig config,
final EsBuildConfigBuilder esBuildConfigBuilder = new EsBuildConfigBuilder()
.loader(loaders)
.publicPath(config.publicBundlePath())
.splitting(config.bundleSplitting())
.splitting(config.bundling().splitting())
.minify(launchMode.getLaunchMode().equals(LaunchMode.NORMAL));
if (config.externalImports().isPresent()) {
for (String e : config.externalImports().get()) {
if (config.bundling().external().isPresent()) {
for (String e : config.bundling().external().get()) {
esBuildConfigBuilder.addExternal(e);
}
} else {
esBuildConfigBuilder.addExternal(join(config.httpRootPath(), "static/*"));
}
esBuildConfigBuilder.sourceMap(config.bundling().sourceMapEnabled());
final BundleOptionsBuilder optionsBuilder = new BundleOptionsBuilder()
.withWorkDir(targetDir)
.withDependencies(webDependencies.list().stream().map(Dependency::toEsBuildWebDependency).toList())
Expand Down Expand Up @@ -283,7 +284,7 @@ private Map<String, EsBuildConfig.Loader> computeLoaders(WebBundlerConfig config
Map<String, EsBuildConfig.Loader> loaders = new HashMap<>();
for (EsBuildConfig.Loader loader : EsBuildConfig.Loader.values()) {
final Function<LoadersConfig, Optional<Set<String>>> configFn = requireNonNull(LOADER_CONFIGS.get(loader));
final Optional<Set<String>> values = configFn.apply(config.loaders());
final Optional<Set<String>> values = configFn.apply(config.bundling().loaders());
if (values.isPresent()) {
for (String v : values.get()) {
final String ext = v.startsWith(".") ? v : "." + v;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ public class WebBundlerAutoImportTest {

@RegisterExtension
static final QuarkusUnitTest unitTest = new QuarkusUnitTest()
.withConfigurationResource("application-auto.properties")
.setForcedDependencies(
List.of(
new ArtifactDependency("org.mvnpm", "jquery", null, "jar", "3.7.0", "provided", false)))
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addAsResource("web-auto", "web")
.addAsResource("application-auto.properties", "application.properties"));
.addAsResource("web-auto", "web"));

@Inject
Bundle bundle;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.quarkiverse.web.bundler.test;

import java.util.List;

import jakarta.inject.Inject;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkiverse.web.bundler.runtime.Bundle;
import io.quarkus.maven.dependency.ArtifactDependency;
import io.quarkus.test.QuarkusUnitTest;
import io.restassured.RestAssured;

public class WebBundlerSourceMapDisabledTest {

@RegisterExtension
static final QuarkusUnitTest unitTest = new QuarkusUnitTest()
.withConfigurationResource("application.properties")
.overrideConfigKey("quarkus.web-bundler.bundling.source-map", "false")
.setForcedDependencies(
List.of(new ArtifactDependency("org.mvnpm", "jquery", null, "jar", "3.7.0", "provided", false)))
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addAsResource("web"));

@Inject
Bundle bundle;

@Test
public void test() {
Assertions.assertNull(bundle.resolve("main.js.map"));
Assertions.assertNull(bundle.resolve("main.css.map"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.hamcrest.Matchers;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

Expand All @@ -19,24 +20,26 @@ public class WebBundlerTest {

@RegisterExtension
static final QuarkusUnitTest unitTest = new QuarkusUnitTest()
.withConfigurationResource("application.properties")
.setForcedDependencies(
List.of(new ArtifactDependency("org.mvnpm", "jquery", null, "jar", "3.7.0", "provided", false)))
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addAsResource("web")
.addAsResource("application.properties"));
.addAsResource("web"));

@Inject
Bundle bundle;

@Test
public void test() {

RestAssured.given()
.get("/")
.then()
.statusCode(200)
.body(Matchers.containsString("mode:TEST"))
.body(Matchers.containsString("<link rel=\"stylesheet\" href=\"" + bundle.style("main") + "\" />"))
.body(Matchers.containsString(" <script type=\"module\" src=\"" + bundle.script("main") + "\"></script>"));

RestAssured.given()
.get(bundle.style("main"))
.then()
Expand All @@ -50,5 +53,22 @@ public void test() {
.then()
.statusCode(200)
.body(Matchers.equalTo("Hello World!"));

}

@Test
void testSourceMap() {
final String jsMap = bundle.resolve("main.js.map");
Assertions.assertNotNull(jsMap);
final String cssMap = bundle.resolve("main.css.map");
Assertions.assertNotNull(cssMap);
RestAssured.given()
.get(jsMap)
.then()
.statusCode(200);
RestAssured.given()
.get(cssMap)
.then()
.statusCode(200);
}
}
4 changes: 2 additions & 2 deletions docs/modules/ROOT/pages/advanced-guides.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ NOTE: By default, as soon as more than one entry-point key is configured, shared
[#loaders]
=== How is it bundled (Loaders)

Bases on the files extensions, the Web Bundler will use xref:config-reference.adoc#quarkus-web-bundler_quarkus.web-bundler.loaders.js[pre-configured loaders] to bundle them. For scripts and styles, the default configuration should be enough.
Bases on the files extensions, the Web Bundler will use xref:config-reference.adoc#quarkus-web-bundler_quarkus.web-bundler.bundling.loaders.js[pre-configured loaders] to bundle them. For scripts and styles, the default configuration should be enough.

For other assets (svg, gif, png, jpg, ttf, ...) imported from your scripts and styles using their relative path, you may choose the loader based on the file extension allowing different options (e.g. serving, embedding the file as data-url, binary, base64, ...). By default, they will automatically be copied and served using the xref:config-reference.adoc#quarkus-web-bundler_quarkus.web-bundler.loaders.file[file loader].
For other assets (svg, gif, png, jpg, ttf, ...) imported from your scripts and styles using their relative path, you may choose the loader based on the file extension allowing different options (e.g. serving, embedding the file as data-url, binary, base64, ...). By default, they will automatically be copied and served using the xref:config-reference.adoc#quarkus-web-bundler_quarkus.web-bundler.bundling.loaders.file[file loader].

For example, `url('./example.png')` in a style or `import example from './example.png';` in a script will be processed, the file will be copied with a static name and the path will be replaced by the new file static path (e.g. `/static/bundle/assets/example-QH383.png`). The `example` variable will contain the public path to this file to be used in a component img `src` for example.

Expand Down
Loading

0 comments on commit ed0ba51

Please sign in to comment.