背景
A项目要使用B包,B包处在研发阶段。A和B组件之间传递数据还比较复杂,AB还属于不同地域。
简单粗暴方法,就是直接把代码搞在本地,然后去调试。 那除了这种粗暴方法其他有高端的办法吗?
模块联邦
项目采用的是vite+react。(和当前技术栈保持一致)
app-A
项目将会引用app-B
项目(组件
app-B 项目配置
- 首先创建两个项目,并安装两个包
pnpm create vite app-B --template react-ts
pnpm create vite app-A --template react-ts
- 首先配置
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
- 先执行
pnpm run build
将包打出来,会生成一个/app-B/dist/assets/remoteEntry.js
的入口文件。 - 执行
pnpm run preview
- 可以验证下入口文件是否被打包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用的是开发的热更新地址,所有对面一保存,这边就可以刷新了。两个人相互同步调试。 这种方法在项目开发初期比较适用。
其他方法
- pnpm link 本质是本地上的软链,需要拉取到对方代码。 soft link 也是支持热更新的。
- 使用grafish微前端框架,没错这个是个微前端。www.garfishjs.org/guide
可以做进一步的完善,增加新的ruouter,注册子应用,应用上线周期更加灵活化。
这些方法就有点麻烦了。
© 版权声明
文章版权归作者所有,未经允许请勿转载,侵权请联系 admin@trc20.tw 删除。
THE END