Skip to content

Commit

Permalink
fix(customElementDependencyStyles): Recursively add styles from impor…
Browse files Browse the repository at this point in the history
…ted components. Missing feature, store available styles to avoid dupes. close vuejs#4662
  • Loading branch information
raffobaffo committed Sep 27, 2021
1 parent 467e113 commit 2de24dd
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 3 deletions.
43 changes: 43 additions & 0 deletions packages/runtime-dom/__tests__/customElement.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
defineAsyncComponent,
defineCustomElement,
defineComponent,
h,
inject,
nextTick,
Expand Down Expand Up @@ -314,6 +315,48 @@ describe('defineCustomElement', () => {
const style = el.shadowRoot?.querySelector('style')!
expect(style.textContent).toBe(`div { color: red; }`)
})

test('should attach styles of children components to shadow dom', () => {
const Bar = defineComponent({
styles: [`.green-color { color: green; }`],
render() {
return h(
'h1',
{
attrs: { class: 'green-color' }
},
'hello'
)
}
})
const Foo = defineComponent({
components: { Bar },
styles: [`.blue-back { color: blue; }`],
render() {
return h(
'span',
{
attrs: { class: 'blue-back' }
},
'<bar></bar>'
)
}
})

const FooBar = defineCustomElement({
components: { Foo },
styles: [`div { color: red; }`],
render() {
return h('div', '<foo/>')
}
})
customElements.define('my-el-with-nested-styles', FooBar)
container.innerHTML = `<my-el-with-nested-styles></my-el-with-nested-styles>`
const el = container.childNodes[0] as VueElement
const style = el.shadowRoot?.querySelectorAll('style')!
expect(style[0].textContent).toBe(`.green-color { color: green; }`)
expect(style[1].textContent).toBe(`.blue-back { color: blue; }`)
})
})

describe('async', () => {
Expand Down
45 changes: 42 additions & 3 deletions packages/runtime-dom/src/apiCustomElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import {
nextTick,
warn,
ConcreteComponent,
ComponentOptions
ComponentOptions,
Component
} from '@vue/runtime-core'
import { camelize, extend, hyphenate, isArray, toNumber } from '@vue/shared'
import { hydrate, render } from '.'
Expand Down Expand Up @@ -215,7 +216,7 @@ export class VueElement extends BaseClass {

const resolve = (def: InnerComponentDef) => {
this._resolved = true
const { props, styles } = def
const { props } = def
const hasOptions = !isArray(props)
const rawKeys = props ? (hasOptions ? Object.keys(props) : props) : []

Expand Down Expand Up @@ -252,7 +253,7 @@ export class VueElement extends BaseClass {
}
})
}
this._applyStyles(styles)
this._applyStyles(this._getChildrenComponentsStyles(def))
}

const asyncDef = (this._def as ComponentOptions).__asyncLoader
Expand Down Expand Up @@ -367,4 +368,42 @@ export class VueElement extends BaseClass {
})
}
}

private _getChildrenComponentsStyles(
component: Component & {
components?: Record<string, Component>
styles?: string[]
}
): string[] {
let componentStyles: string[] = []

if (component.components) {
componentStyles = Object.values(component.components).reduce(
(
aggregatedStyles: string[],
nestedComponent: Component & {
components?: Record<string, Component>
styles?: string[]
}
) => {
if (nestedComponent?.components) {
aggregatedStyles = [
...aggregatedStyles,
...this._getChildrenComponentsStyles(nestedComponent)
]
}
return nestedComponent.styles
? [...aggregatedStyles, ...nestedComponent.styles]
: aggregatedStyles
},
[] as string[]
)
}

if (component.styles) {
componentStyles.push(...component.styles)
}

return componentStyles
}
}

0 comments on commit 2de24dd

Please sign in to comment.