DEV Community

mizchi (Kotaro Chikuba)
mizchi (Kotaro Chikuba)

Posted on

Mount vue component in react with webcomponents

I tried helpers to mount react and vue components via webcomponents.

https://github.com/mizchi/wc-helpers

My goal is to try micro-frontend.

import { vueElementFactory, reactElementFactory, encodeProps } from "@mizchi/wc-helpers"; // register customElements.define("my-react-component", reactElementFactory(MyReactApp)); customElements.define("my-vue-component", vueElementFactory(MyVueApp)); // run const state = { a: 0 }; const encoded = encodeProps(state); document.body.innerHTML = ` <my-react-component data-props="${encoded}"></my-react-component> <my-vue-component data-props="${encoded}"></my-vue-component> `; 
Enter fullscreen mode Exit fullscreen mode

Mount another platform

  • my-react-component(depth=n) => my-vue-component(depth=n-1)
  • my-vue-component(depth=n) => my-react-component(depth=n-1)

HTML

Code

import Vue from "vue"; import Component from "vue-class-component"; import React from "react"; import { vueElementFactory, reactElementFactory, encodeProps } from ".."; // Vue @Component({ props: ["depth"] }) class MyVueApp extends Vue { now: number = Date.now(); render(h: any) { const depth = parseInt(this.$props.depth, 10); if (depth > 0) { return h( "div", { style: { paddingLeft: "10px", backgroundColor: "rgba(0, 255, 0, 0.3)" } }, [ h("p", {}, `vue: ${depth} createdAt:${this.now}`), h("my-react-component", { attrs: { "data-props": encodeProps({ depth: depth - 1 }) } }) ] ); } else { return h( "p", { style: { paddingLeft: "10px", backgroundColor: "rgba(0, 255, 0, 0.3)" } }, `vue: 0 - createtAt:${this.now}` ); } } } customElements.define("my-vue-component", vueElementFactory(MyVueApp)); // React class MyReactApp extends React.PureComponent<{ depth: string }> { now: number = Date.now(); render() { const h = React.createElement; const depth = parseInt(this.props.depth, 10); if (depth > 0) { return h( "div", { style: { paddingLeft: "10px", backgroundColor: "rgba(255, 0, 0, 0.3)" } }, h("p", {}, `react: ${depth} createdAt: ${this.now}`), h("my-vue-component", { "data-props": encodeProps({ depth: depth - 1 }) }) ); } else { return h( "p", { style: { paddingLeft: "10px", backgroundColor: "rgba(255, 0, 0, 0.3)" } }, "react 0: createdAt " + this.now ); } } } customElements.define("my-react-component", reactElementFactory(MyReactApp)); // run // const root = document.querySelector(".root"); let state = { depth: 4 }; const entry = document.createElement("my-react-component"); entry.setAttribute("data-props", state.depth.toString()); document.body.appendChild(entry); setInterval(() => { state = { depth: state.depth + 1 }; entry.setAttribute( "data-props", encodeProps({ depth: (state.depth % 6) + 3 }) ); }, 1000); 
Enter fullscreen mode Exit fullscreen mode

How it works

  • Encode json to safe string
  • Define Component
  • Listen data-props's attributeChangedCallback
  • re-render

See implementation (114 lines) https://github.com/mizchi/wc-helpers/blob/master/index.ts

Why wc-helper needs encode

WebComponents takes properties as string only. If you need to handle event handlers, try lit-html and lit-html/lib/lit-extended.

https://github.com/Polymer/lit-html

Top comments (0)