Skip to content

Conversation

baiwusanyu-c
Copy link
Member

@baiwusanyu-c baiwusanyu-c commented Mar 22, 2023

This PR contains two parts.
Based on the existing CE style implementation design, cooperate with plugin-vue (using the styles attribute provided by the compiler) to implement CE's sub-component style injection.
close: #7941
close: #4662
close: #6530

more: vuejs/rfcs#596

@vercel
Copy link

vercel bot commented Apr 6, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Ignored Deployment
Name Status Preview Updated (UTC)
sfc-playground ⬜️ Ignored (Inspect) Apr 6, 2023 0:44am

@johnp
Copy link

johnp commented Apr 26, 2023

Works similarly well as #6610 and solves #4662. (requires enabling custom element mode in vite-plugin-vue; works for build and HMR)

With this PR, under some circumstances, the style tags are duplicated, see for example:

Edit:

Probably all the same underlying issue, if I had to guess.

@SavkaTaras
Copy link

Hello @LinusBorg ,
I hope you are well.

Could you please look at this PR and decide if that's a valid fix for #4662 once you have some time?

Thank you so much,
Taras Savka

Copy link

@johnp johnp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are the issues as tests (expect the possible style grouping issue):

    test('nested child components w/ fragments in shadow dom should have styles', async () => {
      const GrandChild = {
        styles: [`.my-green { color: green; }`],
        render() {
          return h('p', { class: "my-green" }, "This should be green")
        }
      }
      const Child = {
        components: { GrandChild },
        styles: [`.my-blue { color: blue; }`],
        render() {
          return h('div', {}, [
            h('p', { class: "my-blue" }, "This should be blue"),
            h('div', {}, h(GrandChild))
          ])
        }
      }
      const Foo = defineCustomElement({
        components: { Child },
        styles: [`.my-red { color: red; }`],
        render() {
          return [
            h('p', { class: "my-red" }, "This should be red"),
            h(Child)
          ]
        }
      })
      customElements.define('my-el-with-grandchild-styles', Foo)
      container.innerHTML = `<my-el-with-grandchild-styles></my-el-with-grandchild-styles>`
      await nextTick()

      const el = container.childNodes[0] as VueElement
      const style = el.shadowRoot?.querySelectorAll('style')!
      expect(style.length).toBe(3)
      expect(style[0].textContent).toBe(`.my-red { color: red; }`)
      expect(style[1].textContent).toBe(`.my-blue { color: blue; }`)
      expect(style[2].textContent).toBe(`.my-green { color: green; }`)
    })

    test('deeply nested child components w/ fragments in shadow dom should have styles', async () => {
      const GreatGrandChild = {
        styles: [`.my-grey { color: grey; }`],
        render() {
          return h('p', { class: "my-grey" }, "This should be grey")
        }
      }
      const GrandChild = {
        components: { GreatGrandChild },
        styles: [`.my-green { color: green; }`],
        render() {
          return [
            h('p', { class: "my-green" }, "This should be green"),
            h('span', {}, h(GreatGrandChild))
          ]
        }
      }
      const Child = {
        components: { GrandChild },
        styles: [`.my-blue { color: blue; }`],
        render() {
          return h('div', {}, [
            h('p', { class: "my-blue" }, "This should be blue"),
            h('div', {}, h(GrandChild))
          ])
        }
      }
      const Foo = defineCustomElement({
        components: { Child },
        styles: [`.my-red { color: red; }`],
        render() {
          return [
            h('p', { class: "my-red" }, "This should be red"),
            h(Child)
          ]
        }
      })
      customElements.define('my-el-with-greatgrandchild-styles', Foo)
      container.innerHTML = `<my-el-with-greatgrandchild-styles></my-el-with-greatgrandchild-styles>`
      await nextTick()

      const el = container.childNodes[0] as VueElement
      const style = el.shadowRoot?.querySelectorAll('style')!
      expect(style.length).toBe(4)
      expect(style[0].textContent).toBe(`.my-red { color: red; }`)
      expect(style[1].textContent).toBe(`.my-blue { color: blue; }`)
      expect(style[2].textContent).toBe(`.my-green { color: green; }`)
      expect(style[3].textContent).toBe(`.my-grey { color: grey; }`)
    })

@OBe95
Copy link

OBe95 commented Nov 23, 2023

Just mentioning this bug here, I also reproduce using this PR
Let me know if you want to report this fix here as well :)

@yoyo837
Copy link

yoyo837 commented Dec 14, 2023

Can this be merged?

Copy link

codspeed-hq bot commented Dec 15, 2023

CodSpeed Performance Report

Merging #7942 will not alter performance

Comparing baiwusanyu-c:bwsy/feat/CEChildStyle (1a97321) with main (bae79dd)

Summary

✅ 53 untouched benchmarks

@yoyo837
Copy link

yoyo837 commented Dec 23, 2023

Shadow DOM should support link style.

baiwusanyu-c and others added 4 commits January 3, 2024 11:45
# Conflicts:
#	packages/compiler-sfc/src/compileScript.ts
#	packages/compiler-sfc/src/parse.ts
#	packages/compiler-sfc/src/script/normalScript.ts
#	packages/compiler-sfc/src/style/cssVars.ts
#	packages/runtime-core/src/renderer.ts
#	packages/runtime-dom/__tests__/customElement.spec.ts
@yoyo837
Copy link

yoyo837 commented Jan 3, 2024

I've been following this PR and thank you for your hard work so much. However, does the vue team have a positive view on this PR?

@lseguin1337
Copy link

Hello everyone ✋ I have a simpler solution for those who want to bootstrap their vue app inside a shadowRoot:

here is a simple vitejs plugin that will inject all styles using the adoptedStylesheets API.
Let me know if you face some limitation, and if you need a version for webpack.

https://github.com/lseguin1337/vue-adopted-stylesheets

@matthiasPOE
Copy link

ping @LinusBorg

@leonheess
Copy link

@yyx990803 please 😭😭

Comment on lines +80 to +99
// TODO unit test

/*
const __sfc__ = {};
import { openBlock as _openBlock, createElementBlock as _createElementBlock, defineCustomElement as _defineCustomElement } from "vue"
function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("h1", null, " app "))
}
__sfc__.render = render
__sfc__.__file = "src/App.vue"
export default customElements.define(name, _defineCustomElement(constructor), options);
*/

// :id="{ id: msg3, 'other-attr': msg }"
// id="{ id: msg3, 'other-attr': msg }"
// .id="{ id: msg3, 'other-attr': msg }"
// v-bind:src="msg2s"
// v-bind:[msg]="msg2"
// :[msg]="msg2"
// :xlink:special="msg3"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question (if-minor): should this be removed or enabled? Like now it looks like temporary outcommented code that might never be worked on in the future, if not worked on now.

yyx990803 added a commit that referenced this pull request Aug 5, 2024
yyx990803 added a commit that referenced this pull request Aug 5, 2024
@baiwusanyu-c baiwusanyu-c deleted the bwsy/feat/CEChildStyle branch August 8, 2024 09:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
❗ p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. scope: custom elements version: minor
Projects
Status: Rejected
Status: Done