Skip to content

Serve the console's webjars from a configurable base URL - #29

Merged
codeconsole merged 1 commit into
grails-plugins:8.0.xfrom
codeconsole:webjars-base-url
Sep 22, 2026
Merged

codeconsole merged 1 commit into
grails-plugins:8.0.xfrom
codeconsole:webjars-base-url

Conversation

@codeconsole

@codeconsole codeconsole commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Why

The console links its webjars at <contextPath>/webjars/..., served by Spring Boot's classpath
mapping. An application that mirrors its static files to a CDN has no way to put these there too.

The only lever today is webjars.enabled = false, which is a much bigger step than the question
deserves: exclude four jars, supply jQuery, Bootstrap and Bootstrap Icons yourself, and maintain a
layout to do it — all to change where bytes are fetched from, not which files or versions.

What

grails.plugin.console.webjars.baseUrl replaces the base for every link the plugin emits, the
CodeMirror import map included:

grails:
    plugin:
        console:
            webjars:
                baseUrl: 'https://cdn.example.com/webjars'

The version in each URL is still resolved from the runtime classpath, so this stays compatible with
an application overriding a webjar version. Unset, the default remains <contextPath>/webjars and
nothing changes.

WebjarVersions.url(contextPath, name, file, defaultVersion = null) builds the URL. It keeps the
build-time default-version fallback the generator already had for CodeMirror, and returns null
for a webjar that is not on the classpath, so a caller can leave the tag out rather than emit one
with a null version in it. The gulp fragments (_webjarsCss.gsp, _webjarsJs.gsp,
_webjarsModules.gsp) now generate through it, which also removes the repeated
${request.contextPath}/webjars/... from 13 import-map entries.

This is deliberately narrower than webjars.enabled = false, and the two compose: an application
that wants to supply its own copies still turns the tags off, and one that just wants them served
from elsewhere sets a base.

Tests

WebjarVersionsSpec covers the URL shape under a context path, the empty and null context path,
the default-version fallback, classpath precedence over that fallback, and the null for an absent
webjar. Full plugin suite: 47 tests, all passing.

The console links its webjars at <contextPath>/webjars/..., which Spring Boot
serves off the classpath. An application that mirrors its static files to a CDN
has no way to put these there too: the only lever is webjars.enabled=false, which
means excluding the jars, supplying all four libraries and maintaining a layout —
a large step for a question only about where bytes are fetched from.

grails.plugin.console.webjars.baseUrl replaces that base for every link the
plugin emits, the import map included, while the version in each URL is still
resolved from the classpath. Unset, nothing changes.

WebjarVersions.url() builds the URL, keeping the build-time default-version
fallback the generator had, and returns null for a webjar that is not on the
classpath so a caller can leave the tag out instead of emitting one with a null
version in it. The gulp fragments generate through it.
@codeconsole
codeconsole merged commit a960bce into grails-plugins:8.0.x Sep 22, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant