We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
我们团队正在做一个XX系统,技术栈是React,目前该系统日渐庞大,开发及维护成本加大,且每次必须把整个项目一起打包,费时费力。经考虑后决定将其拆分成多个项目,由它们组合成一个完整系统,微前端架构是非常好的选择。
React
微前端差不多有以下几个好处:
商品模块
对我们来说最大的好处是单项目维护。
单项目维护
我们将整个微前端分为两个部分:
注意看地址栏变化,其中包含 /app1/xxx和/app2/xxx,乍一看这是一个项目中两个页面的切换,实际上是来自两个独立的项目,app1 和 app2 来自不同的 git 仓库。
/app1/xxx
/app2/xxx
整个流程大概为:用户访问 index.html, 此时运行模块加载器Js,加载器会根据整个系统的配置文件(project.config) 去注册各个项目,系统会先加载主项目(Main),然后会根据路由前缀动态加载对应的子项目
我们这个架构也参考了网上很多好的文章,其中核心文章可参考 https://alili.tech/archive/11052bf4/
大概如下
[ { isBase: false, name: 'app1', version: '1.0.0', //通过该路由前缀匹配加载当前入口文件 hashPrefix: '/app1', //入口文件 entry: 'http://www.xxxx.com/app1/dist/singleSpaEntry.js', //顶级Store store: 'http://www.xxxx.com/main/dist/store.js' } ...... ]
我们找了些实现微前端的仓库,对比后决定使用single-spa。
我们技术栈是 react,在子项目入口中需要使用 single-spa-react 来构建,关键代码如下:
import singleSpaReact from 'single-spa-react'; const reactLifecycles = singleSpaReact({ React, ReactDOM, rootComponent: Root, domElementGetter }); export function bootstrap(props) { return reactLifecycles.bootstrap(props); } export function mount(props) { return reactLifecycles.mount(props); } export function unmount(props) { return reactLifecycles.unmount(props); }
如果你使用 vue,可以使用 single-spa-vue
然后在系统入口文件中,把所有的项目注册进来:
import * as singleSpa from 'single-spa'; singleSpa.registerApplication( 'app1', () => SystemJS.import('app1-entry.js'), () => location.hash.startsWith(`#/app1`), props );
具体可参考 single-spa 官网 https://single-spa.js.org 这里有很多例子
我们使用的 lerna 统一管理所有项目的依赖包,所有依赖包的版本统一,这样非常方便维护。
使用 webpack 的 dll 功能,将所有项目的公用依赖包抽离,比如 react、react-dom、react-router、mobx等
为了方便项目动态加载,我们也参考网上大佬的想法,使用了systemjs,只不过我们使用的是 0.20.19 版本,配合 systemjs ,在 Webpack 中需要改一下 libraryTarget:
output: { publicPath: 'http://www.xxxxx.com/', filename: '[name].js', chunkFilename: '[name].[chunkhash:8].js', path: path.resolve(__dirname, 'release'), libraryTarget: 'amd', //注意 这里使用 amd 的规范 library: 'app1' },
我们没有使用 umd 规范,也没有使用 systemjs 里的 Import Maps 功能,而是直接通过 project.config 来动态加载模块入口。
关于这个也看了一些大佬的方案,大概就是所有的项目里有个 store,在注册入口时将所有 store 放进队列,需要更新 store 里的状态时,调用 dispatch 将所有 store 同步。
我的做法和传统单页应用一样,一个系统应该只有一个顶级 Store,由于顶级 Store 里存的一般是整个系统的公用状态 比如菜单、用户信息等,我把它放在 Main项目里,但打包时这个Store是单独抽离的:
entry: { singleSpaEntry: './src/singleSpaEntry.js', store: './src/store' //单独一个入口 },
在注册时,将这个 Store 传入每个项目中:
//顶级Store const mainStore = await SystemJS.import(storeURL); singleSpa.registerApplication( 'app1', () => SystemJS.import('http://www.x.com/app1/entry.js'), hashPrefix('/app1'), { mainStore } ); singleSpa.registerApplication( 'app2', () => SystemJS.import('http://www.x.com/app2/entry.js'), hashPrefix('/app1'), { mainStore } );
这样就可以达到只管理这一个 Store 就可以,非常方便。 注意:我使用的是 Mobx 作为状态管理
我们部署的方式非常简单,我自己写了一个 webpack 插件用于把打包后的 dist 传到 OSS 然后将项目信息传给服务端,服务端根据我传入的项目信息组织成 project.config,然后用户在访问 index.html 时会获取 project.config,此时 single-spa 根据配置注册所有项目,然后根据路由来拉取对应的项目入口文件js文件。
我们的需求是 Main 作为整个项目的 Layout,其中子项目的挂载 Dom 也在 Main项目里,这就必须等到 Main 项目完全渲染完成后,才能挂载子项目。我参考了网上有些微前端的实现,把 domElementGetter 方法借鉴了过来:
function domElementGetter() { let el = document.getElementById('sub-module-wrap'); if (!el) { el = document.createElement('div'); el.id = 'sub-module-wrap'; } let timer = null; timer = setInterval(() => { if (document.querySelector('#content-wrap')) { document.querySelector('#content-wrap').appendChild(el); clearInterval(timer); } }, 100); return el; }
demo地址:https://github.com/Vibing/micro-frontend
这是我们第一次玩微前端,可能有很多地方不完美,还望各位大佬多多包涵
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
我们团队正在做一个XX系统,技术栈是
React
,目前该系统日渐庞大,开发及维护成本加大,且每次必须把整个项目一起打包,费时费力。经考虑后决定将其拆分成多个项目,由它们组合成一个完整系统,微前端架构是非常好的选择。微前端差不多有以下几个好处:
商品模块
单拉出来形成一个项目,它可以由一个小组单独维护,实现良好解耦对我们来说最大的好处是
单项目维护
。展示
UI示例图
我们将整个微前端分为两个部分:
动图展示
注意看地址栏变化,其中包含
/app1/xxx
和/app2/xxx
,乍一看这是一个项目中两个页面的切换,实际上是来自两个独立的项目,app1 和 app2 来自不同的 git 仓库。微前端架构图
整个流程大概为:用户访问 index.html, 此时运行模块加载器Js,加载器会根据整个系统的配置文件(project.config) 去注册各个项目,系统会先加载主项目(Main),然后会根据路由前缀动态加载对应的子项目
我们这个架构也参考了网上很多好的文章,其中核心文章可参考 https://alili.tech/archive/11052bf4/
关于 project.config
大概如下
技术细节
single-spa
我们找了些实现微前端的仓库,对比后决定使用single-spa。
我们技术栈是 react,在子项目入口中需要使用 single-spa-react 来构建,关键代码如下:
如果你使用 vue,可以使用 single-spa-vue
然后在系统入口文件中,把所有的项目注册进来:
具体可参考 single-spa 官网 https://single-spa.js.org 这里有很多例子
Webpack 与 SystemJs
我们使用的 lerna 统一管理所有项目的依赖包,所有依赖包的版本统一,这样非常方便维护。
使用 webpack 的 dll 功能,将所有项目的公用依赖包抽离,比如 react、react-dom、react-router、mobx等
为了方便项目动态加载,我们也参考网上大佬的想法,使用了systemjs,只不过我们使用的是 0.20.19 版本,配合 systemjs ,在 Webpack 中需要改一下 libraryTarget:
我们没有使用 umd 规范,也没有使用 systemjs 里的 Import Maps
功能,而是直接通过 project.config 来动态加载模块入口。
app之间通信
关于这个也看了一些大佬的方案,大概就是所有的项目里有个 store,在注册入口时将所有 store 放进队列,需要更新 store 里的状态时,调用 dispatch 将所有 store 同步。
我的做法和传统单页应用一样,一个系统应该只有一个顶级 Store,由于顶级 Store 里存的一般是整个系统的公用状态 比如菜单、用户信息等,我把它放在 Main项目里,但打包时这个Store是单独抽离的:
在注册时,将这个 Store 传入每个项目中:
这样就可以达到只管理这一个 Store 就可以,非常方便。
注意:我使用的是 Mobx 作为状态管理
前端部署
我们部署的方式非常简单,我自己写了一个 webpack 插件用于把打包后的 dist 传到 OSS 然后将项目信息传给服务端,服务端根据我传入的项目信息组织成 project.config,然后用户在访问 index.html 时会获取 project.config,此时 single-spa 根据配置注册所有项目,然后根据路由来拉取对应的项目入口文件js文件。
把子项目的挂载 DOM 放在 Main 项目里
我们的需求是 Main 作为整个项目的 Layout,其中子项目的挂载 Dom 也在 Main项目里,这就必须等到 Main 项目完全渲染完成后,才能挂载子项目。我参考了网上有些微前端的实现,把 domElementGetter 方法借鉴了过来:
demo
demo地址:https://github.com/Vibing/micro-frontend
结束语
这是我们第一次玩微前端,可能有很多地方不完美,还望各位大佬多多包涵
The text was updated successfully, but these errors were encountered: