一、前言
微前端的概念相信大家都不陌生,其本质是一种架构设计思想,将一个完整的项目拆分成若干个小项目,项目的开发和部署互不影响,上线后再聚合成一个完整的项目。webpack5的模块联邦其功能与这个类似,可以用来加载远程模块
二、三个概念
模块联邦有三个重要的概念:
- webpack构建,一个独立项目通过webpack打包编译而产生资源包
- remote,一个暴露模块提供其它
webpack构建
消费的 webpack构建
- host,一个消费其他
remote
模块的 webpack构建
一言以蔽之,一个webpack构建可以是remote–即服务的提供方,也可以是host–即服务的消费方,也可以同时扮演服务提供方和服务消费者,完全看项目的架构。
需要指出的是,任何一个webpack构建既可以作为host消费方,也可以作为remote提供方,区别在于职责和webpack配置的不同
三、项目实战
一共有三个微应用: lib-app
、component-app
、main-app
,角色分别是:
lib-app
as remote,暴露了两个模块 react
和 react-dom
- component-app as remote and host,依赖lib-app,暴露了一些组件供main-app消费
- main-app as host,依赖lib-app和component-app
lib-app暴露模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| module.exports = { plugins: [ new ModuleFederationPlugin({ name: "lib_app", filename: "remoteEntry.js", exposes: { "./react":"react", "./react-dom":"react-dom" } }) ], }
|
component-app的配置
依赖 lib-app
,暴露三个模块组件 Button
、Dialog
、Logo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| module.exports = { plugins:[ new ModuleFederationPlugin({ name: "component_app", filename: "remoteEntry.js", exposes: { "./Button":"./src/Button.jsx", "./Dialog":"./src/Dialog.jsx", "./Logo":"./src/Logo.jsx" }, remotes:{ "lib-app":"lib_app@http://localhost:3000/remoteEntry.js" } }), ] }
|
1 2 3 4 5
| import React from 'lib-app/react'; export default function(){ return <button style={{color: "#fff",backgroundColor: "#409eff",borderColor: "#409eff"}}>按钮组件</button> }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import React from 'lib-app/react'; export default class Dialog extends React.Component { constructor(props) { super(props); } render() { if(this.props.visible){ return ( <div style={{position:"fixed",left:0,right:0,top:0,bottom:0,backgroundColor:"rgba(0,0,0,.3)"}}> <button onClick={()=>this.props.switchVisible(false)} style={{position:"absolute",top:"10px",right:"10px"}}>X</button> <div style={{ marginTop:"20%",textAlign:"center"}}> <h1> What is your name ? </h1> <input style={{fontSize:"18px",lineHeight:2}} type="text" /> </div>
</div> ); }else{ return null; }
} }
|
1 2 3 4 5 6
| import React from 'lib-app/react'; import pictureData from './MF.jpeg' export default function(){ return <img src={pictureData} style={{width:"500px",borderRadius:"10px"}}/> }
|
main-app的配置
main-app依赖两个项目 lib-app
和 component-app
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| module.exports = { plugins: [ new ModuleFederationPlugin({ name: "main_app", remotes:{ "lib-app":"lib_app@http://localhost:3000/remoteEntry.js", "component-app":"component_app@http://localhost:3001/remoteEntry.js" }, }), new HtmlWebpackPlugin({ template: "./public/index.html", }) ] };
|
使用
在 main-app
中引入 component-app
暴露出来的模块,即可使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import React from 'lib-app/react'; import Button from 'component-app/Button' import Dialog from 'component-app/Dialog' import Logo from 'component-app/Logo' export default class App extends React.Component{ constructor(props) { super(props) } render(){ return (<div> //省略... </div>) } }
|