• 微前端的起源


    微前端的概念最早由 thoughtworks 在 2016 年提出。其核心思路是借鉴后端微服务架构理念,将一个单体的庞大的前端应用拆分为多个简单独立的前端工程。每个前端工程可以独立开发、测试、部署。最终再由一个容器应用,将拆分后的微前端工程组合为一个整体,面向用户提供服务。

    微前端架构图

    微前端的架构方式所带来的好处也是显而易见的:

    • 降低代码耦合
    • 微前端可独立部署
    • 团队可以按照业务垂直拆分更高效

    常见的实现方式

    微前端的概念最近一两年很火。但必须指出的是,微前端并不是一门新技术,而是一种新的架构方式。社区开发者们充分发挥聪明才智,提供了不少实现思路。

    iframe

    对于前端同学来讲,最容易想到的就是 iframe 了。iframe 天然具备微前端的基因。我们只需将单体的前端应用,按照业务模块进行拆分,分别部署。最后通过 iframe 进行动态加载即可。 一个简单的实现如下:

    <html>
      <head>
        <title>微前端-ifame</title>
      </head>
      <body>
        <h1>我是容器</h1>
        <iframe id="mfeLoader"></iframe>
        <script type="text/javascript">
          const routes = {
            '/': 'https://app.com/index.html',
            '/app1': 'https://app1.com/index.html',
            '/app2': 'https://app2.com/index.html',
          };
    
          const iframe = document.querySelector('#mfeLoader');
          iframe.src = routes[window.location.pathname];
        </script>
      </body>
    </html>
    复制代码

    优点

    • 实现简单
    • 天然具备隔离性

    缺点

    • 主页面和 iframe 共享最大允许的 HTTP 链接数。
    • iframe 阻塞主页面加载。
    • 浏览器的后退按钮无效

    服务端模板组合

    有年代感的前端程序员对这种方式一定不陌生。常见的实现方式是,服务端根据路由动态渲染特定页面的模板文件。架构图如下:

    服务端模板组合

    容器模板代码如下:

    <html lang="en" dir="ltr">
      <head>
        <meta charset="utf-8">
        <title>微前端-服务端模板</title>
      </head>
      <body>
        <h1>容器应用</h1>
        <!--# include file="$PAGE.html" -->
      </body>
    </html>
    复制代码

    通过 Nginx 服务器根据 url 路径动态设置要加载的模板:

    server {
        listen 8080;
        server_name localhost;
    
        root /usr/share/nginx/html;
        index index.html;
        ssi on;
    
        rewrite ^/$ http://localhost:8080/app redirect;
    
        location /app {
          set $PAGE 'app';
        }
        location /app1 {
          set $PAGE 'app1';
        }
        location /app2 {
          set $PAGE 'app2';
        }
    
        error_page 404 /index.html;
    }
    复制代码

    优点

    • 实现简单
    • 技术栈独立

    缺点

    • 需要额外配置 Nginx
    • 前后端分离不彻底

    微前端框架 single-spa

    对于时刻将 “没有 js 做不到的事情” 视为座右铭的前端程序员们是不可能不造轮子的,鼎鼎大名的 single-spa 就这么被造出来了。

    single-spa

    借助 single-spa,开发者可以为不同的子应用使用不同的技术栈,比如子应用 A 使用 vue 开发,子应用 B 使用 react 开发,完全没有历史债务。

    single-spa 的实现原理并不难,从架构上来讲可以分为两部分:子应用和容器应用。

    子应用与传统的单页应用的区别在于

    • 不需要 HTML 入口文件,
    • js 入口文件导出的模块,必须包括 bootstrap、mount 和 unmount 三个方法。

    容器应用主要负责注册应用,当 url 命中子应用的路由时激活并挂载子应用,或者当子应用不处于激活状态时,将子应用从页面中移除卸载。其核心方法有两个:

    • registerApplication 注册并下载子应用
    • start 启动处于激活状态的子应用。

    以下是 single-spa 的简单示例:

    容器应用代码

    <html>
    <body>
        <script src="single-spa-config.js"></script>
    </body>
    </html>
    复制代码

    single-spa-config.js 代码如下:

    import * as singleSpa from 'single-spa';
    const appName = 'app1';
    const app1Url = 'http://app1.com/app1.js'
    
    singleSpa.registerApplication('app1',() => loadJS(app1Url), location => location.pathname.startsWith('/app1'))
    
    singleSpa.start();
    复制代码

    loadJS 方法是伪代码,表示加载 app1.js。开发者需要自己实现,或者借助 systemJS 来实现。

    子应用代码:

    //app1.js
    let domEl;
    export function bootstrap(props) {
        return Promise
            .resolve()
            .then(() => {
                domEl = document.createElement('div');
                domEl.id = 'app1';
                document.body.appendChild(domEl);
            });
    }
    export function mount(props) {
        return Promise
            .resolve()
            .then(() => {
                domEl.textContent = 'App 1 is mounted!'
            });
    }
    export function unmount(props) {
        return Promise
            .resolve()
            .then(() => {
                domEl.textContent = '';
            })
    }
    复制代码

    优点

    • 纯前端解决方案
    • 可以使用多种技术栈
    • 完善的生态

    缺点

    • 上手成本高
    • 需要改造现有应用
    • 跨应用的联调变得复杂

    适用场景

    以上介绍了三种常见的微前端架构方式。天生喜爱新事物的前端同学,早就想要一试了。那么问题来了。哪些场景适合微前端架构?采用哪种微前端实现方式?我的看法很简单:

    1. 业务模块相对独立的复杂单体应用
    2. 综合考虑团队技术能力和业务现状选择适合的方式

    总结

    以上介绍了三种常见的微前端实现方式:

    • 使用 iframe 组合
    • 服务端模板渲染组合
    • 微前端框架 single-spa
  • 相关阅读:
    面试题6:用两个栈实现队列
    cygrunsrv: Error starting a service: QueryServiceStatus: Win32 error 1062: 解决办法
    支付系统的对账处理与设计--转
    centos 6.7下安装rabbitmq 3.6.6过程
    Can't access RabbitMQ web management interface after fresh install
    Spring Cloud Netflix Eureka client源码分析
    spring cloud config配置中心源码分析之注解@EnableConfigServer
    量化派基于Hadoop、Spark、Storm的大数据风控架构--转
    Inversion of Control Containers and the Dependency Injection pattern--Martin Fowler
    spark groupByKey 也是可以filter的
  • 原文地址:https://www.cnblogs.com/plBlog/p/14023915.html
Copyright © 2020-2023  润新知