Vaadin14整合Spring Boot时JS引入失败及CompletableFuture不触发问题求助
Vaadin 14 + Spring Boot 自定义JS导入及调用问题解答
1. JavaScript资源正确导入方式
Vaadin 14按照JS的类型分为两种标准导入方案,对应不同的存放路径和API:
- 导入ES模块:使用
@JsModule注解,JS文件需放在项目根目录的frontend/文件夹下,注解路径开头加./标识相对frontend根目录的路径,示例:@JsModule("./src/teams.js")。注意ES模块默认是隔离作用域,要暴露全局方法需要显式挂载到window对象上,不要直接覆盖整个window对象。 - 导入普通全局JS文件:使用
@JavaScript注解或者page.addJavaScript()方法,JS文件统一放在src/main/resources/META-INF/resources/目录下,比如存放在src/main/resources/META-INF/resources/js/teams.js,导入时写绝对路径@JavaScript("/js/teams.js")即可。不要在路径开头加.,.开头是相对当前页面路由的路径,路由变化后会出现资源找不到的问题。
2. 之前配置无效的原因
最开始的配置存在两个核心错误:
- 全局对象覆盖问题:你的JS代码里直接写
window = {initTeams:...},直接替换了整个浏览器全局window对象,Vaadin客户端运行时依赖的所有全局变量都会被清空,所以执行到window.initTeams()时直接抛出未定义错误,后续的console.log('xx')自然不会执行。正确的JS写法是window.initTeams = function () { console.log('initTeams...'); },仅给window添加属性而不是覆盖整个对象。 - 路径规则匹配错误:使用
@JsModule时路径没有加./相对前缀,Vaadin会默认到node_modules目录下查找对应文件,自然找不到你的自定义JS;使用frontend://前缀是Vaadin 13及更早版本的语法,14+版本已经废弃,会被识别为独立主机地址,因此报CORS跨域错误。
3. 调用join()导致浏览器冻结的原因
page.executeJs()返回的CompletableFuture是服务端异步对象,需要等待浏览器端JS执行完成后回传结果,才会触发future完成。你在视图构造函数中直接调用join()/get()会阻塞当前服务端请求线程,导致整个视图渲染请求无法完成,浏览器端一直收不到服务端响应,就会出现加载冻结的情况。这个API的设计是异步回调模式,绝对不能在请求处理线程中同步阻塞等待结果。
4. CompletableFuture回调始终不触发的原因
你在视图构造函数中执行page.executeJs()时,当前视图还没有完成客户端挂载,JS执行指令会被暂存到UI的待发送队列中,没有实际发送到浏览器端。如果后续视图渲染出现报错、UI实例被销毁,或者服务端没有开启推送/心跳机制,暂存的JS指令永远不会被发送,因此future永远不会完成,isSentToBrowser()方法始终返回false。
解决方法是把initTeams()的调用从构造函数移到beforeEnter生命周期方法中,这个阶段视图已经完成挂载,UI处于可交互状态,JS指令会被正常发送到浏览器执行。
内容的提问来源于stack exchange,提问作者Viktor Korai
相关产品推荐
相关产品推荐

