Closed caalador closed 3 years ago
Since there is no exact code to reproduce the issue, I need to ask some clarifying questions:
It seems, that it happens when an async UI Runnable (getUI().access(...)) get's executed before the initial framework request is finished
a) Do you mean that this only happens for the initial page render ? For example when refreshing the page ?
b) Is the UI
object instance where the access
callback is being invoked of type class MprUI
or UI
? Based on the JS exception it should be MprUI
but just to be sure
a) Our test starts with a very simple Vaadin Flow page (in the same app, SampleUI
), before it switches to our main application where this error happens. So it's not the initial render of the browser, but the seconds main-app page uses another UI (FrontendUI
). By switching to the different UI, the browser reloads many files.
b) Both, SampleUI
and FrontendUIextend the
MprUI`.
a) Our test starts with a very simple Vaadin Flow page (in the same app, SampleUI), before it switches to our main application where this error happens. So it's not the initial render of the browser, but the seconds main-app page uses another UI (FrontendUI). By switching to the different UI, the browser reloads many files.
Ok now I would be even more interested in getting the code to reproduce this to safe time. How is the switching happening between the two UIs ? Is there some redirect ? How is that done ?
And I need to ask that what is the purpose of switching between the UIs ? Why would you not have just one UI and then switch the shown Flow routes instead that encapsulate the legacy parts inside it ? I don't think it is mentioned anywhere that you should be able to use multiple UI
s with Flow even with MPR in place, so would need to understand better that what you are trying to achieve and why. Thanks
For now, we don't have a minimal example to demonstrate the problem. As you mentioned, it's not clear if using multiple UIs in the same app is working. From the Vaadin support, I got answers from... "RTFM this is not supported", to "yes, in your setup this should work". The MPR migration guide says "Multiple UIs are not supported".
The important question, of why we have this multiple UI setup. In our BIG monolithic application, we have different sections which use independent styling. The idea when this design decision was made was: Don't deliver the whole CSS of the platform or even the admin section, if the user just opens the login page. We also have pages which are accessible without a login - we call them guest sites. Also, here we wanted to hide internal CSS which is not needed. And for development, we also deliver a sampler with our components (like the new design systems) application, which has its own styling.
In addition to this CSS optimization, we put much logic of these different sections into the individual UI classes. A lot of that is already refactored during the MPR migration, but completely removing these UI-classes would be another task.
To be concrete, In our application we have 11
different UI
-classes. If possible, we want to avoid merging them together during the mpr migration.
Here you can see how we set up two of these independent sections - we call them application.
AppApplication.java
@Route(value = "app")
@MprTheme(ThemeVariant.ThemeName.FRONTEND)
@LegacyUI(FrontendUI.class)
@MprWidgetset("com.vaadin.addons.widgetsets.AddonWidgetset")
@Push
public class AppApplication extends Div {
LoginApplication .java
@Route(value = "login")
@MprTheme(ThemeVariant.ThemeName.LOGIN)
@LegacyUI(LoginUI.class)
@Push
@MprWidgetset("com.vaadin.addons.widgetsets.AddonWidgetset")
public class LoginApplication extends MprNavigatorRoute , HasDynamicTitle {
Changing the application from Login to App is done with
getPage().open("app","_blank")
This works as expected without our freezing problem. The case which crashes the UI is when our Selenium switches from a simple SamplerApplication
page to the AppApplication
by chaining the URL in the browser. But for us, it seems that not switching the UI is the problem. It seems to be a general problem when loading the UI takes longer (e.g. wen we throttle the browser) and an async getUI().access(...)
sends data to the client which is not ready.
Don't deliver the whole CSS of the platform or even the admin section, if the user just opens the login page. To be concrete, In our application we have 11 different UI-classes. If possible, we want to avoid merging them together during the mpr migration.
I understand that you will be keeping this CSS as "v8 code", because for newer v14+ parts it is not even possible. Unless you customize the frontend build process somehow or dynamically inject the CSS/stylesheet that should be loaded, you will end up into a situation where all the CSS will be loaded regardless of what UI the user opens. I have not heard of a situation before with v14+ where there would be so much CSS to be loaded that it is a problem if all of it is loaded. So I'm not sure if the optimization is worth the trouble in the end.
Secondly, using this type of "unorthodox" setup might lead into further problems later on. I would simply recommend working your code from using UIs to @Route
and/or RouterLayout
s (and PageConfigurator
if needed) that utilize the routing instead when moving between different parts.
Changing the application from Login to App is done with
getPage().open("app","_blank")
But this opens the new UI in another new window/tab and leaves the old UI open in the browser. So this is not really switching but opening another UI. Switching would be done with getPage().setLocation("app");
instead. And you could close the existing UI so that it and all the components don't stay in the memory server side.
This works as expected without our freezing problem. The case which crashes the UI is when our Selenium switches from a simple SamplerApplication page to the AppApplication by chaining the URL in the browser. But for us, it seems that not switching the UI is the problem. It seems to be a general problem when loading the UI takes longer (e.g. wen we throttle the browser) and an async getUI().access(...) sends data to the client which is not ready.
So I assume the selenium code does another getDriver().open("app");
call in the middle of the test ?
And then there is some asynchronous push-call done after some time which breaks on the client side.
Based on this, it should be enough to create a simple MPR app with a TB test that fails even for just one UI. So basically it opens a UI, then the test opens it again with maybe some parameter ?push
given that will trigger the asynchronous call this time and make things fail. I would expect the Vaadin support should be able to help you get this reproduced or do it for you. Or help you with the other alternatives on the table.
In the meantime I was able to get the JS stack trace. Therefore I upgraded our setup to Vaadin 14 version: 14.6.0
and Vaadin Flow Plugin version: 2.6.0
. This was needed, because of missing jfrog dependencies, which prevent to build flow 2.4.
In the flow project I set:
<gwt.module.style>PRETTY</gwt.module.style>
After building I included the client lib. Also had to exclude it on several places to make sure only the SNAPSHOT version is available.
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>flow-client</artifactId>
<version>2.6-SNAPSHOT</version>
</dependency>
I hope it will help to nail that problem.
client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:1893 Uncaught TypeError: $0.firstElementChild.setResponse is not a function
at Object.eval (eval at $invoke (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6387), <anonymous>:3:22)
at $invoke (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6388)
at $handleInvocation (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6377)
at $execute (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6315)
at $lambda$4 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5347)
at MessageHandler$lambda$4$Type.flush_5 [as flush] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5601)
at flush_17 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:9762)
at $processMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5391)
at MessageHandler$lambda$0$Type.execute_12 [as execute_0] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5568)
at runWhenEagerDependenciesLoaded (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:2331)
at $handleJSON (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5277)
at $handlePendingMessages (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5312)
at $resumeResponseHandling (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5449)
at $processMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5426)
at MessageHandler$lambda$0$Type.execute_12 [as execute_0] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5568)
at runWhenEagerDependenciesLoaded (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:2331)
at $handleJSON (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5277)
at $handleMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5294)
at XhrConnection$XhrResponseHandler.onSuccess_1 [as onSuccess] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6236)
at Xhr$Handler.onReadyStateChange (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:10084)
at XMLHttpRequest.<anonymous> (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:1582)
at apply_0 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:915)
at entry0 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:954)
at XMLHttpRequest.<anonymous> (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:942)
client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:1893 Uncaught TypeError: $0.firstElementChild.setResponse is not a function
at Object.eval (eval at $invoke (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6387), <anonymous>:3:22)
at $invoke (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6388)
at $handleInvocation (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6377)
at $execute (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6315)
at $lambda$4 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5347)
at MessageHandler$lambda$4$Type.flush_5 [as flush] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5601)
at flush_17 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:9762)
at $processMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5391)
at MessageHandler$lambda$0$Type.execute_12 [as execute_0] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5568)
at runWhenEagerDependenciesLoaded (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:2331)
at $handleJSON (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5277)
at $handlePendingMessages (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5312)
at $resumeResponseHandling (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5449)
at $processMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5426)
at MessageHandler$lambda$0$Type.execute_12 [as execute_0] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5568)
at runWhenEagerDependenciesLoaded (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:2331)
at $handleJSON (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5277)
at $handlePendingMessages (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5312)
at $resumeResponseHandling (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5449)
at $processMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5426)
at MessageHandler$lambda$0$Type.execute_12 [as execute_0] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5568)
at runWhenEagerDependenciesLoaded (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:2331)
at $handleJSON (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5277)
at $handleMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5294)
at XhrConnection$XhrResponseHandler.onSuccess_1 [as onSuccess] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6236)
at Xhr$Handler.onReadyStateChange (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:10084)
at XMLHttpRequest.<anonymous> (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:1582)
at apply_0 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:915)
at entry0 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:954)
at XMLHttpRequest.<anonymous> (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:942)
The problem also occurs on a single UI just when reloading the page when the browser throttling is enabled. I checked this with the opened chrome developer tools with enabled caching. So it switching the UI or the page is not necessary to reproduce this error.
@TobseF so are these steps to reproduce ?
1) any MPR application running in production mode with frontend production build done
2) open an MPR UI which schedules a thread that soon updates the UI through ui.access
3) setup chrome to throttle the network connection to Fast-3G
.
4) reload the page -> error appears on browser
And I would just like to note that in my opinion it makes no sense to test any application by throttling the network if the application doesn't behave like it should behave for the end user - with Flow applications this means that the frontend build has been done with build-frontend
Maven/Gradle build goal. Running the webpack development server while throttling the network makes no sense to me. Enabling the vaadin.productionMode=true
is can be left out, even though it would be enabled for end user.
Could this be linked to https://github.com/vaadin/multiplatform-runtime/issues/56
@pleku
prepare-frontent
or production mode
with build frontend
doesn't matter. The problem occurs in both scenarios.com.vaadin.ui.Label asyncReturn = new com.vaadin.ui.Label("Waiting...");
UI ui = SampleUI.getCurrent();
new Thread(() -> {
System.out.println("Thread Start");
ThreadUtils.sleep(100);
ui.access(() -> {
System.out.println("Here we are!");
asyncReturn.setValue("Here we are!");
});
}).start();
This is exactly which causes the exception as you can see the JS stacktrace:
⚡Uncaught TypeError: $0.firstElementChild.setResponse is not a function
For 3. and 4. Yes the reload wit fast-3G
triggers the exception.
Our setup is the mentioned AppApplication
. This adds our old legacy application to a V8 CssLayout
which will be added to the AppApplication Div
by add(new LegacyWrapper(legacyContent));
.
Our old application uses a HorizontalSplitPanel
as main layout and uses the Navigator
in combination with custom ViewProvider
, ViewDisplay
and NavigationStateManager
to set its main content.
We also tried it with Transport.LONG_POLLING
for @Push
which also makes no difference.
To check out the resource loading, here is a bigger picture of the browser network tab in the error case:
Could this be linked to #56
No, but probably exactly the same as #13
I'm able to reproduce the same error by using popup-button
test module/application and simply navigating to With Grid
tab.
UPDATE:
It is only reproducible in dev mode.
The root cause of this is the missing pom.xml
configuration of popup-button
module: vaadin maven plugin not set up
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
</plugin>
and, thus, widget-set is not installed.
This apparently causes an error during AbstractMprUIContentConnector
initialisation, which prevent set up of setResponse
function here
addFunction(getConnection().getUIConnector().getWidget().getElement());
.
This case has the same end result (setResponse function is not defined), but probably it's different from your root cause @TobseF. I'm not able to reproduce the issue with async request, but will try once more.
By the way, popup-button
test module isn't even executed, because of missing maven failsafe plugin.
The whole missing config is following:
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>flow-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>prepare-frontend</goal>
</goals>
</execution>
</executions>
<configuration>
<productionMode>false</productionMode>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
</plugin>
UPDATE:
AbstractMprUIContentConnector
code (and other client-side Java classes compiled into JS using GWT) is in {hash}.cache.js bundle. It's being initialised from AppWidgetset.nocache.js
bundle and generated by vaadin-maven-plugin
. If no vaadin-maven-plugin
is set - there is no setResponse
function available in the client side.
I used the following, but still not able to reproduce the issue:
2.0
of MPR projectpopup-button
test module@Route("test")
@LegacyUI(TestMainLayout.MyCustomUI.class)
@Push
public class TestMainLayout extends Div {
public TestMainLayout() {
com.vaadin.ui.Label legacyComponent = new com.vaadin.ui.Label(
"Legacy component");
add(new LegacyWrapper(legacyComponent));
Div flowComponent = new Div();
flowComponent.setText("Flow component");
add(flowComponent);
addAttachListener(event -> {
com.vaadin.flow.component.UI ui = event.getUI();
new Thread(() -> {
System.out.println("Thread Start");
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {
}
ui.access(() -> {
System.out.println("Here we are!");
legacyComponent.setValue("Legacy component changed");
flowComponent.setText("Flow component changed");
});
}).start();
});
}
public static class MyCustomUI extends MprUI {
@Override
protected void init(VaadinRequest request) {
super.init(request);
}
}
}
Fast-3G
throttle and nothing, refresh the page many times. Everything works fine.I managed to reproduce setResponse is not a function
error (in ~5% of refreshes) with the same example as in my previous comment above, but with another delay: Thread.sleep(500);
. It depends on the machine where this app is running.
Here is a screenshot
It's not really visible on the Gantt diagram, but apparently ?v-r=push&v-uiId=...
overlaps 5BC0122...cache.js
in a way that the setResponse
is called before the bundle completely loaded.
To reproduce:
mvn jetty:run
This fix has been released with platform 14.6.5
Thanks for the platform release which to handle this bug. I tested the new 14.6.5
in our scenarios and indeed, the error message is gone. But the problem with the
"frozen UI". The page loads all content, but it never stops showing the loading indicator is still present.
So this fix doesn't change our situation, that the MPR cannot be used for our application. This bug is critical for us, because it challenges our whole invest of 6 months work of migration. It breaks about 100 of our Selenium-tests and it's still not clear if we can use the MPR at all.
Please reopen the issue, so we can investigate this problem further.
@TobseF the issue with the JS exception, caused by push-message processing before the client-engine was initialized, was fixed so it is probably something else that is causing the loading indicator to stay. Or then the fix was inadequate.
In case the fix was inadequate, then yes, this issue could be reopened. For us it means that we should be able to reproduce it the same way, which I understood is not the case. So to understand if the fix is valid or not, following things can be done:
1) You check in your project, when the loading indicator is still loading, that what does the $wnd.Vaadin.Flow.pendingResponses
JavaScript object have as its values - if the push messages have been processed, then it should be empty.
2) If processing the response has failed, then there should be another JS exception shown instead. Do you see those in the console ?
3) In theory there could be also an issue with the timing of when the pending responses are processed, but I can verify this and write back here if that is the case.
In case it is another issue, then a new issue should be opened to this repository with new steps to reproduce the problem. In that case I think you can use the support portal to contact the expertise team for help in diagnosing and creating a new issue.
Based on another code review for the fix, @TobseF please wait until we double check that the fix is actually valid https://github.com/vaadin/multiplatform-runtime-internal/commit/ed3435c53d47a0f258b753020cf1ab45f102e735#r52907555 - I'm betting that in your case the initial UIDL response with the state has not been processed and thus the state is not correct when the push message is processed - which can have the effect that loading indicator stays present. However I would also expect that there are client side errors since the state on client side will in flux.
We concluded that the fix made is not correct, and thus reopened the issue. Not sure if it even breaks your application more, but there is a high chance for that. Sorry for the inconvenience, we're looking at this.
The second try to address the issue failed, but it is pretty clear now that the original fix (in Vaadin 14.6.5) is causing more problems when push is used immediately after the page was opened: when testing by refreshing the page, I see that the UI component will be in either a) the state after push - correct b) the initial state before the push - incorrect
Version 2.2.2 is now fixed and it should handle the issue with the push messages. Should be in a Vaadin 14.6 release tomorrow.
If you run into further issues with your project, please work with the expertise team to create a new issue that has the necessary code and steps to reproduce the problem.
Copy from issue made by @TobseF
Problem
We are migrating our monolithic business app with the MPR to Vaadin
14.4.8
. But in the current state our app is very unstable and often breaks with a "frozen UI". The page loads all content, but it never stops showing the loading indicator and shows a JS Error message.⚠ JS Client Error
After that exception, the waring
Gave up waiting for message
seems to indicate, that the client-server communication is broken.⚠ JS Client Warning
It seems, that it happens when an async UI Runnable (
getUI().access(...)
) get's executed before the initial framework request is finished. Then the client is not ready to service this request. Push in enabled by the@Push
annoation.Here you can see the Request order in such a case in recorded Browser session:
This behavior is new with the MPR and happens when the UI is loaded. We can reproduce it several times with a Selenium Test. It happens in 2 of 4 runs. It happen even every time if we set throttle the browser in debug settings to network Fast-3G.
Expected Behavior
No matter when we call
ui.access(...)
the client should only get updates, after it's loaded and ready to serve push requests. Push updates should never destroy the client ui in such a way, that loading-indicator and user page interaction breaks.Versions:
14.4.8
8.12.3
2.4.6
90.0.4430.212
14.0.2
@Push
-annotationvaadin.productionMode = false
⚡Full stacktrace