8

I'd like to export some of the components I use in my vue projects as web-component in order to be able to use them on other non-vue projects. I see that vue has support for this, and it exports web-components, but the issue I have is with the css - it is not included (or not useable) when using the exported webcomponent.

In order to make this case easy to reproduce, I'm using the default code generated when creating a new vue js 3 project. And the component I'd like to export as web component is the default App.vue we get with the new project.

Steps to reproduce:

  1. create a standard vue (I have 3.2) project, with typescript and less.
  2. Modify the main.ts like this:
    import { createApp, defineCustomElement } from 'vue'
    import App from './App.vue'

    createApp(App).mount('#app'). // this can be commented out

    const customApp = defineCustomElement(App);
    window.customElements.define('app-component', customApp);
  1. add a new script in package.json:
    "build:wc": "vue-cli-service build --target lib --name AppComponent src/main.ts"
  1. Modify the vue.config in order to include the style in exported bundle:
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  css: {
    extract: false,
  }
})
  1. On HelloWord.vue I added a custom class to the first div (in order to be easier to find it in generated js library code) and inside the css (less in my case) block:
.hello { border: 1px solid green; background-color: #dedede; }
  1. Run the build: npm run build:wc

This will create a new folder - dist - and inside it will put the exported webcomponent - AppComponent.udm.js is the file we need to import in order to have access to the newly exported component.

  1. On the public folder I created a simple html file, test.html with this content:
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Web-Component</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="../dist/AppComponent.umd.js"></script>
</head>
<body>
    <app-component></app-component>
</body>
</html>

When I open this file, in chrome, I can see the webcomponent in my test.html I can see the component, but it has no css applied to it.

I opened the generated AppComponent.umd.js file and I see that the css was added to it (you can see the .hello class and its definition: border:1px solid green;background-color:#dedede):

var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));
// Module
___CSS_LOADER_EXPORT___.push([module.id, "h3[data-v-1ac357d5]{margin:40px 0 0}ul[data-v-1ac357d5]{list-style-type:none;padding:0}li[data-v-1ac357d5]{display:inline-block;margin:0 10px}a[data-v-1ac357d5]{color:#42b983}.hello[data-v-1ac357d5]{border:1px solid green;background-color:#dedede}", ""]);

But.... the test.html file doesn't render correctly (as you can see in the following screen capture).

enter image description here

Questions:

How is the correct way to do this? How to export from vue 3 a webcomponent (with subcomponents - like I have in this case App.vue using HelloWordComponent) in order to get it rendered correctly (with css) by the browsers.

Is someone that had this issue? Some ideas? Some documentations/tutorials?

I try to export a VUE component as a webcomponent. I expect to get a full functional component - but I get it without style.

4
  • 1
    IMHO great example where using a framework has too many drawbacks. You might spend 10% - 15% more time programming a Vanilla Web Component. But you won't have sh* like this. AND you won't have any upgrade issues in the future. You are old enough to know what happened with the Angular 1 to 2 "upgrade". Standards will evolve, just like querySelector, and Frameworks will have to adapt to it. That means Vanilla code is always better.... if you account for your whole component lifecycle. Commented Feb 1, 2023 at 15:16
  • First of all, thank you for your comment. The idea is that I have a parralel project running vue 3 and I'd like to reuse some code. So far I'm writing code for angular js (big legacy project) and new vue project. I'd like to build WebComponents in order to avoid writing angular js. And a full migration is not in scope for the next year. Commented Feb 1, 2023 at 16:32
  • 1
    (IMHO) native Web Components are mainly to part-by-part replace existing functionality. You can start by replacing 2 DIVs, or as big a component as your team can handle. Building Web Components with Vue or Svelte or Whatever, is like driving in a nail with a sledgehammer. If you now use Vue3 to build Web Components, you will, most likely, have upgrade issues everywhere you used that Component when Vue hits version 4,5,6. Because at one point Vue will make breaking changes, I will bet you all my bitcoins on that. Then again, banks still run Cobol. And Cobol developers make 120K+ Commented Feb 1, 2023 at 17:51
  • 1
    Have a look at vue-web-component. Commented Jun 2, 2023 at 8:39

2 Answers 2

2

If you rename your SFC from my-component.vue to my-component.ce.vue then the styles will be handled properly by defineCustomElement see https://vuejs.org/guide/extras/web-components for detail ( Example.vue is renamed te Example.ce.vue )

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. I don't understand from the documentation what happen in case I use some third part components. Let's say I use ag grid inside my custom component. Will the styles from agv be correctly included?
For me, this only worked if for the main component. I had to move all sub-components styles to the main component.
0

I've been working on this for weeks and found out there is one solution that can make all problems go away, but it is a complex one.

As we know, it is not a problem to create a library with one or more components exposed. Such a library, when built, will produce not only JS bundle but also CSS bundle with all the styles being used. With that in place one can create a separate project for the library that houses the components in question, then a separate webcomponent project would be created that imports the actual component from the library, wraps it, imports all the necessary styles and registers the web component so that everyone else can use it.

Here's an example project that does all of it and has an additional app project that imports the web component module and uses it to verify it will all work in the final product.

https://github.com/padcom/vue-webcomponent-example

Hope it helps someone.

1 Comment

Please don't forget that some styles are leaking from the parent components into the web component, for example font-family if not set inside the web component.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.