You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2026/07/06 13:34:19 UTC

(struts-site) branch main updated: WW-5640 docs: document WebJars support (Struts 7.3.0) (#315)

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

lukaszlenart pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/struts-site.git


The following commit(s) were added to refs/heads/main by this push:
     new 1abc30338 WW-5640 docs: document WebJars support (Struts 7.3.0) (#315)
1abc30338 is described below

commit 1abc30338b7f06f728a204ec043cbdf6c6bc1fe7
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Mon Jul 6 15:34:13 2026 +0200

    WW-5640 docs: document WebJars support (Struts 7.3.0) (#315)
    
    * WW-5640 docs: add webjar tag reference page
    
    Document the new <s:webjar> tag (and <@s.webjar> macro) that resolves
    version-less WebJar resource paths to servable URLs, introduced in
    Struts 7.3.0. Pulls description/attributes from the released source and
    links the Static Content serving pipeline. Lists the tag under Other
    Tags in the tag reference index.
    
    Co-Authored-By: Claude Opus 4.8 <no...@anthropic.com>
    
    * WW-5640 docs: document WebJars support in static content
    
    Add a WebJars support section to the Static Content guide covering the
    new /static/webjars/** serving pipeline, version-less resolution, the
    struts.webjars.enabled and struts.webjars.allowlist constants, the
    fail-closed security constraints, and the WebJarUrlProvider extension
    seam. Introduced in Struts 7.3.0.
    
    Co-Authored-By: Claude Opus 4.8 <no...@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude Opus 4.8 <no...@anthropic.com>
---
 source/core-developers/static-content.md | 65 ++++++++++++++++++++++++++++++++
 source/tag-developers/tag-reference.md   |  2 +-
 source/tag-developers/webjar-tag.md      | 51 +++++++++++++++++++++++++
 3 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/source/core-developers/static-content.md b/source/core-developers/static-content.md
index 6d132577f..1416472ae 100644
--- a/source/core-developers/static-content.md
+++ b/source/core-developers/static-content.md
@@ -63,6 +63,71 @@ If needed you can change the default path at which static content is served. Jus
 
 This value is also used by the Default Content Loader.
 
+## WebJars support
+
+{:.alert .alert-info}
+Available since Struts 7.3.0.
+
+[WebJars](https://www.webjars.org/) package client-side libraries (Bootstrap, jQuery, …) as JARs, shipping their assets
+under `META-INF/resources/webjars/<name>/<version>/…`. Instead of vendoring these files into your web application and
+re-committing them on every upgrade, you add the WebJar as a regular dependency and let Struts resolve and serve it.
+
+Struts serves WebJar assets through the same static content pipeline described above, under
+`<staticContentPath>/webjars/**` (by default `/static/webjars/**`). Resolution is **version-less**: you reference a
+resource by its logical path and Struts resolves the version present on the classpath. For example, a request for:
+
+```
+/static/webjars/bootstrap/css/bootstrap.min.css
+```
+
+is served from `META-INF/resources/webjars/bootstrap/5.3.8/css/bootstrap.min.css` (whichever version is on the
+classpath). To emit these URLs from a template without hardcoding the version, use the
+[webjar tag](../tag-developers/webjar-tag):
+
+```jsp
+<link rel="stylesheet" href="<s:webjar path="bootstrap/css/bootstrap.min.css"/>"/>
+```
+
+Struts resolves versions using [webjars-locator-lite](https://github.com/webjars/webjars-locator-lite), which is bundled
+with `struts2-core`.
+
+### Configuration
+
+| Constant                   | Default | Description                                                                                       |
+|----------------------------|---------|---------------------------------------------------------------------------------------------------|
+| `struts.webjars.enabled`   | `true`  | Master switch for resolving and serving WebJar assets under `<staticContentPath>/webjars/**`.     |
+| `struts.webjars.allowlist` | (empty) | Optional comma-separated allowlist of WebJar names. When empty, all WebJars on the classpath are allowed. |
+
+To restrict serving to specific WebJars:
+
+```xml
+<constant name="struts.webjars.allowlist" value="bootstrap,jquery"/>
+```
+
+To disable the feature entirely:
+
+```xml
+<constant name="struts.webjars.enabled" value="false"/>
+```
+
+### Security
+
+Resolution is hard-constrained to the `META-INF/resources/webjars/` root: path traversal attempts (`..`, `.`,
+backslashes) are rejected before resolution, the resolved path is re-checked for containment, and only paths that the
+locator can resolve to a real WebJar are served. Disabled, unresolved, traversal, and allowlist-blocked requests all
+**fail closed** - a `404` when serving and empty output when building URLs.
+
+### Customizing resolution
+
+URL resolution is provided by the `org.apache.struts2.webjars.WebJarUrlProvider` container bean (default implementation
+`DefaultWebJarUrlProvider`), which exposes `resolveResourcePath(String)` and `resolveUrl(String, HttpServletRequest)`.
+Plugins and applications can replace it by declaring their own bean:
+
+```xml
+<bean type="org.apache.struts2.webjars.WebJarUrlProvider" class="com.example.MyWebJarUrlProvider" name="myProvider"/>
+<constant name="struts.webjars.urlProvider" value="myProvider"/>
+```
+
 ## Preventing Struts from handling a request
 
 If there is a request that Struts is handling as an action, and you wish to make Struts ignore it,
diff --git a/source/tag-developers/tag-reference.md b/source/tag-developers/tag-reference.md
index 32997e35c..8c00832ca 100644
--- a/source/tag-developers/tag-reference.md
+++ b/source/tag-developers/tag-reference.md
@@ -30,7 +30,7 @@ Struts Generic Tags control the execution flow as pages render.
 | [if](if-tag)               | [a](a-tag)               | [compress](compress-tag) |
 | [elseif](elseif-tag)       | [action](action-tag)     | [script](script-tag)     |   
 | [else](else-tag)           | [bean](bean-tag)         | [link](link-tag)         |
-| [append](append-tag)       | [date](date-tag)         |                          |
+| [append](append-tag)       | [date](date-tag)         | [webjar](webjar-tag)     |
 | [generator](generator-tag) | [debug](debug-tag)       |                          |
 | [iterator](iterator-tag)   | [i18n](i18n-tag)         |                          |
 | [merge](merge-tag)         | [include](include-tag)   |                          |
diff --git a/source/tag-developers/webjar-tag.md b/source/tag-developers/webjar-tag.md
new file mode 100644
index 000000000..34df2faeb
--- /dev/null
+++ b/source/tag-developers/webjar-tag.md
@@ -0,0 +1,51 @@
+---
+layout: default
+title: webjar tag
+parent:
+  title: Tag Reference
+  url: tag-reference.html
+---
+
+# webjar
+
+{:.alert .alert-info}
+Available since Struts 7.3.0.
+
+Please make sure you have read the [Tag Syntax](tag-syntax) document and understand how tag attribute syntax works.
+
+## Description
+
+Resolves a version-less [WebJar](https://www.webjars.org/) resource path to a servable URL and writes it to the output
+(or stores it in a variable when `var` is set). For example, `bootstrap/css/bootstrap.min.css` is resolved to
+`<ctx>/static/webjars/bootstrap/5.3.8/css/bootstrap.min.css`, so you never hardcode the WebJar version in your templates.
+
+The tag emits a plain URL string, so it composes with [script](script-tag), [link](link-tag), or a raw `<link>` /
+`<script>` element. See [Static Content](../core-developers/static-content#webjars-support) for the serving pipeline and
+configuration constants.
+
+{% remote_file_content https://raw.githubusercontent.com/apache/struts/main/core/src/site/resources/tags/webjar-description.html %}
+
+## Attributes
+
+{% remote_file_content https://raw.githubusercontent.com/apache/struts/main/core/src/site/resources/tags/webjar-attributes.html %}
+
+## Examples
+
+**Example 1** - reference a WebJar stylesheet:
+
+```jsp
+<link rel="stylesheet" href="<s:webjar path="bootstrap/css/bootstrap.min.css"/>"/>
+```
+
+**Example 2** - reference a WebJar script:
+
+```jsp
+<s:webjar var="webjarUrl" path="jquery/jquery.min.js"/>
+<s:script src="%{webjarUrl}"/>
+```
+
+**Example 3** - FreeMarker macro:
+
+```html
+<@s.webjar path="jquery/jquery.min.js"/>
+```