基于react的远程组件加载 实践

2024-2-14 633 2/14

这个自己确实研究了蛮久了,就是如何实现远程组件的加载。

因为对于业务组件一般来说,第一选择会发npm包,但是对于产品组件的话,第一就是组件过大,与独立的项目无异,迭代很频繁,有时需要更改线上的问题,且平台有时需要支持加载客户的第三方组件等问题,可以选择一个组件远程加载的方案去实现。

 

因为自己现在所做的产品,为了保证项目的扩展性,是需要支持用户可以上传自己的组件,且对于新的twin相关的产品线,也是需要支持组件可以进行远程加载的,就是说平台应用和产品组件是分离的。

对于超复杂的组件,是单独的提成了一个单独的项目去进行处理的,例如easyv中的数字孪生渲染的屏。然后在平台中去做一个按需引入。

 

给出的技术方案:

第一个就是组件的打包

组件为独立的一个项目,在打包时需要打包为一个单文件,组件打包代码为umd格式(可以去了解下umd,amd,以及cmd,esmodule规范)。将打包组件的js上传到cdn中(这里的话其实可以推荐使用阿里云的oss服务)。

第二个的话就是组件的加载。

加载的话这里其实有多种方案去选择,自己的熟悉的有两种,第一个是放在全局对象window上,第二个的话是,基于amd规范打包,在组件的使用时,使用requirejs进行组件的注册(可以去了解下关于amd,cmd规范,以及模块的加载方案)。

还有就是基于esmodule去处理的,但是这种方案的话,自己也并没有去多了解

 

实现,

这里是基于vite去搭建的项目,emmmm,减少工作量,就将测试的组件及项目合为一个项目,

首先就是子组件的打包,

我的vite配置,其实主要的是在打包时,组件的输出格式为umd,且指定打包的入口,也是我测试的子组件,保证我的打包与运行是独立的。

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import {createHtmlPlugin} from "vite-plugin-html";
import { viteSingleFile } from 'vite-plugin-singlefile'
import { resolve } from "path"
export default defineConfig (({mode}) => ({
  plugins: [react(),
    viteSingleFile(),
    createHtmlPlugin({
    inject: {
      data: { MODE: mode, HASH: Date.now() },
    },
  }),],
  server: {
    host: '127.0.0.1',
    port: 5371,
    proxy: {
      '/api': {
        target: '',
        changeOrigin: true,
      },
    },
    open: true,
  },
  define:{
    'process.env':{}
  },
  build: {
    outDir: 'lib',
    lib: {
      entry: resolve('./src/testComponent.ts'),
      name: 'ESDrager', // 使用script标签引入时全局名称
      fileName: format => `index.${format}.js`,
      formats: ['umd'],
    },
  }
}))

第一种方案,需要将组件挂在到window上面的,所以需要一个入口,也就是testComponent,入口处做一个组件的挂载

基于react的远程组件加载 实践

子组件

基于react的远程组件加载 实践

,打包后将文件放入到bucket中去

基于react的远程组件加载 实践

然后就是在项目中进行一个引入,en,这里其实只能用一个类组件去承载我们远程加载的组件,使用函数组件的话,这里会直接崩掉的,具体的原因自己还没有时间去研究。


import React, { PureComponent } from 'react';

export default class InnerEasyVComponent extends PureComponent {
    constructor(props) {
        super(props)
        this.state = {
            component: null,
        };
    }
    componentDidMount() {
        const url = 'https://linzai.oss-cn-beijing.aliyuncs.com/index.umd.js';
        const script = document.createElement('script');
        script.src = url;
        script.onload = (v) => {
        console.log(window.components.testComponent,'我的组件')
            setCom(window.components.testComponent)
        }
        document.head.appendChild(script);
    }
    render() {
        const Com = this.state.component
        return (
           <div>
               图书管理
               {
                   Com && <Com/>
               }
           </div>
        );
    }
}

 

第二种方案的话是基于amd规范去实现的,其实打包组件的规范不用变,还是基于umd(实际的话是基于amd规范去实现的,UMD 是 AMD 和 CommonJS 的一个糅合。)然后打包的话 是不需要入口的,也就是不需要testComponent.ts

然后最大的区别在于对组件的一个加载与组件,这里的话 使用requirejs获取组件并注册,

首先需要去引入requirjs,刚开始的话直接尝试去下载的他的pnpm包,不过会有error,不能够使用,

后面的话还是通过script去做的引用,

   <script src="https://requirejs.org/docs/release/2.3.6/minified/require.js"></script>

 

- THE END -
3

共有 1 条评论

  1. lll

    😱