Skip to content

Commit 6dff8a2

Browse files
committed
fix(runtime-core): ensure customElements have set domprop listeners synchronously if possible.
1 parent 6b68898 commit 6dff8a2

File tree

2 files changed

+59
-21
lines changed

2 files changed

+59
-21
lines changed

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,29 @@ describe('defineCustomElement', () => {
210210
customElements.define('my-el-upgrade', E)
211211
expect(el.shadowRoot.innerHTML).toBe(`foo: hello`)
212212
})
213+
214+
test('handle properties set before connecting', () => {
215+
const obj = {}
216+
const E = defineCustomElement({
217+
props: {
218+
foo: String,
219+
post: Object
220+
},
221+
setup(props) {
222+
expect(props.foo).toBe('hello')
223+
expect(props.post).toBe(obj)
224+
},
225+
render() {
226+
return `foo: ${this.foo}`
227+
}
228+
})
229+
customElements.define('my-el-preconnect', E)
230+
const el = document.createElement('my-el-preconnect') as any
231+
el.foo = 'hello'
232+
el.post = obj
233+
234+
container.appendChild(el)
235+
})
213236
})
214237

215238
describe('emits', () => {

packages/runtime-dom/src/apiCustomElement.ts

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ export class VueElement extends BaseClass {
173173
)
174174
}
175175
this.attachShadow({ mode: 'open' })
176+
if (!(this._def as ComponentOptions).__asyncLoader) {
177+
// for sync component defs we can immediately resolve props
178+
this._resolveProps(this._def)
179+
}
176180
}
177181
}
178182

@@ -214,10 +218,9 @@ export class VueElement extends BaseClass {
214218
}
215219
}).observe(this, { attributes: true })
216220

217-
const resolve = (def: InnerComponentDef) => {
218-
const { props, styles } = def
221+
const resolve = (def: InnerComponentDef, isAsync = false) => {
222+
const { props = [], styles } = def
219223
const hasOptions = !isArray(props)
220-
const rawKeys = props ? (hasOptions ? Object.keys(props) : props) : []
221224

222225
// cast Number-type props set before resolve
223226
let numberProps
@@ -232,23 +235,10 @@ export class VueElement extends BaseClass {
232235
}
233236
this._numberProps = numberProps
234237

235-
// check if there are props set pre-upgrade or connect
236-
for (const key of Object.keys(this)) {
237-
if (key[0] !== '_') {
238-
this._setProp(key, this[key as keyof this], true, false)
239-
}
240-
}
241-
242-
// defining getter/setters on prototype
243-
for (const key of rawKeys.map(camelize)) {
244-
Object.defineProperty(this, key, {
245-
get() {
246-
return this._getProp(key)
247-
},
248-
set(val) {
249-
this._setProp(key, val)
250-
}
251-
})
238+
if (isAsync) {
239+
// defining getter/setters on prototype
240+
// for sync defs, this already happened in the constructor
241+
this._resolveProps(def)
252242
}
253243

254244
// apply CSS
@@ -260,12 +250,37 @@ export class VueElement extends BaseClass {
260250

261251
const asyncDef = (this._def as ComponentOptions).__asyncLoader
262252
if (asyncDef) {
263-
asyncDef().then(resolve)
253+
asyncDef().then(def => resolve(def, true))
264254
} else {
265255
resolve(this._def)
266256
}
267257
}
268258

259+
private _resolveProps(def: InnerComponentDef) {
260+
// check if there are props set pre-upgrade or connect
261+
for (const key of Object.keys(this)) {
262+
if (key[0] !== '_') {
263+
this._setProp(key, this[key as keyof this], true, false)
264+
}
265+
}
266+
267+
const { props } = def
268+
const hasOptions = !isArray(props)
269+
const rawKeys = props ? (hasOptions ? Object.keys(props) : props) : []
270+
271+
// defining getter/setters on prototype
272+
for (const key of rawKeys.map(camelize)) {
273+
Object.defineProperty(this, key, {
274+
get() {
275+
return this._getProp(key)
276+
},
277+
set(val) {
278+
this._setProp(key, val)
279+
}
280+
})
281+
}
282+
}
283+
269284
protected _setAttr(key: string) {
270285
let value = this.getAttribute(key)
271286
if (this._numberProps && this._numberProps[key]) {

0 commit comments

Comments
 (0)