You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2026/10/08 11:50:09 UTC

(juneau) branch juneau-release-manager updated: Serve Excel/PDF export libraries (JSZip, pdfmake) from a local WebJars pack instead of cdnjs

This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch juneau-release-manager
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/juneau-release-manager by this push:
     new e78de19746 Serve Excel/PDF export libraries (JSZip, pdfmake) from a local WebJars pack instead of cdnjs
e78de19746 is described below

commit e78de197461f9e893e330372cfab52755bdd17cb
Author: James Bognar <ja...@apache.org>
AuthorDate: Thu Oct 8 07:50:04 2026 -0400

    Serve Excel/PDF export libraries (JSZip, pdfmake) from a local WebJars pack instead of cdnjs
---
 pom.xml                                                 | 14 ++++++++++++++
 .../java/org/apache/juneau/releng/rest/ReleaseRest.java | 16 ++++++++++++++++
 src/main/resources/templates/releases.ftlh              |  4 ++--
 .../org/apache/juneau/releng/rest/ReleaseRestTest.java  | 17 ++++++++++++++---
 4 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/pom.xml b/pom.xml
index dcb0e864e5..d8aa7000c4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -91,6 +91,20 @@
             <artifactId>juneau-secret-macos-keychain</artifactId>
             <version>${juneau.version}</version>
         </dependency>
+        <!-- Excel/PDF export libraries for the "datatables-export" toolkit pack. Their npm transitive deps are not
+             needed (both ship a self-contained browser bundle), so exclude them. -->
+        <dependency>
+            <groupId>org.webjars.npm</groupId>
+            <artifactId>jszip</artifactId>
+            <version>3.10.1</version>
+            <exclusions><exclusion><groupId>*</groupId><artifactId>*</artifactId></exclusion></exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.webjars.npm</groupId>
+            <artifactId>pdfmake</artifactId>
+            <version>0.2.7</version>
+            <exclusions><exclusion><groupId>*</groupId><artifactId>*</artifactId></exclusion></exclusions>
+        </dependency>
         <!-- FreeMarker engine (provided-scope in the bridge module; supply it here). -->
         <dependency>
             <groupId>org.freemarker</groupId>
diff --git a/src/main/java/org/apache/juneau/releng/rest/ReleaseRest.java b/src/main/java/org/apache/juneau/releng/rest/ReleaseRest.java
index d32bb97cd2..80e4366d7d 100644
--- a/src/main/java/org/apache/juneau/releng/rest/ReleaseRest.java
+++ b/src/main/java/org/apache/juneau/releng/rest/ReleaseRest.java
@@ -43,6 +43,9 @@ import org.apache.juneau.rest.server.view.View;
 import org.apache.juneau.rest.server.view.freemarker.FreemarkerMixin;
 import org.apache.juneau.rest.server.view.freemarker.FreemarkerViewRenderer;
 import org.apache.juneau.rest.server.view.freemarker.console.ConsoleFreemarkerMixin;
+import org.apache.juneau.rest.server.view.freemarker.console.ToolkitPack;
+import org.apache.juneau.rest.server.view.freemarker.console.ToolkitPackRegistry;
+import org.apache.juneau.rest.server.staticfile.WebJarResolver;
 import org.apache.juneau.rest.server.staticfile.WebJarsMixin;
 import org.apache.juneau.rest.server.views.ViewsMixin;
 
