How to create a web component with vuetify - vue.js

I've built a component in my vue + vuetify app and I want to make a web component out of it.
I managed to include vue and vuetify in the package, but the style, icons included, still isn't working in the shadow dom(which, actually, is a huge part of vuetify).
The component has to work without access to the internet.
I'm building the package with the following command:
vue-cli-service build --target wc --name <name> <component> --inline-vue
What should I do?
Thank you!

Related

Quasar: Building a Quasar component library that exports Quasar with it

I made a fairly simply Quasar component library using Vite.
npm install avvinue-clowder
However, I'm now unable to get it to work as intended within other Quasar apps.
For example if I do:
import { AVRow } from 'avvinue-clowder'
and use it within the template:
<AVRow>Foobar</AVRow>
I get the following error:
I think its because Quasar doesn't get exported with the components. Anyone know how to do that?
Here is my repo: https://github.com/RizaHKhan/clowder/tree/master/src for reference.
Note:
I know this library works because the exports that are pure Javascript, work fine. Its just the Quasar based components that throw errors.

How to remove shadow root (shadow dom) on vue web component creation

When creating web component from a vue project using the following command,
npm run build -- --target wc --name v-card src\App.vue
It creates a shadow root by default. Is there any way to build the web component without the shadow root ?

Vuetify not rendering v-menu when built as a webcomponent

I'm trying to create a Web Component using vue + vuetify.
I know that vuetify doesn't support web components, but I decided to give it a try (for sport) anyway.
Apart from some minor things, like having to manually import CSS, or manually register all vuetify components, everything seems to work fine.
There's however one big obstacle that I hit, which is trying to use <v-menu> in a web component. After being built, the button simply does nothing once it's clicked. I only get one warning in the console:
console.ts:34 [Vuetify] Unable to locate target [data-app]
I already tried making sure data-app is present, but to no avail.
I'm building the web component using:
npx vue-cli-service build --target wc --name tl-test --inline-vue
When I compare the vue project (ran via yarn serve) to the web component output (dist/demo.html), I can see that when I click the v-menu trigger button, the DOM of the dropdown gets created and appended to the page DOM. This doesn't seem to happen with the web component.
What am I missing that would prevent <v-menu> from working?
Repository reproducing the issue: https://github.com/samupl/vuetify-webcomponent-issue
You can pass a HTML node to the attach prop of the v-menu.
This will prevent Vuetify from using a query selector which wouldn't work with shadow DOMs.
For example:
<v-menu :attach="$parent.$el">
...
</v-menu>

Include Style From NPM Package Component Into WebComponent

I am building a webcomponent package using Vue CLI 3 and single file components. We have a shared package our-awesome-shared-controls that contain basic site components such as a collapsible container.
Inside my component, I import and reference the collapsible container and wrap my content in it. When I build as an app the styles from the imported components are included and everything looks great, however; when I target wc (WebComponent) using the vue-cli the style for the imported component (collapsible container) are not included.
Is there a way for me to tell the vue cli that it should include those styles? If not would there be a way to import those styles? The imported components have their style set to scoped so I'm not sure if that makes a difference.

Creating a single Vue component inside a larger project

I have a PHP project that uses Kirby CMS. I also use Gulp for building my assets. Now, I need to add a calculator on the homepage that is complex enough to justify the usage of Vue. How would I incorporate Vue in my project without introducing a ton of new tooling? All I want is a simple Single File Component basically. I have:
<div id="calculator"></div>
and I want the component to be rendered there. Nothing more.
After some consideration, I came up with the following options but found issues with each of them:
Use the Vue CLI for instant prototyping. That's the closest solution for my use case, but I can't easily develop the component. If I use vue serve, I get to see the component isolated in a new page. The issue lies in the fact the component isn't a part of my project's page. It's not affected by its stylesheets, layout, and other scripts. I can't know if it'll work properly once I build it and view it in my project. Running vue build on each change would be pretty painful and time consuming. Sadly, vue watch isn't a thing, which leads me to:
Creating a project and using Vue CLI Service. If I create a project, I'd be able to run vue-cli-service build --watch and have my component automatically refresh on each change of its source file. While developing the component, I simply make a change, wait for it to compile, and refresh my project in the browser to see the modified component in action. While that would work, it introduces a bunch of node_modules inside my project, along with a package.json. I feel that's too much for just a single component. It would pollute the project more than I'd like:
assets/
js/
build/
calculator/
dist/
node_modules/ # modules here
public/ # I don't need that
package.json # package here
package-lock.json
App.vue
scripts/
main.js
content/
site/
node_modules/ # modules here as well
panel/
package.json # package here as well
package-lock.json
index.php
I would basically have a project within a project.
Use vueify to compile the component with Browserify and Gulp (which I already use). While this appears OK, vueify is deprecated and not supported. Besides, I'd have to add a bunch of stuff to my gulpfile.js in order to use Babel + ESLint for the component.
How do I set up Vue in such a way that I'm able to develop a very simple component as a part of a larger project with as little friction as possible?
If anyone has dealt with a similar problem, how did they solve it?
I ended up using the second approach I mentioned in my question with one small twist - I initialized the Vue project in my main project. I merged them.
I opened the parent folder of my project in a terminal.
I ran vue create my-project where my-project was the actual folder name of my project. The CLI asked if it should overwrite the project or merge it. I chose merge.
After the project was created, my old package.json was overwritten and only had the Vue dependencies listed in it.
I reverted my old package.json and installed these packages: #vue/cli-plugin-babel, #vue/cli-service, vue-template-compiler, and vue.
I added the following npm script in my package.json:
"scripts": {
"calculator": "vue-cli-service build assets/js/calculator/main.js --watch --dest assets/js/calculator/build"
}
Result
My project's folder structure remained the same, except for a few new packages in node_modules. I put my component files in assets/js/calculator/. There, I have main.js which is the main component script, and build which is a folder containing the processed component.
I have:
<div id="calculator"></div>
in my page, and:
<script src="/assets/js/calculator/build/app.js"></script>
in the footer. When I open the page, the component is rendered correctly.
To modify the component, I simply run npm run calculator in a terminal, which spins up the CLI service. It monitors the main.js file and builds the component on each change. Once the build is complete (which happens in under a second), I refresh the page and the updated component is there.
Conclusion
I believe that's the smoothest way to handle this use case. It didn't bloat the project, all dependencies were listed, and the development experience is great. The part where my package.json got overwritten was a bit concerning, but other than that - it worked perfectly. If there's a better way to do this, please leave an answer!
This is probably not the answer you're looking for but if I were you I'd look into inline templates and x-templates as they seem well suited to your use case.
Also have a look at this blog post. It offers a nice write up about the different template authoring methods in Vue and their pros/cons.