vaadin / flow

Vaadin Flow is a Java framework binding Vaadin web components to Java. This is part of Vaadin 10+.
Apache License 2.0
621 stars 167 forks source link

Production of dev.bundle fails in ear with multiple wars #20358

Open guttormvik2 opened 4 weeks ago

guttormvik2 commented 4 weeks ago

Describe the bug

I'm upgrading from 24.5.0.beta5 to 24.5.1, so dev.bundle needs to be recreated. At startup I get this:

Failed to find the following css files in the node_modules or C:\DeveloperArea\dawinci-main\vaadin-upgrade\ptsmc-widgetset\src\main\frontend directory tree:

  • leaflet/dist/leaflet.css

While the actual file looks like this:

leaflet\dist\leaflet.css.DELETE.462c023d5a95cd0bbb12b41499d3a5eb

It looks like the cause is that DevModeInitializer is running in parallel, once for each of my wars.

Expected-behavior

No response

Reproduction

My setup is a multi-module maven project with a vaadin "widgetset" as one of the modules. This produces an ear containing several wars and a vaadin "widgetset" jar, which we run on wildfly.

At boot, I got two of these:

14:44:50,550 ERROR [com.vaadin.flow.server.frontend.BundleUtils] (ServerService Thread Pool -- 119) Failed to copy existing package-lock.json to use: java.nio.file.FileSystemException: C:\DeveloperArea\dawinci-main\vaadin-upgrade\ptsmc-widgetset\target\dev-bundle\package-lock.json -> ... 14:44:50,550 ERROR [com.vaadin.flow.server.frontend.BundleUtils] (ServerService Thread Pool -- 114) Failed to copy existing package-lock.json to use: java.nio.file.FileSystemException: C:\DeveloperArea\dawinci-main\vaadin-upgrade\ptsmc-widgetset\target\dev-bundle\package-lock.json ->

And then later on, when I accessed the 1st vaadin page I got

Failed to find the following css files in the node_modules or C:\DeveloperArea\dawinci-main\vaadin-upgrade\ptsmc-widgetset\src\main\frontend directory tree:

  • leaflet/dist/leaflet.css

Checking in node_modules I saw that the file had been renamed for some reason:

leaflet\dist\leaflet.css.DELETE.462c023d5a95cd0bbb12b41499d3a5eb

Suspecting that Vaadin is interfering with itself while processing things in parallel, I set a breakpoint in DevModeInitializer.initDevModeHandler

After doing a clean-frontend and a restart, the breakpoint was hit 4 times. I let the 1st one complete before letting the other ones continue, and now everything works as expected.

Looking at the context at each breakpoint, it looks like DevModeInitializer is called once for each war in the ear, no matter if the war uses vaadin or not.

System Info

Windows 10 Enterprise 22H2 Firefox 131.0.3 (64-bit) Vaadin 24.5.1

mcollovati commented 4 weeks ago

DevModeInitializer initialization is started by a servlet listener (could be DevModeStartupListener, or VaadinServletContextInitializer for Spring projects).

Having it called for every war, makes me suspect that the above servlet listeners are in some way accessible in the web application class path; thus the servlet container invokes them. Could you please investigate who the caller of initDevModeHandler() is in each web application?

guttormvik2 commented 3 weeks ago

Could you please investigate who the caller of initDevModeHandler() is in each web application?

Callstack:

Thread [ServerService Thread Pool -- 134] (Suspended (breakpoint at line 294 in DevModeInitializer))    
    DevModeInitializer.initDevModeHandler(Set<Class<?>>, VaadinContext) line: 294   
    DevModeHandlerManagerImpl.initDevModeHandler(Set<Class<?>>, VaadinContext) line: 100    
    DevModeStartupListener.initialize(Set<Class<?>>, VaadinContext) line: 83    
    DevModeStartupListener(VaadinServletContextStartupInitializer).process(Set<Class<?>>, ServletContext) line: 42  
    GeneratedMethodAccessor115.invoke(Object, Object[]) line: not available 
    DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  
    Method.invoke(Object, Object...) line: 568  
    DevModeStartupListener(ClassLoaderAwareServletContainerInitializer).lambda$onStartup$2(Set, ServletContext) line: 98    
    0x0000000801ba8e40.init(ServletContext) line: not available 
    DevModeStartupListener(ClassLoaderAwareServletContainerInitializer).onStartup(Set<Class<?>>, ServletContext) line: 122  
    DeploymentManagerImpl$1.call(HttpServerExchange, Object) line: 204  
    DeploymentManagerImpl$1.call(HttpServerExchange, Object) line: 187  
    ServletRequestContextThreadSetupAction$1.call(HttpServerExchange, C) line: 42   
    ContextClassLoaderSetupAction$1.call(HttpServerExchange, C) line: 43    
    UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(ThreadSetupHandler$Action, HttpServerExchange, Object) line: 1435   
    0x0000000802665be8.call(HttpServerExchange, Object) line: not available 
    UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(ThreadSetupHandler$Action, HttpServerExchange, Object) line: 1435   
    0x0000000802665be8.call(HttpServerExchange, Object) line: not available 
    UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(ThreadSetupHandler$Action, HttpServerExchange, Object) line: 1435   
    0x0000000802665be8.call(HttpServerExchange, Object) line: not available 
    UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(ThreadSetupHandler$Action, HttpServerExchange, Object) line: 1435   
    0x0000000802665be8.call(HttpServerExchange, Object) line: not available 
    UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(ThreadSetupHandler$Action, HttpServerExchange, Object) line: 1435   
    0x0000000802665be8.call(HttpServerExchange, Object) line: not available 
    DeploymentManagerImpl.deploy() line: 255    
    UndertowDeploymentService.startContext() line: 105  
    UndertowDeploymentService$1.run() line: 87  
    Executors$RunnableAdapter<T>.call() line: 539   
    FutureTask<V>.run() line: 264   
    ContextClassLoaderSavingRunnable.run() line: 35 
    EnhancedQueueExecutor.safeRun(Runnable) line: 1990  
    EnhancedQueueExecutor$ThreadBody.doRunTask(Runnable) line: 1486 
    EnhancedQueueExecutor$ThreadBody.run() line: 1377   
    JBossThread(Thread).run() line: 833 
    JBossThread.run() line: 513 

I suspect I understand the cause for this now; Our project uses "skinnywar". That means we have one ear with multiple wars, and the things the wars share is put in ear\lib:

I assume this means everything in lib is on the classpath for every war, so any listener you have in vaadin-dev will be triggered for all wars, even for ptsmc-static which only contains static files.

The pom-file for the ear contains this:

    <dependencies>

        <!-- Dependencies listed here end up in ear\lib. -->

        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-core</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.vaadin</groupId>
                    <artifactId>hilla-dev</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        ...
tltv commented 2 weeks ago

DevModeStartupListener is in Flow's vaadin-dev-server dependency, which is in Platform's vaadin-dev dependency. Just as hilla-dev.

You could try excluding whole vaadin-dev dependency from the shared libraries. And add it to only one WAR. It's basically same as with production packaging where you can exclude whole vaadin-dev when development mode dependencies are not needed.