@@ -98,6 +101,10 @@ public class ReleaseRest extends BasicRestResource {
 
 	/**
 	 * The Freemarker mixin used to render this resource's templates.
+	 *
+	 * <p>
+	 * Registers the app-local {@code datatables-export} pack (JSZip, pdfmake and its fonts, from WebJars) that the
+	 * releases card requires for Excel and PDF export; it loads after the built-in Buttons pack.
 	 */
 	// Return type stays FreemarkerMixin - FreemarkerViewRenderer does an exact-type bean lookup (see
 	// ConsoleFreemarkerMixin's class Javadoc).
@@ -105,6 +112,15 @@ public class ReleaseRest extends BasicRestResource {
 	public FreemarkerMixin freemarker() {
 		var builder = ConsoleFreemarkerMixin.create();
 		builder.adopterAssets(getClass().getClassLoader(), "static");
+		builder.registerToolkitPack(ToolkitPack.create("datatables-export")
+			.js(
+				WebJarResolver.asset("org.webjars.npm", "jszip", "jszip/{version}/dist/jszip.min.js"),
+				WebJarResolver.asset("org.webjars.npm", "pdfmake", "pdfmake/{version}/build/pdfmake.min.js"),
+				WebJarResolver.asset("org.webjars.npm", "pdfmake", "pdfmake/{version}/build/vfs_fonts.js"))
+			.dependsOn(ToolkitPackRegistry.PACK_DATATABLES_BUTTONS)
+			.kind(ToolkitPack.Kind.VENDOR)
+			.resolver(ToolkitPackRegistry.WEBJAR_RESOLVER)
+			.build());
 		builder.basePath("/templates/").templateSuffix(".ftlh");
 		return builder.build();
 	}
diff --git a/src/main/resources/templates/releases.ftlh b/src/main/resources/templates/releases.ftlh
index 5c4c259858..6ae278c130 100644
--- a/src/main/resources/templates/releases.ftlh
+++ b/src/main/resources/templates/releases.ftlh
@@ -16,12 +16,12 @@
 -->
 
 <@page tab="releases" toolkit="views"
-    init="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js,https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/pdfmake.min.js,https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/vfs_fonts.min.js,/js/releases-detail.js">
+    init="/js/releases-detail.js">
     <div class="jc-page-header">
         <h1>All Releases</h1>
         <p class="jc-page-sub">Every Apache Juneau release, from the current vote candidate back through GA history.</p>
     </div>
-    <@card type="datatables" id="releases" requires="datatables-buttons">
+    <@card type="datatables" id="releases" requires="datatables-export">
     {
         rowType: 'Release',
         dataMode: 'server',
diff --git a/src/test/java/org/apache/juneau/releng/rest/ReleaseRestTest.java b/src/test/java/org/apache/juneau/releng/rest/ReleaseRestTest.java
index a4836e4f23..7c20bf472b 100644
--- a/src/test/java/org/apache/juneau/releng/rest/ReleaseRestTest.java
+++ b/src/test/java/org/apache/juneau/releng/rest/ReleaseRestTest.java
@@ -177,9 +177,20 @@ class ReleaseRestTest {
 				assertTrue(body.contains("/webjars/"), "Pack assets should be served as WebJars: " + body);
 				assertFalse(body.contains("cdn.datatables.net"), "Buttons must not come from the CDN: " + body);
 				assertFalse(body.contains("/datatables/jquery.min.js"), "Bundled jQuery should be gone: " + body);
-				assertTrue(body.contains("jszip.min.js"), "Missing jszip.min.js script include: " + body);
-				assertTrue(body.contains("pdfmake.min.js"), "Missing pdfmake.min.js script include: " + body);
-				assertTrue(body.contains("vfs_fonts.min.js"), "Missing vfs_fonts.min.js script include: " + body);
+				var jszipIdx = body.indexOf("jszip.min.js");
+				var pdfmakeIdx = body.indexOf("pdfmake.min.js");
+				var vfsIdx = body.indexOf("vfs_fonts.js");
+				assertTrue(jszipIdx >= 0, "Missing jszip.min.js script include: " + body);
+				assertTrue(pdfmakeIdx >= 0, "Missing pdfmake.min.js script include: " + body);
+				assertTrue(vfsIdx >= 0, "Missing vfs_fonts.js script include: " + body);
+				assertTrue(buttonsHtml5Idx < jszipIdx, "Buttons must precede JSZip: " + body);
+				assertTrue(jszipIdx < pdfmakeIdx && pdfmakeIdx < vfsIdx, "Export libraries out of order: " + body);
+				assertEquals(jszipIdx, body.lastIndexOf("jszip.min.js"), "JSZip loaded more than once: " + body);
+				assertEquals(pdfmakeIdx, body.lastIndexOf("pdfmake.min.js"), "pdfmake loaded more than once: " + body);
+				assertEquals(vfsIdx, body.lastIndexOf("vfs_fonts.js"), "vfs_fonts loaded more than once: " + body);
+				assertTrue(body.contains("/webjars/jszip/3.10.1/dist/jszip.min.js"), "JSZip should be served as a WebJar: " + body);
+				assertTrue(body.contains("/webjars/pdfmake/0.2.7/build/pdfmake.min.js"), "pdfmake should be served as a WebJar: " + body);
+				assertFalse(body.contains("cdnjs"), "No cdnjs URL should remain: " + body);
 			}
 		}
 	}