前端不同仓库之间联调方法

背景

A项目要使用B包,B包处在研发阶段。A和B组件之间传递数据还比较复杂,AB还属于不同地域。

简单粗暴方法,就是直接把代码搞在本地,然后去调试。 那除了这种粗暴方法其他有高端的办法吗?

模块联邦

项目采用的是vite+react。(和当前技术栈保持一致)

app-A 项目将会引用app-B 项目(组件

app-B 项目配置

  1. 首先创建两个项目,并安装两个包
pnpm create vite app-B --template react-ts

pnpm create vite app-A --template react-ts
  1. 首先配置 app-graph 项目下的 vite.config.ts 配置,如下
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import federation from "@originjs/vite-plugin-federation";

// https://vitejs.dev/config/
export default defineConfig({
    build:{
      target:['edge90','chrome90','firefox90','safari15']
    },
    esbuild: {
      target: "es2020"
    },
    optimizeDeps: {
      esbuildOptions : {
          target: "es2020"
    }
  },
  plugins: [react(),
    federation({    // 重点关注这里配置
      name: "app-B",    // App名称
      filename: "remoteEntry.js", // 生成文件名称
      remoteType:  "module",  //生成包类型
      exposes: {
        "./App": "./src/App.tsx", // 输出组件
      },
      shared: ["react"],
    })
  ],
})

完成app-B项目组件 App.tsx

import './App.css'
interface dataProps{
  name: string
}
function App(props: dataProps) {

  return (
    <>
      <div>
      .ʕ◔ϖ◔ʔ.. Yeap... I'm Here! --- from {props.name}
      </div>
    </>
  )
}

export default App
  1. 先执行 pnpm run build 将包打出来,会生成一个 /app-B/dist/assets/remoteEntry.js 的入口文件。
  2. 执行 pnpm run preview
  3. 可以验证下入口文件是否被打包ok http://localhost:3002/assets/remoteEntry.js

Tips: 修改端口的方法是:"preview": "vite preview --port=3002"

app-A项目配置

配置 app-A项目下的 vite.config.ts文件,如下:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import federation from "@originjs/vite-plugin-federation";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react(),
    federation({
      name: "app1",
      remotes: {
        AppGraph: "http://localhost:3002/assets/remoteEntry.js",
      },
      shared: ["react"],
    }),
  ],
})

App.tsx 文件中引入外部组件如下:

import React, { Suspense } from "react";
const RemoteApp = React.lazy(() => import("AppGraph/App"));

function App() {
  return (
    <>
      <div>
        <div
          style={{
            margin: "10px",
            padding: "10px",
            textAlign: "center",
            backgroundColor: "greenyellow",
          }}
        >
          <h1>Risk</h1>
        </div>
        <Suspense fallback={"loading..."}>
         {/* 这里是组件引入方法,以及对应的参数 */}    
          <RemoteApp name="app-A"/> 
        </Suspense>
    </div>
    </>
  )
}

export default App

运行app-A就可以看到app-B作为一个组件引入进来了。

小结

模块联邦需要阶段性的完成工作,然后去build产物。(这样也符合预期)
那有没有办法实时同时开发的?看下面iframe形式。

万能的iframe

app-B 组件

import './App.css'
import {useEffect,useState} from 'react'
interface dataProps{
  name: string
}
function App(props: dataProps) {
  const [message, setMessage] = useState<string>('')
  const messageHandler = (event) => {
    console.log(event);
    setMessage(event.data) // 接收来自外部数据,也就是图漏出的参数
  }
  useEffect(()=>{
    window.addEventListener("message", messageHandler);
    return ()=>{
      window.removeEventListener("message", messageHandler);
    }
  },[])
  return (
    <>
      <div>
      .ʕ◔ϖ◔ʔ.. Yeap... I'm Here! --- from {message} 
      </div>
    </>
  )
}

export default App

app-A 组件

import React, { useEffect, useRef } from "react";

function App() {
  const iframeRef = useRef();
  const postMessage = () => {
    setTimeout(()=>{
       {/* 把组件所需要的参数传递进去*/}
      iframeRef.current?.contentWindow.postMessage('app-A', 'http://127.0.0.1:3002/')
    },0)  
  }

  useEffect(() => {
    const iframe = iframeRef.current;
    if(!iframe){
      return
    }
    iframe.addEventListener('load', postMessage);
    return () => {
      iframe.removeEventListener('load', postMessage);
    };
  }, [iframeRef.current]);

  return (
    <>
      <div>
        <div
          style={{
            margin: "10px",
            padding: "10px",
            textAlign: "center",
            backgroundColor: "greenyellow",
          }}
        >
          <h1>Risk</h1>
        </div>
          {/* 这里是iframe引入方法 */}
          <iframe  
            id="app-B" 
            name="app-B" 
            ref={iframeRef}  
            scrolling="yes" 
            frameBorder="0"
            style={{height:400, width:400, overflow:'visible'}}
            src={"http://127.0.0.1:3002/"}
          />
    </div>
    </>
  )
}

export default App

小结

这种方法iframe用的是开发的热更新地址,所有对面一保存,这边就可以刷新了。两个人相互同步调试。 这种方法在项目开发初期比较适用。

其他方法

  1. pnpm link 本质是本地上的软链,需要拉取到对方代码。 soft link 也是支持热更新的。
  2. 使用grafish微前端框架,没错这个是个微前端。www.garfishjs.org/guide
    可以做进一步的完善,增加新的ruouter,注册子应用,应用上线周期更加灵活化。

这些方法就有点麻烦了。

原文链接:https://juejin.cn/post/7244083820215222330 作者:大熊全栈分享

(0)
上一篇 2023年6月14日 上午10:41
下一篇 2023年6月14日 上午10:51

相关推荐

发表回复

登录后才能评论