-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
When importing component inside custom element, style is discarded #4662
Comments
I also encountered it and just worked on a fix, will create a PR soon (my first one here 😨 ) |
I just realized there is already an open PR about this : #4309 |
I see 👁️ . My changes are very similar, just its more recursive, meaning also components at any level are interested. |
…ted components. Missing feature, store available styles to avoid dupes. close vuejs#4662
…ted components. Missing feature, store available styles to avoid dupes. close vuejs#4662
Ok, this should be safer now. This addition will add any child component style to the main parent, no matter how deeply nested it is |
…ted components. Missing feature, store available styles to avoid dupes. close vuejs#4662
Anyone know if it will be merged? It blocks me from using Vue 3 :/ @raffobaffo What about third party nested components (e.g. imported from some package)? Will your solution also work for them? |
We will solve this, it might take a few more days or weeks though. |
@LinusBorg Ok, thanks for quick reply, it's good to know that it will be solved at some point in the future :) |
@pawel-marciniak Yes, it is. |
@raffobaffo would you mind sharing how did you extend it? I tried it here by basically cloning |
@lucasantunes-ciandt sorry but not TS for me on this project. This is pretty much the hack I built:
|
@raffobaffo Thank you so much! I thought you were literally extending the whole file 😅 I tried this code here, but unfortunately it doesn't work. I suppose it expects the components are all custom elements, When my components are named I reckon we'll need to wait for your PR to be merged. |
Oopsie, actually this works! Thank you @raffobaffo!! I was a bit confused about the meaning of So my two cents to the Issue Owner: |
@raffobaffo I had only to change the injection a little bit, since I may have multiple instances of the same Custom Element:
|
@lucasantunes-ciandt Nice find 👍 ! Still this block is not part of the PR, because this actually make sense to have it in a separate module that is loaded just when custom elements are needed. In my case I have a components library and I want to have 2 exports, one to be consumed by Vue applications and one for browsers/html. |
@raffobaffo Exactly! In our case we're using Vue inside a CMS, so we'll be only exporting custom elements to use within it instead of creating a Vue app, so we'll definitely keep that part because we need some external styles and even scripts from the CMS to be injected into the elements. |
@raffobaffo would your solution also inject styles into the shadow DOM from child components imported within the As an example, if I define and export a component with Also @lucasantunes-ciandt do you have a working example using the reproduction repo? |
@adamlewkowicz hard to answer. Depends from how the imported element (third party) is structured. Does it comes with is own inline styles? If yes, it should work, if not, it cant. |
@raffobaffo would you be willing to update your reproduction repo linked above with a new branch that utilizes your fix? I tried what you have but wasn't able to get it working for some reason. Would be much appreciated! |
As a workaround I've created component, which tracks Mutation in
<script setup lang="ts">
/***
* @see https://github.com/vuejs/vue-next/issues/4662
**/
import { computed } from "vue";
import { onMounted, onUnmounted, ref } from "@vue/runtime-core";
const props = defineProps<{
cssHref?: string;
}>();
const inlineStyles = ref<HTMLElement[]>([]);
const html = computed(() =>
// @ts-ignore
import.meta.env.PROD && props.cssHref
? `<link href="${props.cssHref}" rel="stylesheet"/>`
: `<style>${inlineStyles.value
.map((style) => style.innerHTML)
.join("")}</style>`
);
const findAndInsertStyle = () => {
inlineStyles.value = Array.from(
document.getElementsByTagName("style")
).filter((node) => {
return node.innerHTML.includes("VueCustomElementChildren");
});
};
// @ts-ignore
if (!import.meta.env.PROD) {
const observer = new MutationObserver(findAndInsertStyle);
observer.observe(document.head, {
childList: true,
subtree: true,
characterData: true,
});
onMounted(findAndInsertStyle);
onUnmounted(() => {
observer.disconnect();
});
}
</script>
<template>
<div v-html="html"></div>
</template>
<style>
/* VueCustomElementChildren */
</style>
<script setup lang="ts">
</script>
<template>
<div class="some-other">test</div>
</template>
<style>
/* VueCustomElementChildren */
.some-other {
color: red;
}
</style>
<script setup lang="ts">
import CustomElements from "@/components/CustomElements.vue";
import SomeOtherComponent from "@/components/SomeOtherComponent.vue";
</script>
<template>
<CustomElements css-href="/style/stylesheet.css" />
<SomeOtherComponent />
</template>
<style>
</style> |
I've found a blog by @ElMassimo describing a workaround which works for me. To summarize:
Don't know the limitations yet e.G vuex etc. |
@dezmound, wont that make other Vue custom elements' styles get injected into the first one? For example, if you have 3 custom elements in the same page:
As so you end up with unwanted styles from other components into the components. It only works well if there is only one Vue based custom element/application in the page. |
@claudiomedina Thank you for the comment 🙏 That's right, but it can be solved for example with adding scope prop for
<script setup lang="ts">
/***
* @see https://github.com/vuejs/vue-next/issues/4662
**/
import { computed } from "vue";
import { onMounted, onUnmounted, ref } from "@vue/runtime-core";
const props = defineProps<{
cssHref?: string;
scope?: string;
}>();
const inlineStyles = ref<HTMLElement[]>([]);
const html = computed(() =>
// @ts-ignore
import.meta.env.PROD && props.cssHref
? `<link href="${props.cssHref}" rel="stylesheet"/>`
: `<style>${inlineStyles.value
.map((style) => style.innerHTML)
.join("")}</style>`
);
const findAndInsertStyle = () => {
inlineStyles.value = Array.from(
document.getElementsByTagName("style")
).filter((node) => {
return node.innerHTML.includes(`${props.scope}: VueCustomElementChildren`);
});
};
// @ts-ignore
if (!import.meta.env.PROD) {
const observer = new MutationObserver(findAndInsertStyle);
observer.observe(document.head, {
childList: true,
subtree: true,
characterData: true,
});
onMounted(findAndInsertStyle);
onUnmounted(() => {
observer.disconnect();
});
}
</script>
<template>
<div v-html="html"></div>
</template>
<style>
/* VueCustomElementChildren */
</style>
<script setup lang="ts">
import CustomElements from "@/components/CustomElements.vue";
import SomeOtherComponent from "@/components/SomeOtherComponent.vue";
</script>
<template>
<CustomElements css-href="/style/stylesheet.css" scope="Element A" />
<SomeOtherComponentForA />
</template>
<style>
</style>
<script setup lang="ts">
</script>
<template>
<div class="some-other">test</div>
</template>
<style>
/* Element A: VueCustomElementChildren */
.some-other {
color: red;
}
</style>
<script setup lang="ts">
import CustomElements from "@/components/CustomElements.vue";
import SomeOtherComponent from "@/components/SomeOtherComponent.vue";
</script>
<template>
<CustomElements css-href="/style/stylesheet.css" scope="Element B" />
<SomeOtherComponentForB />
</template>
<style>
</style>
<script setup lang="ts">
</script>
<template>
<div class="some-other">test</div>
</template>
<style>
/* Element B: VueCustomElementChildren */
.some-other {
color: red;
}
</style> My example's just a solution that allows to write and use components for |
Any update, or is it time to ditch Vue and switch to Svelte? |
Oddly enough, Svelte has the exact same issue: sveltejs/svelte#4274 where there is talk about switching to Vue. |
This issue is labeled as "p4-important". I can't promise, but in an ideal world, the priority queue could be like this:
|
Since this problem has caused me some troubles, and I don’t know when the official vue will fix it, as a temporary solution, I made my PR into a vite plugin and injected the code through compilation to temporarily solve this problem problem, but for more complex scenarios still need testing, if you happen to need it too, you can use this plugin |
Could I using regular Vue components with scoped styles tag inside custom elements? |
cc 👀: https://stackblitz.com/edit/vitejs-vite-4wwdax?file=package.json |
Duplicate css |
Thanks, I'll check it out later, maybe there's something wrong with the plug-in injection code @yoyo837 |
Sorry, this is not a code problem. Before this test project, I manually pasted and copied 1000 style tags for testing. |
Sorry, I haven't worked in this project in over a year now so I no longer have access to it. Hope you have fixed your issue or been able to use baiwusanyu-c's plugin! |
I remember having this issue at the time, but the culprit was another one. In my case, I vaguely remember I was trying to |
Hey all, I wanted to give a BIG THANK YOU to @baiwusanyu-c for creating Thank you for all your hard work @baiwusanyu-c ! https://github.com/baiwusanyu-c/unplugin-vue-ce/tree/master Best regards, |
@LinusBorg looks like it takes quite a bit more than a few days or weeks. Any idea when this will be fixed? |
Bump, we really need this... |
it will reduce the amount of hacks we have to implement, for sure. now everybody is solving this problem in different ways. |
anyone managed to solve this cleanly yet? |
Three years and still no resolution. This problem is not so simple to solve. The context of the webcomponent needs to be maintained, and the inserted style tags need to be marked to prevent repeated insertion when the component is used multiple times. Currently, I deprecated scoped, and all styles are imported into .ce.vue using @import. Expect an official fix soon |
Just another plugin that resolves the issue as SFC or a full app |
有大bug,上面别人修复出现的问题基本全部出现了,一个组件多次使用,样式重复,element-plus的例子,组件样式上升到head标签里去了,而且大量重复的样式,仅仅解决了组件样式不生效的基本问题,不可靠 |
I used the following plugin to resolve all issues: Works like magic. I understand this is not an official fix, but this is good. |
Life saver, I'm using from its foundation. Kudos to @baiwusanyu-c for this masterpiece. |
closed via #11517 |
Version
3.2.14
Reproduction link
github.com
Steps to reproduce
git clone git@github.com:gnuletik/vue-ce-import-comp-style.git cd vue-ce-import-comp-style yarn run dev
Open browser
What is expected?
CSS of OtherComponent.vue should be applied.
The text "It should be blue" should be blue.
What is actually happening?
Style is not applied.
I tried renaming OtherComponent to OtherComponent.ce.vue, but the result is the same.
This is useful when writing a set of custom elements to have shared components between custom elements.
The text was updated successfully, but these errors were encountered: