Skip to content

Commit 07d28f8

Browse files
author
yangchangtao
committed
fix(custom-element): ensure correct order of nested component styles
1 parent 119f18c commit 07d28f8

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,39 @@ describe('defineCustomElement', () => {
791791
assertStyles(el, [`div { color: blue; }`, `div { color: red; }`])
792792
})
793793

794+
test('child components styles should before parent styles', async () => {
795+
const Baz = () => h(Bar)
796+
const Bar = defineComponent({
797+
styles: [`div { color: green; }`],
798+
render() {
799+
return 'bar'
800+
},
801+
})
802+
const WarpperBar = defineComponent({
803+
styles: [`div { color: blue; }`],
804+
render() {
805+
return h(Baz)
806+
},
807+
})
808+
const WBaz = () => h(WarpperBar)
809+
const Foo = defineCustomElement({
810+
styles: [`div { color: red; }`],
811+
render() {
812+
return [h(Baz), h(WBaz)]
813+
},
814+
})
815+
customElements.define('my-el-with-wrapper-child-styles', Foo)
816+
container.innerHTML = `<my-el-with-wrapper-child-styles></my-el-with-wrapper-child-styles>`
817+
const el = container.childNodes[0] as VueElement
818+
819+
// inject order should be child -> parent
820+
assertStyles(el, [
821+
`div { color: green; }`,
822+
`div { color: blue; }`,
823+
`div { color: red; }`,
824+
])
825+
})
826+
794827
test('with nonce', () => {
795828
const Foo = defineCustomElement(
796829
{

packages/runtime-dom/src/apiCustomElement.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ export class VueElement
229229
private _connected = false
230230
private _resolved = false
231231
private _numberProps: Record<string, true> | null = null
232-
private _styleChildren = new WeakSet()
232+
private _styleChildren = new WeakMap<ConcreteComponent, HTMLStyleElement[]>()
233233
private _pendingResolve: Promise<void> | undefined
234234
private _parent: VueElement | undefined
235235
/**
@@ -581,18 +581,29 @@ export class VueElement
581581
owner?: ConcreteComponent,
582582
) {
583583
if (!styles) return
584+
const styleList: HTMLStyleElement[] = []
584585
if (owner) {
585-
if (owner === this._def || this._styleChildren.has(owner)) {
586+
if (owner === this._def) {
586587
return
587588
}
588-
this._styleChildren.add(owner)
589+
if (this._styleChildren.has(owner)) {
590+
const styleList = this._styleChildren.get(owner)!
591+
styleList.forEach(s => s.remove())
592+
this.shadowRoot!.prepend(...styleList)
593+
return
594+
}
595+
this._styleChildren.set(owner, styleList)
589596
}
597+
590598
const nonce = this._nonce
591599
for (let i = styles.length - 1; i >= 0; i--) {
592600
const s = document.createElement('style')
593601
if (nonce) s.setAttribute('nonce', nonce)
594602
s.textContent = styles[i]
595603
this.shadowRoot!.prepend(s)
604+
if (owner) {
605+
styleList.unshift(s)
606+
}
596607
// record for HMR
597608
if (__DEV__) {
598609
if (owner) {

0 commit comments

Comments
 (0)