美文网首页over
前端微服务化进阶3 - 跨模块共享组件

前端微服务化进阶3 - 跨模块共享组件

作者: Hello丶Alili | 来源:发表于2020-06-20 11:57 被阅读0次

    个人博客: https://alili.tech/

    前端微服务化之后,我们会面临一个问题: 模块之间重复代码不能复用的问题.

    如果使用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/

    相关文章

      网友评论

        本文标题:前端微服务化进阶3 - 跨模块共享组件

        本文链接:https://www.haomeiwen.com/subject/vemwxktx.html