web component with vue 3 - styles are not added
Asked Answered
N

1

7

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.

Neuburger answered 25/1, 2023 at 16:54 Comment(4)
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.Howes
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.Neuburger
(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+Howes
Have a look at vue-web-component.Halstead
A
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 )

Arnone answered 24/1 at 11:12 Comment(2)
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?Neuburger
For me, this only worked if for the main component. I had to move all sub-components styles to the main component.Fateful

© 2022 - 2024 — McMap. All rights reserved.