vuejs / vue-web-component-wrapper

(Vue 2 only) Wrap a Vue component as a web component / custom element.
1.05k stars 100 forks source link

Web Components encorperating Vuetify a la carte ignore style, even when bundled together via rollup #66

Open SumNeuron opened 4 years ago

SumNeuron commented 4 years ago

Cool stuff you're doing here.

How I got here:

  1. Created empty project repo: mkdir test && cd test
  2. Created fresh project via vue-cli: vue create dev
  3. Added Vuetify to project: cd dev && vue add veutify
  4. Pulled config files from test/dev up to test
  5. Updated vue.config.js to point to new location:
//vue.config.js
{
//...
pages: {
    index: {
      entry: 'dev/src/main.js',
      template: 'dev/public/index.html',
      filename: 'index.html',
    }
  },
}
  1. Made a very simple component CountButton.vue which is just a wrapper of the Vuetify component <v-btn> imported a la carte (see test/dev/components/CountButton.vue)
  2. tried mounting multiple instances of the component CountButton in dev/src/main.js e.g.
// dev/src/main.js
// ...
import CountButton from './components/CountButton.vue'
new Vue({
  store,
  vuetify,
  render: h => h(CountButton)
}).$mount('#app')

new Vue({
  store,
  vuetify,
  render: h => h(CountButton)
}).$mount('#app2') // <--- copy pasted <div id="app"> and gave it new id "app2" in `public/index.html`
  1. Noticed that direct mounting this way does not work as expected (CountButton.vue was mounted and data was reactive in Vue inspector, but not the template)
  2. Updated dev/src/App.vue to contain just CountButton.vue
  3. Tried the multi-mount, and that works.
  4. Copy pasted the file dev/src/App.vue to dev/src/App0.vue and tried mounting the App0 component. This failed in the same manner as (8) as the vue-cli targets dev/src/App.vue as the entry point.
  5. Tried to then convert component to a WebComponent by adding the following package.json
"build:wc": "npx vue-cli-service build --target wc --name pub 'dev/src/components/*.vue'",
  1. inspected the resulting dist/pub.min.js and dist/demo.html files and noticed the component regained its dynamic template - error from (8) - but lost all styling

  2. Thought that this may be due to Vuetify styles not being bundled with the the Vuetify component

  3. Setup rollup to try and force the CSS to be bundled with the component (see rollup.config.js, dev/src/rollup.entry.js and package.json)

  4. then I rolled up npm run build:r

  5. then I tried to use the component: (dist/demo.html)

  6. Am back to where I was at step (13); namely, I have WebComponents, but despite bundling vuetify.min.css with the CountButton.vue component, but no styling.

This belabored process raises two questions:

  1. How to mount multiple components (not App.vue) in main.js from vue-cli3
  2. How to rollup Vue Components that are built on top of Vuetify.js to keep their styling and functionality outside of

The former is related more to vue-cli (but if you know the answer I'd appreciate it) The latter is where my issue comes from.

How can I have @vue/web-component-wrapper convert my component and either include the requisite styles or use the stylesheets from a cdn?

a MWE repo to help figure this out can be found here

SumNeuron commented 4 years ago

I have tried a bunch of stuff

// rollup.entry.js
let components = {
  CountButton
}

// BEGIN: @vue/web-component-wrapper
// helpers for registering with window
const pascalToKebabHelper = (x, y) => `-${y.toLowerCase()}`
const pascalToKebab = (str) => {
  return str.replace(/\.?([A-Z]+)/g, pascalToKebabHelper).replace(/^-/, "")
}

let GlobalVue = null;
let GlobalVuetify = null;

// define webcomponents
if (typeof window !== 'undefined') {
  // vue / vuetify from cdn
  GlobalVue = window.Vue;
  GlobalVuetify = window.Vuetify

  let vuePlugins = GlobalVue._installedPlugins
  let vuetifyFound = false
  for (let i = 0; i < vuePlugins.length; i++) {
    let plug = vuePlugins[i]
    if (plug.name === 'Vuetify') {
      vuetifyFound = true // Vue.$_vuetify_installed = true, but Vue._installedPlugins[0].installed = false
      // tried manually installing vuetify, didn't work
      // if (plug.installed === false) {
      //   plug.install()
      //   plug.installed = true
      // }
      break
    }
  }

  if (!vuetifyFound) {
    // GlobalVue.use(plugin);
    GlobalVue.use(GlobalVuetify)
  }
  console.log(GlobalVue)

  Object.keys(components).forEach(name=>{
    let htmlTagName = pascalToKebab(name) // <--- too lazy to wrangle pascal to kebab case
    // let vueWebComponent = wrap(new Vue({}), components[name]) // tried new Vue but complains about constructor
    let vueWebComponent = wrap(GlobalVue, components[name]) // this doesn't work with vuetify
    window.customElements.define(htmlTagName, vueWebComponent)
  })
}
// END: @vue/web-component-wrapper
vallemar commented 4 years ago

Loading the .css in the component. It worked for me.

<template>
    <div>
        <link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet" />
        .
        .
        .
    <div>
<template>
jaspersnelwebcenter commented 2 years ago

@SumNeuron have you ever found a solution for this?