I’m in the process of completing an update from V23 to V24.4.x and have a particular is behaving badly: It extends LitTemplate and the matching typescript code extends ThemableMixin(LitElement). It all works correctly in development mode but when I build it in production mode, the tag appears in the DOM but there’s no actual content there. There are no errors on the server side. The browser console is full of js errors that seem to be due solely to the fact that none of the expected DOM structure is there.
I’m at a loss how to debug this - any suggestions?
Did you apply correct “Usage” annotation on the server side?
Yes, I think so, though it wasn’t needed in V24.3 and doesn’t seem to make any difference in 24.4.
That is, I’ve got something like:
@Route(value="a")
@Uses(B.class)
class A extends Div {
B b;
A() {}
@PostConstruct
init() {
b = new B();
}
}
@NpmPackage(...)
@Tag("my-b")
@JsModule("./src/my-b.ts")
class B extends LitTemplate {}
The resulting DOM (in production mode) is rendered as just:
<my-b></my-b>
It is probably worth mentioning that we use gradle and the result is a WAR file. I used to have all the component ts/js in the module’s /frontend directory, but with V24, I moved it to /src/main/frontend
Exactly. Here is an example. E.g. in my TabSheet, which is a custom component build with Lit (see tab-sheet.ts), I use vaadin-icon
, vaadin-tab,
vaadin-tabs
as building blocks. So I need to add @Uses
with those in order to ensure Vaadin plugin can pick those components. Plugin is not able to scan Lit-source, it scans Java bytecode for @JsModule
, @NpmPackae
and @Uses
annotations.
What’s in there might be interesting - see Tatu’s example where he had to reference things only the client side knows
Hmm - that’s an interesting thought. There is a lot in there, but I would have expected something to complain about unresolvable imports somewhere.
The head of the actual typescript is:
import {
svg,
html,
css,
PropertyValues,
LitElement
} from "lit-element";
import {
customElement,
query,
property
} from 'lit/decorators.js';
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin';
import { Button } from '@vaadin/button';
import WaveformData from '../lib/waveform-data/waveform-data.js';
import * as d3 from 'd3';
import '@vaadin/icons';
import { pSBC, luminance } from '../lib/colors/colors.js';
import 'paper-range-slider';
Adding @Uses(Button.class) and @Uses(Icon.class) doesn’t change anything.
Do I need to also add @JsModule declarations for all my transitive JS imports or something?
Also, I do see a warning in the js console:
chunk-c4ede1b6083bab5c5505df79af6210ba799cf631231b383d49e870e7c8ed25b6-ClSuRnfn.js:13 The custom element definition for "vaadin-button" was finalized before a style module was registered. Ideally, import component specific style modules before importing the corresponding custom element. This warning can be suppressed by setting "window.Vaadin.suppressPostFinalizeStylesWarning = true".
Also also, I actually have two components in (pseudo code) A that the same thing is happening to: component C is another LitTemplate, this time backed by js code.
The use annotation will help for the specific component in typescript. It basically says that the waveform is using a button in your typescript so you need to add it in your bundle if you’re using the Hava associated to this typescript.
If the waveform client side is not in your production bundle it’s because when the production bundle is built it thinks the Java waveform component is not used in your view/application.
You can try to optimizeBundle=false. Instead of this you can try to add this @LoadDependenciesOnStartup. See the documentation How to create a production build in Vaadin Flow
Hah - Maybe you remember this code, JC?
The good news is that setting @LoadDependenciesOnStartup({WaveComponent.class,...})
worked. I can add the components I need on my AppShellConfigurator and I have a working application again.
I guess I’m unblocked, but I don’t understand why the @Uses on the @Route marked class that creates those instances isn’t working… I’m not thrilled that I lose lazy loading on these components.
As an aside, just using @LoadDependenciesOnStartup without specifying the components results in an application that basically seems to hang forever - I waited minutes before killing it.
Yes I definitely remember this :).
Normally the Uses(waveform) annotated on the route should also solve the issue in my opinion, if not then there is probably an issue ( maybe in the Gradle plugin). It’s difficult to do more without the code or putting the build in debug/verbose mode.
I’ll ask how to do it with gradle ( if there is no answer tomorrow)
Thanks - I’m obviously happy to help debug if it would be helpful. Unfortunately, I’m no longer in a position where I can share code/configuration directly with you.
To reiterate, the final (working) code is:
@LoadDependenciesOnStartup({WaveComponent.class}) // this worked!
public class MyAppShellConfigurator implements AppShellConfigurator { ../ }
@Route(...)
@Uses(WaveComponent.class) // didn't help
public class Listening ... {
private WaveComponent waveComponent;
...
init() {
waveComponent = new WaveComponent(...)
}
}
@Tag(...)
@JsModule("./.../...ts")
@Uses(Button.class) // didn't help
@Uses(Icon.class) // didn't help
public class WaveComponent extends ... { ... }