Vaadin Flow 23.2自定义Web组件生产环境无法加载求助
我使用Vaadin Flow 23.2开发了若干Web组件,这些组件在开发环境中运行正常,但部署到生产环境后无法正常工作。最明显的表现是开发环境下组件标签带有Shadow DOM,而生产环境中没有Shadow DOM。需说明的是,这些组件仅在客户端使用,我为每个Web组件都编写了对应的服务端组件,但并未通过服务端组件创建实例,而是通过向浏览器发送原生HTML来渲染组件。
客户端代码
import { css, html, LitElement } from 'lit'; import { property } from 'lit/decorators.js'; export class HintBlock extends LitElement { @property() colour = 'green'; static styles = css` .red { border-left: 4px solid red; padding: 10px; margin: 10px; } .green { border-left: 4px solid green; padding: 10px; margin: 10px; } .blue { border-left: 4px solid blue; padding: 10px; margin: 10px; } .orange { border-left: 4px solid orange; padding: 10px; margin: 10px; } `; render() { return html` <div class=${this.colour}> <slot></slot> </div> `; } } customElements.define('hint-block', HintBlock);
未使用的服务端组件代码
package dev.onepub.components; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Tag; import com.vaadin.flow.component.dependency.JsModule; /** * Server side for HintBlock Web Component * @author bsutton * */ @Tag("hint-block") @JsModule("./components/hint-block/hint-block.ts") public class WCHintBlock extends Component { static Logger logger = LogManager.getLogger(); private static final long serialVersionUID = 1L; public WCHintBlock(String content) { this.setContent(content); } private void setContent(String content) { getElement().setProperty("content", content); } }
渲染效果对比
开发环境下组件渲染效果:

生产环境下组件渲染效果:

疑问:请问是否需要执行额外操作才能让自定义Web组件被包含到生产构建中?我原以为@JsModule和@Tag注解已经足够。
解决方案
问题核心
Vaadin生产构建会启动摇树优化(Tree Shaking),只打包服务端代码实际引用到的前端资源。你虽然给服务端组件加了@JsModule注解,但因为从未实例化过这个服务端组件,Vaadin的构建工具会判定该前端模块未被使用,不会将其打包进生产包。客户端没有加载到Web组件的定义,自然无法创建Shadow DOM,组件也就失效了。
可行解决办法
- 强制引入模块
在项目的主入口类(比如Spring Boot的Application类)或者任何一定会被加载的配置类上,直接添加@JsModule注解引入你的Web组件模块:
@JsModule("./components/hint-block/hint-block.ts")
这样构建工具就会把该模块纳入生产构建范围,不会被摇树优化剔除。
改用服务端组件实例化
如果业务允许,放弃直接发送原生HTML的方式,改用服务端组件创建实例。这样Vaadin会自动识别组件依赖,确保前端模块被打包,同时还能获得服务端对组件的状态控制能力。手动修改构建配置
如果使用Maven或Gradle,可以在构建脚本中手动指定要包含的前端资源。不过这种方式需要手动维护资源路径,不如前两种简洁,容易出现路径错误,不推荐优先使用。
补充说明
开发环境下Vaadin会加载所有前端资源(或按需实时加载),所以即使没有显式引用也能正常运行;但生产环境为了优化包体积,会严格剔除未被引用的资源,这就是开发和生产环境表现差异的原因。
内容的提问来源于stack exchange,提问作者Brett Sutton

