前端微服务化进阶3 - 跨模块共享组件
前端微服务化之后,我们会面临一个问题: 模块之间重复代码不能复用的问题.
如果使用npm管理我们的重复代码,我们会多出维护npm包的成本. 在子模块更新npm包版本,也是一件很麻烦的事情. 在js文件体积上也没有任何的优化.
组件共享
今天我们就来聊一聊如何在多个模块中同时使用一个组件.
思路
在base模块管理公共组件,将组件封装成动态组件,这样在打包的时候我们就可以将该组件切割成单独文件了. 当其他的子模块需要这个组件的时候,向Base模块动态获取.
实践
动态组件的封装
为了让其他模块可以按需加载我们的公共组件,我们需要对已有的组件封装成动态组件.
我这里使用的是 umi/dynamic
,
他是基于https://github.com/jamiebuilds/react-loadable 封装了一层. 有兴趣的小伙伴可以自行了解.
import React from 'react';
import dynamic from 'umi/dynamic';
import PageLoading from '@/components/PageLoading'
export const Demo = dynamic(import( `../Demo`), {loading: () => <PageLoading />})
export default Demo;
对外提供获取动态组件的方法
在加载Base模块的时候,我们可以在window下暴露一个调用该模块动态组件的方法
window.getDynamicComponent = async function(name) {
let component = null;
component = await import(`@/components/dynamic/${name}`);
return component[name];
};
子模块调用公共组件
因为base模块提供了一个获取公共组件的全局方法, 我们就可以在任何模块任何需要调用公共组件的地方去是使用它了.
// 获取组件
let component = await window.getDynamicComponent('Demo')
为了方便这种公共组件的使用,我们可以将这一方法封装成一个组件. 在调用公共组件,我们只需要声明就好了.
import React, { Component } from 'react';
// Matrix 在黑客帝国中是母体的意思
export default class Matrix extends Component {
state = {
DynamicComponent: null
}
static defaultProps = {
$name: ""
}
async componentWillMount() {
this.renderComponent()
}
componentWillReceiveProps(nextProps) {
this.props = nextProps
this.renderComponent()
}
async renderComponent() {
const { $name } = this.props;
try {
if ($name) {
const component = await window.getDynamicComponent($name)
this.setState({
DynamicComponent: component
})
}
} catch (error) {
this.setState({
DynamicComponent: null
})
console.error(error)
}
}
render() {
const { DynamicComponent } = this.state;
// 继承所有props
return DynamicComponent && <DynamicComponent {...this.props} />;
}
}
在实际页面中调用我们的公共组件
import React, { Component } from 'react';
import Matrix from '@/components/Matrix'
export default class Page extends Component {
render() {
return (
<div>
<Matrix name="Demo" />
</div>
);
}
}
尾巴
实现这样的功能,其实非常简单. 但是因为如此,我们需要对公共组件的颗粒度要有一些把控. 不然我们可能会遇到一个页面会加载文件过多的问题,随之会影响页面加载速度. 当然我们也可以通过现有的网络技术去改善这种状况.
有了这一思路,我们或许可以在我们的子模块中不引用任何的其他组件, 依赖我们的base模块提供的公共组件.我们就可以完成页面的开发.
前端微服务化的可玩性非常的高.而且还有更多的玩法没有挖掘出来.
相关系列文章
https://alili.tech/tags/microfrontend/