vue-hybrids
v1.1.3
Published
Wrap Vue components as Hybrids JS web components.
Downloads
976
Maintainers
Readme
vue-hybrids
Hybrids web component wrappers for Vue components
vue-hybrids is an interop layer for Vue components and built on hybridsJS. Using vue-hybrids, you can quickly transition from building Vue single file components into pure web components with minimal interruptions to your toolchain.
Getting Started
Install npm package:
npm i --save-dev vue-hybrids
Then, import the vue-hybrids define
function into your SFC:
<script>
import {define} from 'vue-hybrids'
export default define({
name: 'my-vue-component',
props: {
foo: {type: String},
bar: {type: Number},
},
// ...
})
</script>
Finally, import the vue component to register it as a web component and use it in your appplication:
import './path/to/my-vue-component.vue'
<my-vue-component :foo="fooProp" :bar="barProp" @ondelete="onDelete" @onCreate="onCreate" />
define
will wrap your component in a Hybrids JS web component, register it, and proxy all your props and events.
API
define
Define and register a new web component using an existing Vue component. Define returns the defn
argument.
define(defn: Object, options: DefineOptions): void
defn
A Vue component definition. Some special considerations around various options:
name
: This will be the name of the web component. By standard, web components must have a hyphen in their name.
options: DefineOptions
Various options for the component and/or component wrapper
vue?: Vue
An instance of the Vue constructor. This can be helpful for components which need to inherit functionality from plugins.
import {define} from 'vue-hybrids' import vue from 'vue' import Vuex from 'vuex' vue.use(Vuex) define({name: 'my-store', /* ... */}, {vue}) // the component has access to this.$store
styles?: string | string[]
Style sheet strings for the shadowDOM. vue-hybrids will ensure that these styles do not bleed into the light DOM.
import {define} from 'vue-hybrids' import globalStyles from './my-global-styles.styl' import styles from './my-styles.styl' define({name: 'my-styled-component', /* ... */}, {styles: [globalStyles, styles]})
If you are using the typical vue-loader toolchain to bundle styles in conjunction with vue-hybrids, SFC <style>
tags will still be mounted in the light DOM and CSS selection into the shadow DOM will be restricted. Please avoid this in order to keep your web components side-effect free.
wrap
Wrap a vue component as a Hybrids component. The component can be defined later with a different name using the hybrids define
function.
import {wrap} from 'vue-hybrids'
import {define} from 'hybrids'
const hybrid: Hybrids<CustomElement> = wrap(defn: Object, options: DefineOptions)
// ...
define('my-element-name', hybrid)
Attributes
These attributes are available on all vue-hybrids components
vh-debug
A boolean prop which is available for every vue-hybrid which renders the proxied props, their type, and their value.
<my-component :prop="foo" vh-debug/>
vh-key
A string key functioning much like key
in Vue. If the value of vh-key
changes, vue-hybrids will refresh the encapsulated Vue component.
This will execute all of its lifecycle methods again.
Design Considerations
Binding Prop Data
When passing props to vue-hybrids components from a vue component, you will need to pass props by property instead of by attribute. To do this, add the .prop
modifier to your props in vue templates.
- An issue with the
.prop
shorthand (.
) is documented here
<my-component :static="staticValue" :dynamic.prop="dynamicValue" />
Converting Vue Props
It's considered best practice to define types in your Vue component props. If no type is provided the wrapping hybrids component will assume a string, like other HTML attributes.
Vue Functionality
Avoid using the custom model
property of Vue component definitions. When wrapped as a web component,
the parent Vue component will not know to which event and prop it should bind v-model.
Instead, design your component to use the traditional value
prop and input
event if possible.
Or, if this is not possible, you may spell out the prop and event binding manually:
<my-component :value="myBoundValue" @change="(value) => myBoundValue = value" />
IE11
Though IE11 does not support the shadowDOM for style encapsulation, vue-hybrids should work with some polyfill support. Normally, one would include the following before any of their app code:
import '@webcomponents/webcomponentsjs`
However, if you are using @babel/preset-env and/or core-js, you may have difficulty with overlapping polyfills.
vue-hybrids
provides a fix if your build falls into this scenario. Replace your @webcomponents import statement with:
import 'vue-hybrids/dist/polyfill.min.js' //464 KB
If your polyfill implementation is more complicated, a manual fix can be employed by assigning a nonsense Symbol
before your @webcomponents import:
// Forces core-js to include their Symbol polyfill strictly before @webcomponents
const nonce = Symbol('I_DO_NOTHING')
import '@webcomponents/webcomponentsjs'
As a last resort, I've included a build of the @webcomponents/webcomponentsjs package which disincludes the Symbol polyfill. The package build outputs are generated from a fork (auzmartist/polyfills) and can be used like so:
import 'vue-hybrids/dist/legacy-polyfill.min.js' // 1,127 KB
Vue Dev Tools
vue-hybrids is compatible with vue dev tools. You can still inspect your mounted vue elements. Each defined component will show as wrapped in a <shadow-root>
tag to signify it's placement in the shadow DOM.
NOTE: If using vue-hybrids within another Vue app, Vue Dev Tools will tend to bind to your app Vue instance.
Development
Contributions welcome!
git clone [email protected]:auzmartist/vue-hybrids.git
cd vue-hybrids
npm install
npm run dev