Skip to content
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
13 changes: 13 additions & 0 deletions bom/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,19 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-webjars-locator-deployment</artifactId>
<version>${project.version}</version>
</dependency>

<!-- Quarkus extension dependencies -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
<version>0.39</version>
</dependency>

<!-- Quarkus test dependencies -->

<dependency>
Expand Down
5 changes: 5 additions & 0 deletions bom/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,11 @@
<artifactId>quarkus-picocli</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-webjars-locator</artifactId>
<version>${project.version}</version>
</dependency>

<!-- External dependencies -->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public final class FeatureBuildItem extends MultiBuildItem {
public static final String VERTX = "vertx";
public static final String VERTX_WEB = "vertx-web";
public static final String VERTX_GRAPHQL = "vertx-graphql";
public static final String WEBJARS_LOCATOR = "webjars-locator";

private final String info;

Expand Down
23 changes: 23 additions & 0 deletions docs/src/main/asciidoc/http-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,29 @@ was chosen as it is the standard location for resources in `jar` files as define
Quarkus can be used without Servlet following this convention allows existing code that places its resources in this
location to function correctly.

=== WebJar Locator Support

If you are using webjars, like the following JQuery one
[source, xml]
----
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.1.1</version>
</dependency>
----
and rather write `/webjars/jquery/jquery.min.js` instead of `/webjars/jquery/3.1.1/jquery.min.js`
in your HTML files, you can add the `quarkus-webjars-locator` extension to your project.
To use it, add the following to your project's dependencies:

[source, xml]
----
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-webjars-locator</artifactId>
</dependency>
----

== Configuring the Context path

By default Quarkus will serve content from under the root context. If you want to change this you can use the
Expand Down
1 change: 1 addition & 0 deletions extensions/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<module>vertx-http</module>
<module>undertow</module>
<module>undertow-websockets</module>
<module>webjars-locator</module>

<!-- Monitoring -->
<module>smallrye-health</module>
Expand Down
84 changes: 84 additions & 0 deletions extensions/webjars-locator/deployment/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>quarkus-webjars-locator-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-webjars-locator-deployment</artifactId>
<name>Quarkus - WebJar Locator - Deployment</name>

<dependencies>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx-http-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-webjars-locator</artifactId>
</dependency>

<!-- Tests -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>

<!-- Using setForcedDependencies only works if the dependency is in the pom's test scope. -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.4.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>momentjs</artifactId>
<version>2.24.0</version>
<scope>test</scope>
</dependency>

<!-- DevMode has no setForcedDependencies, so need to add resteasy extension here -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.quarkus.webjar.locator.deployment;

import java.util.Map;

import org.webjars.WebJarAssetLocator;

import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.vertx.http.deployment.RouteBuildItem;
import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig;
import io.quarkus.webjar.locator.runtime.WebJarLocatorRecorder;

public class WebJarLocatorStandaloneBuildStep {

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
public void findWebjarsAndCreateHandler(
HttpBuildTimeConfig httpConfig,
BuildProducer<FeatureBuildItem> feature,
BuildProducer<RouteBuildItem> routes,
WebJarLocatorRecorder recorder) throws Exception {

WebJarAssetLocator webJarLocator = new WebJarAssetLocator();
Map<String, String> webjarNameToVersionMap = webJarLocator.getWebJars();

if (!webjarNameToVersionMap.isEmpty()) {
// The context path + the resources path
String rootPath = httpConfig.rootPath;
String webjarRootPath = (rootPath.endsWith("/")) ? rootPath + "webjars/" : rootPath + "/webjars/";
feature.produce(new FeatureBuildItem(FeatureBuildItem.WEBJARS_LOCATOR));
routes.produce(
new RouteBuildItem(webjarRootPath + "*",
recorder.getHandler(webjarRootPath, webjarNameToVersionMap),
false));
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.quarkus.webjar.locator.test;

import javax.annotation.PreDestroy;
import javax.ws.rs.POST;
import javax.ws.rs.Path;

@Path("/post")
public class PostResource {

@POST
public String modify(String data) {
return "Hello: " + data;
}

@PreDestroy
void destroy() {
throw new IllegalStateException("Something bad happened but dev mode should work fine");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package io.quarkus.webjar.locator.test;

import static org.hamcrest.core.Is.is;

import org.hamcrest.Matchers;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.test.QuarkusDevModeTest;
import io.restassured.RestAssured;

public class WebJarLocatorDevModeTest {
private static final String META_INF_RESOURCES = "META-INF/resources/";

@RegisterExtension
static QuarkusDevModeTest test = new QuarkusDevModeTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClass(PostResource.class)
.addAsResource(new StringAsset("<html>Hello!<html>"), META_INF_RESOURCES + "/index.html")
.addAsResource(new StringAsset("Test"), META_INF_RESOURCES + "/some/path/test.txt"));

@Test
public void testDevMode() {
// Test Endpoint
RestAssured.given().body("Stuart")
.when()
.post("/post")
.then()
.body(Matchers.equalTo("Hello: Stuart"));
// Test normal files
RestAssured.get("/").then()
.statusCode(200)
.body(is("<html>Hello!<html>"));

RestAssured.get("/index.html").then()
.statusCode(200)
.body(is("<html>Hello!<html>"));

RestAssured.get("/some/path/test.txt").then()
.statusCode(200)
.body(is("Test"));

// Test Existing Web Jars
RestAssured.get("/webjars/jquery/jquery.min.js").then()
.statusCode(200);
RestAssured.get("/webjars/momentjs/min/moment.min.js").then()
.statusCode(200);

// Test using version in url of existing Web Jar
RestAssured.get("/webjars/jquery/3.4.1/jquery.min.js").then()
.statusCode(200);
RestAssured.get("/webjars/momentjs/2.24.0/min/moment.min.js").then()
.statusCode(200);

// Test non-existing Web Jar
RestAssured.get("/webjars/bootstrap/js/bootstrap.min.js").then()
.statusCode(404);
RestAssured.get("/webjars/bootstrap/4.3.1/js/bootstrap.min.js").then()
.statusCode(404);
RestAssured.get("/webjars/momentjs/2.25.0/min/moment.min.js").then()
.statusCode(404);

// Change a source file
test.modifySourceFile(PostResource.class, s -> s.replace("Hello:", "Hi:"));

// Test modified endpoint
RestAssured.given().body("Stuart")
.when()
.post("/post")
.then()
.body(Matchers.equalTo("Hi: Stuart"));

// Test normal files
RestAssured.get("/").then()
.statusCode(200)
.body(is("<html>Hello!<html>"));

RestAssured.get("/index.html").then()
.statusCode(200)
.body(is("<html>Hello!<html>"));

RestAssured.get("/some/path/test.txt").then()
.statusCode(200)
.body(is("Test"));

// Test Existing Web Jars
RestAssured.get("/webjars/jquery/jquery.min.js").then()
.statusCode(200);
RestAssured.get("/webjars/momentjs/min/moment.min.js").then()
.statusCode(200);

// Test using version in url of existing Web Jar
RestAssured.get("/webjars/jquery/3.4.1/jquery.min.js").then()
.statusCode(200);
RestAssured.get("/webjars/momentjs/2.24.0/min/moment.min.js").then()
.statusCode(200);

// Test non-existing Web Jar
RestAssured.get("/webjars/bootstrap/js/bootstrap.min.js").then()
.statusCode(404);
RestAssured.get("/webjars/bootstrap/4.3.1/js/bootstrap.min.js").then()
.statusCode(404);
RestAssured.get("/webjars/momentjs/2.25.0/min/moment.min.js").then()
.statusCode(404);
}
}
Loading