I've just upgraded to vaadin 24 from vaadin 23.
Now my client application won't load.
I forced a rebuild of the client side components by deleting src/main/dev-bundle and generated.
I also deleted node_modules, package.json and package-lock.json and ran
mvn vaadin:clean-frontend clean install
to ensure that I had a nice clean build.
The web server starts without issue and reports
Vaadin application has been deployed and started to the context path "/".
When I try to load the client I'm seeing the following errors:
Path '/' is not properly resolved due to an error. Resolution had failed on route: '(.*)'
(index):4 Uncaught (in promise) DOMException: Failed to execute 'define' on 'CustomElementRegistry': the name "vaadin-checkbox" has already been used with this registry
at window.customElements.define (https://xxx/:4:829)
at https://xxx/VAADIN/dev-bundle/VAADIN/build/generated-flow-imports-7d167742.js:2759:2556
And
sw.js:1 Uncaught (in promise) bad-precaching-response: bad-precaching-response :: [{"url":"https://xxx/VAADIN/build/component-picker-acd91974.js","status":404}]
at d._handleInstall (https://xxx/sw.js:1:8531)
at async d._handle (https://xxx/sw.js:1:7942)
at async d._getResponse (https://xxx/sw.js:1:7010)
The component-picker exists in the build directory and has the correct name.
Edit: I've found some more pertinent information.
When I look at the network resources being loaded I see:
https://xxx/VAADIN/dev-bundle/VAADIN/build/indexhtml-6a220e3b.js
Note how VAADIN is in the path twice.
When the component-picker.js load is tried the path is:
https://xxx/VAADIN/build/component-picker-acd91974.js
This second path looks to be correct, but the first incorrect path is the one that successfully loads.
Edit 2: I believe that I can see the cause of the error for the CustomElementRegistry.
The generated-flow-imports.js has two CheckBox components.
Both of these are being registered by a call to:
customElements.define(CheckboxElement.is, CheckboxElement);
With CheckboxElement.is returning the same value in both cases.
The first version is:
/**
* @license
* Copyright (c) 2017 - 2023 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
registerStyles$1("vaadin-checkbox", checkboxStyles, {
moduleId: "vaadin-checkbox-styles"
});
class Checkbox extends CheckboxMixin(ElementMixin$1(ThemableMixin(PolymerElement))) {
static get is() {
return "vaadin-checkbox"
}
static get template() {
return html`
<div class="vaadin-checkbox-container">
<div part="checkbox" aria-hidden="true"></div>
<slot name="input"></slot>
<slot name="label"></slot>
</div>
<slot name="tooltip"></slot>
`
}
ready() {
super.ready(),
this._tooltipController = new TooltipController(this),
this.addController(this._tooltipController)
}
}
customElements.define(Checkbox.is, Checkbox);
The second version is:
/**
@license
Copyright (c) 2017 Vaadin Ltd.
This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
class CheckboxElement extends ElementMixin(ControlStateMixin(ThemableMixin(GestureEventListeners(PolymerElement)))) {
static get template() {
return html`
<style>
:host {
display: inline-block;
}
:host([hidden]) {
display: none !important;
}
label {
display: inline-flex;
align-items: baseline;
outline: none;
}
[part="checkbox"] {
position: relative;
display: inline-block;
flex: none;
}
input[type="checkbox"] {
position: absolute;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: inherit;
margin: 0;
}
:host([disabled]) {
-webkit-tap-highlight-color: transparent;
}
</style>
<label>
<span part="checkbox">
<input type="checkbox" checked="{{checked::change}}" disabled\$="[[disabled]]" indeterminate="{{indeterminate::change}}" role="presentation" tabindex="-1">
</span>
<span part="label">
<slot></slot>
</span>
</label>
`
}
static get is() {
return "vaadin-checkbox"
}
static get version() {
return "2.5.0"
}
static get properties() {
return {
checked: {
type: Boolean,
value: !1,
notify: !0,
observer: "_checkedChanged",
reflectToAttribute: !0
},
indeterminate: {
type: Boolean,
notify: !0,
observer: "_indeterminateChanged",
reflectToAttribute: !0,
value: !1
},
value: {
type: String,
value: "on"
},
_nativeCheckbox: {
type: Object
}
}
}
constructor() {
super(),
this.name
}
get name() {
return this.checked ? this._storedName : ""
}
set name(te) {
this._storedName = te
}
ready() {
super.ready(),
this.setAttribute("role", "checkbox"),
this._nativeCheckbox = this.shadowRoot.querySelector('input[type="checkbox"]'),
this.addEventListener("click", this._handleClick.bind(this)),
this._addActiveListeners();
const te = this.getAttribute("name");
te && (this.name = te),
this.shadowRoot.querySelector('[part~="label"]').querySelector("slot").addEventListener("slotchange", this._updateLabelAttribute.bind(this)),
this._updateLabelAttribute()
}
_updateLabelAttribute() {
const te = this.shadowRoot.querySelector('[part~="label"]')
, ee = te.firstElementChild.assignedNodes();
this._isAssignedNodesEmpty(ee) ? te.setAttribute("empty", "") : te.removeAttribute("empty")
}
_isAssignedNodesEmpty(te) {
return te.length === 0 || te.length == 1 && te[0].nodeType == Node.TEXT_NODE && te[0].textContent.trim() === ""
}
_checkedChanged(te) {
this.indeterminate ? this.setAttribute("aria-checked", "mixed") : this.setAttribute("aria-checked", Boolean(te))
}
_indeterminateChanged(te) {
te ? this.setAttribute("aria-checked", "mixed") : this.setAttribute("aria-checked", this.checked)
}
_addActiveListeners() {
this._addEventListenerToNode(this, "down", te=>{
this.__interactionsAllowed(te) && this.setAttribute("active", "")
}
),
this._addEventListenerToNode(this, "up", ()=>this.removeAttribute("active")),
this.addEventListener("keydown", te=>{
this.__interactionsAllowed(te) && te.keyCode === 32 && (te.preventDefault(),
this.setAttribute("active", ""))
}
),
this.addEventListener("keyup", te=>{
this.__interactionsAllowed(te) && te.keyCode === 32 && (te.preventDefault(),
this._toggleChecked(),
this.removeAttribute("active"),
this.indeterminate && (this.indeterminate = !1))
}
)
}
get focusElement() {
return this.shadowRoot.querySelector("input")
}
__interactionsAllowed(te) {
return !(this.disabled || te.target.localName === "a")
}
_handleClick(te) {
this.__interactionsAllowed(te) && (this.indeterminate ? (this.indeterminate = !1,
te.preventDefault(),
this._toggleChecked()) : te.composedPath()[0] !== this._nativeCheckbox && (te.preventDefault(),
this._toggleChecked()))
}
_toggleChecked() {
this.checked = !this.checked,
this.dispatchEvent(new CustomEvent("change",{
composed: !1,
bubbles: !0
}))
}
}
customElements.define(CheckboxElement.is, CheckboxElement);
I note that the second version has a version of 2.5.0. This makes me wonder if it is an old version. My problem is that I can't see any dependency that would be pulling it in.