在 Vue 中渲染 React 组件(跨技术栈渲染研究)

背景介绍

虽然在日常工作中很少会碰到跨技术栈的组件引用这种骚操作,但是不同项目组、甚至是一个集团的不同子公司之间还是有相互嵌入页面、组件的需求,本文主要为了解决这一问题。

方案介绍

经过一顿搜索,最终确定的方案是通过 web components 做中间层(兼容性查看 caniuse)。

但是这里有一个难题是,怎么把 react 或者 vue 组件转为 web components 以及怎么传入函数?这里推荐用字节跳动的 @magic-microservices/magic 仓库,它的就是为了解决上述问题的!

我们以 react 组件嵌入 Vue 为例:

创建 react 组件

mkdir react-hello && cd react-hello
yarn add father-build -D # 用于构建 react 组件
yarn add react react-dom
touch index.js # 创建 index.js
复制代码
# 创建 father-build 的配置文件
echo "export default {
  entry: './index.js',
  esm: 'rollup'
}" > .fatherrc.js
复制代码
// index.js
import React, { createElement } from 'react';
import ReactDOM from 'react-dom';

// 定义组件
const Hello = ({name}) => {
  return <div>hello { name }</div>
}

// 初始化
export function bootstrap() {}

// 挂载
export function mount(container, props) {
  console.log(props)
  ReactDOM.render(createElement(Hello, props, null), container);
}

// 更新
export function updated(attrName, value, container, props) {
  ReactDOM.render(createElement(Hello, props, null), container);
}
复制代码

修改 package.json,增加 version 和 name:

{
  "name": "react-hello",
  "version": "0.0.1",
  "main": "./dist/index.esm.js",
  "scripts": {
    "build": "father-build"
  },
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  },
  "devDependencies": {
    "father-build": "^1.20.1"
  }
}
复制代码

执行 yarn link 进行全局链接。

Vue 项目渲染 React 组件

yarn create @vitejs/app my-vue-app --template vue
复制代码

安装如下内容:

yarn link "react-hello" # 链接组件
yarn add react react-dom # 因为是打包为 es module 形式,所以这里需要安装依赖
yarn add @magic-microservices/magic # 安装 magic
复制代码

修改 main.js

import { createApp } from 'vue'
import App from './App.vue'
import magic from '@magic-microservices/magic';
import * as ReactHello from 'react-hello';

// 全局注册组件
magic('react-hello', ReactHello, {
  // 这里很重要,web components 要求一定要显示声明属性
  propTypes: {
    name: String
  },
});

createApp(App).mount('#app')
复制代码

修改 vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [
    vue({
      template: {
        compilerOptions: {
          // 将所有包含短横线的标签作为自定义元素处理
          isCustomElement: tag => tag === 'react-hello'
        }
      }
    })
  ]
})
复制代码

修改 App.vue

<template>
  <react-hello name="react"></react-hello>
</template>
复制代码

image.png

DEMO 链接为:[email protected]:dream2023/cross-stack…

完结撒花 ✿✿ヽ(°▽°)ノ✿

猜你喜欢

转载自juejin.im/post/7018497647832989709