Skip to content

Commit 9a36bac

Browse files
LinusBorgyyx990803
authored andcommitted
fix(runtime-core): ensure customElements have set domprop listeners synchronously if possible.
1 parent 89f37ce commit 9a36bac

File tree

2 files changed

+57
-20
lines changed

2 files changed

+57
-20
lines changed

packages/runtime-dom/__tests__/customElement.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,29 @@ describe('defineCustomElement', () => {
247247
expect(el.maxAge).toBe(50)
248248
expect(el.shadowRoot.innerHTML).toBe('max age: 50/type: number')
249249
})
250+
251+
test('handle properties set before connecting', () => {
252+
const obj = {}
253+
const E = defineCustomElement({
254+
props: {
255+
foo: String,
256+
post: Object
257+
},
258+
setup(props) {
259+
expect(props.foo).toBe('hello')
260+
expect(props.post).toBe(obj)
261+
},
262+
render() {
263+
return `foo: ${this.foo}`
264+
}
265+
})
266+
customElements.define('my-el-preconnect', E)
267+
const el = document.createElement('my-el-preconnect') as any
268+
el.foo = 'hello'
269+
el.post = obj
270+
271+
container.appendChild(el)
272+
})
250273
})
251274

252275
describe('attrs', () => {

packages/runtime-dom/src/apiCustomElement.ts

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ export class VueElement extends BaseClass {
186186
)
187187
}
188188
this.attachShadow({ mode: 'open' })
189+
if (!(this._def as ComponentOptions).__asyncLoader) {
190+
// for sync component defs we can immediately resolve props
191+
this._resolveProps(this._def)
192+
}
189193
}
190194
}
191195

@@ -227,9 +231,8 @@ export class VueElement extends BaseClass {
227231
}
228232
}).observe(this, { attributes: true })
229233

230-
const resolve = (def: InnerComponentDef) => {
234+
const resolve = (def: InnerComponentDef, isAsync = false) => {
231235
const { props, styles } = def
232-
const declaredPropKeys = isArray(props) ? props : Object.keys(props || {})
233236

234237
// cast Number-type props set before resolve
235238
let numberProps
@@ -248,23 +251,10 @@ export class VueElement extends BaseClass {
248251
}
249252
this._numberProps = numberProps
250253

251-
// check if there are props set pre-upgrade or connect
252-
for (const key of Object.keys(this)) {
253-
if (key[0] !== '_' && declaredPropKeys.includes(key)) {
254-
this._setProp(key, this[key as keyof this], true, false)
255-
}
256-
}
257-
258-
// defining getter/setters on prototype
259-
for (const key of declaredPropKeys.map(camelize)) {
260-
Object.defineProperty(this, key, {
261-
get() {
262-
return this._getProp(key)
263-
},
264-
set(val) {
265-
this._setProp(key, val)
266-
}
267-
})
254+
if (isAsync) {
255+
// defining getter/setters on prototype
256+
// for sync defs, this already happened in the constructor
257+
this._resolveProps(def)
268258
}
269259

270260
// apply CSS
@@ -276,12 +266,36 @@ export class VueElement extends BaseClass {
276266

277267
const asyncDef = (this._def as ComponentOptions).__asyncLoader
278268
if (asyncDef) {
279-
asyncDef().then(resolve)
269+
asyncDef().then(def => resolve(def, true))
280270
} else {
281271
resolve(this._def)
282272
}
283273
}
284274

275+
private _resolveProps(def: InnerComponentDef) {
276+
const { props } = def
277+
const declaredPropKeys = isArray(props) ? props : Object.keys(props || {})
278+
279+
// check if there are props set pre-upgrade or connect
280+
for (const key of Object.keys(this)) {
281+
if (key[0] !== '_' && declaredPropKeys.includes(key)) {
282+
this._setProp(key, this[key as keyof this], true, false)
283+
}
284+
}
285+
286+
// defining getter/setters on prototype
287+
for (const key of declaredPropKeys.map(camelize)) {
288+
Object.defineProperty(this, key, {
289+
get() {
290+
return this._getProp(key)
291+
},
292+
set(val) {
293+
this._setProp(key, val)
294+
}
295+
})
296+
}
297+
}
298+
285299
protected _setAttr(key: string) {
286300
let value = this.getAttribute(key)
287301
const camelKey = camelize(key)

0 commit comments

Comments
 (0)