JSP / Gradle setup
The JSP path is the vanilla path plus a few server conveniences:
- paths built from the servlet context instead of hard-coded roots,
- an asset version query string (
?v=…) for cache-busting on deploy, - the design-system build wired into Gradle so it runs with your app build.
The design system itself is identical — same CSS, same JS.
The head (as a JSP include)
Section titled “The head (as a JSP include)”Put this in something like includes/header.jsp. Adjust the context paths and supply an
ASSET_VERSION value from your app.
<%-- design tokens for native control chrome --%><style> :root { --select-bg: url(${pageContext.request.contextPath}/design-system/assets/section-icons/selector.svg); --date-bg: url(${pageContext.request.contextPath}/design-system/assets/section-icons/calendar.svg); --optional-title: 'Optional'; }</style><link rel="stylesheet" href="${pageContext.request.contextPath}/app.css?v=<%=ASSET_VERSION%>" />
<%-- theme: run before paint --%><script> ;(function () { const theme = localStorage.getItem('theme') || 'system' const className = theme === 'system' ? window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' : theme document.documentElement.classList.add(className) })()</script>
<%-- third-party libraries --%><script src="https://cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js" defer></script><script src="https://cdn.jsdelivr.net/npm/[email protected]/locale/en-US/cdn.min.js" defer></script><script src="https://cdn.jsdelivr.net/npm/animejs/dist/bundles/anime.umd.min.js" defer></script>
<%-- preline (bundled with the design system) --%><script src="${pageContext.request.contextPath}/design-system/assets/preline/preline.js" defer></script>
<%-- runtime + components (note the ?v= cache-buster on each) --%><c:set var="v" value="<%=ASSET_VERSION%>" /><script src="${pageContext.request.contextPath}/design-system/js/runtime.js?v=${v}" defer></script><script src="${pageContext.request.contextPath}/design-system/js/_defaults.js?v=${v}" defer></script><script src="${pageContext.request.contextPath}/design-system/js/theme.js?v=${v}" defer></script><script src="${pageContext.request.contextPath}/design-system/js/format.js?v=${v}" defer></script><script src="${pageContext.request.contextPath}/design-system/js/shell.js?v=${v}" defer></script><script src="${pageContext.request.contextPath}/design-system/js/table.js?v=${v}" type="module"></script><script src="${pageContext.request.contextPath}/design-system/js/input.js?v=${v}" type="module"></script><%-- …load the rest of the component scripts the same way… --%>Build with Gradle
Section titled “Build with Gradle”Add the node-gradle plugin and a task that runs the design-system build through pnpm.
-
Add the plugin:
build.gradle plugins {id 'com.github.node-gradle.node' version '7.1.0'} -
Configure Node + pnpm (downloaded and managed by Gradle):
build.gradle node {version = '22.12.0'pnpmVersion = '10.12.2'download = true} -
Register the UI build/watch as pnpm tasks.
pnpmInstallcomes from the plugin;build:uiandwatch:uiare the scripts from Installation:build.gradle tasks.register('buildDs', PnpmTask) {dependsOn pnpmInstalldescription = 'Compile the project ui'args = ['build:ui']}tasks.register('watchDs', PnpmTask) {dependsOn pnpmInstalldescription = 'Watch the project ui'args = ['watch:ui']}Run the watcher during development with
./gradlew watchDs. -
Hook the one-shot build into your WAR/app build so the compiled CSS ships with the app, e.g.:
build.gradle tasks.named('processResources') { dependsOn 'buildDs' }