This boilerplate project aims to use vue-custom-element
library with Vue2, and use Buefy
as a plugin/CSS framework, Material design fonts for the icons, all above encapsulating the CSS in every custom element's (or widget's) shadow DOM.
For test purposes we also created a shared vuex store
between components, so a encapsulated widget could have an effect on anoter.
This project aimed to find an answer to this issue.
As we write this, Buefy
is not supporting Vue3. So to make custom element using Buefy as a vue plugin we had to use Vue2, and vue-custom-element
still seems the best way to make custom elements with vue2.
Due to the way vue-custom-element
works the CSS must be imported and injected as strings in the custom-element options (shadowCss
) in main.js
. To do so we used the raw-loader
library.
As the widgets are encapsulated in a shadow-root
most of the buefy CSS only applies to the component. But still, some CSS selectors are by default set to inherit
from the parents (when the style is something like box-sizing: inherit
). To solve that problem we had to create a specific css file we also injected after injecting the buefy and material design css files (./src/styles/initialize.css
).
In shadow mode the scoped
styles usually used in Vue are useless : those styles are injected into the <head>
tag, not reachable by the custom element within their shadow-root
. To be able to apply different styles to specific components, even nested, we had to find a workaround : we created a mixin
function available on all components (this.addStyle(url)
) able to generate a <link>
tag pointing to specific css files (in the public folder) from a value in component's data, and adding this link to the component's parent shadow-root
.
By the same trick we can inject the Material Design CSS file, but doing so the injected css still needs to load the fonts themselves from a public folder (src: url("../fonts/materialdesignicons-webfont.eot")
and so on).
/* From './node_modules/@mdi/font/css/materialdesignicons.css' file */
@font-face {
font-family: "Material Design Icons";
src: url("../fonts/materialdesignicons-webfont.eot?v=6.6.96");
src: url("../fonts/materialdesignicons-webfont.eot?#iefix&v=6.6.96") format("embedded-opentype"), url("../fonts/materialdesignicons-webfont.woff2?v=6.6.96") format("woff2"), url("../fonts/materialdesignicons-webfont.woff?v=6.6.96") format("woff"), url("../fonts/materialdesignicons-webfont.ttf?v=6.6.96") format("truetype");
font-weight: normal;
font-style: normal;
}
To serve these fonts we need to copy the installed fonts from ./node_modules/@mdi/font/fonts
folder to the ./public/fonts
folder.
To automatize this operation we added a command at the beginning of the serve
script :
// From './package.json'
{
...
"scripts": {
"serve": "cp -a ./node_modules/@mdi/font/fonts/. ./public/fonts && vue-cli-service serve",
"build": "cp -a ./node_modules/@mdi/font/fonts/. ./public/fonts && vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"lint": "vue-cli-service lint"
},
...
}
- Import CSS styles as strings with
raw-loader
toshadowCss
- Inject CSS styles in
shadow-root
instead of<head>
tag - vue-custom-element-shadow-examples (with Vuetify)
- vue-custom-element shadow DOM example with Bootstrap
URL : https://test-vue-custom-element-with-buefy.netlify.app
The current project is working with npm 16.12.0
version
To install it, use the command :
nvm use
npm install
To run locally Datami you just have to type :
npm run serve
npm run build
npm run test:unit
npm run lint