Skip to content

Commit 2de24dd

Browse files
committed
fix(customElementDependencyStyles): Recursively add styles from imported components. Missing feature, store available styles to avoid dupes. close vuejs#4662
1 parent 467e113 commit 2de24dd

File tree

2 files changed

+85
-3
lines changed

2 files changed

+85
-3
lines changed

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
defineAsyncComponent,
33
defineCustomElement,
4+
defineComponent,
45
h,
56
inject,
67
nextTick,
@@ -314,6 +315,48 @@ describe('defineCustomElement', () => {
314315
const style = el.shadowRoot?.querySelector('style')!
315316
expect(style.textContent).toBe(`div { color: red; }`)
316317
})
318+
319+
test('should attach styles of children components to shadow dom', () => {
320+
const Bar = defineComponent({
321+
styles: [`.green-color { color: green; }`],
322+
render() {
323+
return h(
324+
'h1',
325+
{
326+
attrs: { class: 'green-color' }
327+
},
328+
'hello'
329+
)
330+
}
331+
})
332+
const Foo = defineComponent({
333+
components: { Bar },
334+
styles: [`.blue-back { color: blue; }`],
335+
render() {
336+
return h(
337+
'span',
338+
{
339+
attrs: { class: 'blue-back' }
340+
},
341+
'<bar></bar>'
342+
)
343+
}
344+
})
345+
346+
const FooBar = defineCustomElement({
347+
components: { Foo },
348+
styles: [`div { color: red; }`],
349+
render() {
350+
return h('div', '<foo/>')
351+
}
352+
})
353+
customElements.define('my-el-with-nested-styles', FooBar)
354+
container.innerHTML = `<my-el-with-nested-styles></my-el-with-nested-styles>`
355+
const el = container.childNodes[0] as VueElement
356+
const style = el.shadowRoot?.querySelectorAll('style')!
357+
expect(style[0].textContent).toBe(`.green-color { color: green; }`)
358+
expect(style[1].textContent).toBe(`.blue-back { color: blue; }`)
359+
})
317360
})
318361

319362
describe('async', () => {

packages/runtime-dom/src/apiCustomElement.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import {
1919
nextTick,
2020
warn,
2121
ConcreteComponent,
22-
ComponentOptions
22+
ComponentOptions,
23+
Component
2324
} from '@vue/runtime-core'
2425
import { camelize, extend, hyphenate, isArray, toNumber } from '@vue/shared'
2526
import { hydrate, render } from '.'
@@ -215,7 +216,7 @@ export class VueElement extends BaseClass {
215216

216217
const resolve = (def: InnerComponentDef) => {
217218
this._resolved = true
218-
const { props, styles } = def
219+
const { props } = def
219220
const hasOptions = !isArray(props)
220221
const rawKeys = props ? (hasOptions ? Object.keys(props) : props) : []
221222

@@ -252,7 +253,7 @@ export class VueElement extends BaseClass {
252253
}
253254
})
254255
}
255-
this._applyStyles(styles)
256+
this._applyStyles(this._getChildrenComponentsStyles(def))
256257
}
257258

258259
const asyncDef = (this._def as ComponentOptions).__asyncLoader
@@ -367,4 +368,42 @@ export class VueElement extends BaseClass {
367368
})
368369
}
369370
}
371+
372+
private _getChildrenComponentsStyles(
373+
component: Component & {
374+
components?: Record<string, Component>
375+
styles?: string[]
376+
}
377+
): string[] {
378+
let componentStyles: string[] = []
379+
380+
if (component.components) {
381+
componentStyles = Object.values(component.components).reduce(
382+
(
383+
aggregatedStyles: string[],
384+
nestedComponent: Component & {
385+
components?: Record<string, Component>
386+
styles?: string[]
387+
}
388+
) => {
389+
if (nestedComponent?.components) {
390+
aggregatedStyles = [
391+
...aggregatedStyles,
392+
...this._getChildrenComponentsStyles(nestedComponent)
393+
]
394+
}
395+
return nestedComponent.styles
396+
? [...aggregatedStyles, ...nestedComponent.styles]
397+
: aggregatedStyles
398+
},
399+
[] as string[]
400+
)
401+
}
402+
403+
if (component.styles) {
404+
componentStyles.push(...component.styles)
405+
}
406+
407+
return componentStyles
408+
}
370409
}

0 commit comments

Comments
 (0)