前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >无需框架,就能实现微前端,理解起来通俗易懂

无需框架,就能实现微前端,理解起来通俗易懂

作者头像
前端修罗场
发布2022-07-29 08:11:03
2K0
发布2022-07-29 08:11:03
举报
文章被收录于专栏:Web 技术

什么微前端

微前端是一种测试方法,它为独立团队拥有的web应用提供多种功能或模块,使它们更加用户友好和更小的体积。他们基本上把前端应用分成独立的和半独立的微应用,这样每个应用都可以采用不同的技术,比如React、Angular或Vue,这样就可以很容易地集成到单个应用中

为什么需要微前端

假设你正在一个项目中使用一个特定的框架或库(比如React.js),但你需要切换到另一个框架或库,或者添加另一个在另一个框架(比如Angular.js)上编写的模块。没有一个微前端,你将不得不重写整个项目或模块,这是一个乏味的过程。

另一种情况是,如果你正在处理一个包含多个团队的大型项目,那么协作将成为一项任务。当代码库很大时,组件和页面需要连接起来,因为有时您的工作与其他团队成员的工作重叠。这将导致进一步的重写,更复杂和时间管理不善,并导致整个开发过程的延迟。如果你不需要改变任何东西,你可以用你选择的另一个框架开始添加新模块呢?这就是微前端出现的地方。

它们帮助我们在多个框架(甚至是Vanilla JS)中编写应用程序,并使用相同的路由(router)和域(domain)加载它们。我们可以开发包含认证和路由实现的主父应用程序,然后我们可以继续添加多个独立工作的子应用程序,可以在相同或不同的页面加载。

如何构建微前端

现在让我们来看看如何构建一个真正的应用,以及如何使用微前端集成两个框架,React和Angular。这里出现的第一个问题是,我们应该如何划分应用,因为没有特定的标准来划分它们。根据我们的要求,我们可以用相当多的方式来做到这一点。让我们来看看下面的一些想法:

  • 功能

这是最常用的划分,我们将在这里划分应用程序的特性或模块。例如,假设仪表板上有三个功能,我们也可以为每个各自的功能提供三个微前端,仪表板作为公共部分。

  • 页面

在一些应用程序中,功能按页面划分。我们可以按页面来划分应用程序,使用这种方法时,每个页面都有独立的功能。

应用程序也可以按域划分。例如,我们可以根据我们的需求将应用程序划分为核心域、支付域或配置文件域。

在网页上实现子应用程序有两种方法:

  1. 每个页面上有一个应用程序
  2. 所有的子应用程序在一个页面上

准备

由于每个微前端将被放置在特定的位置,并将有自己的API,我们需要有一个将在特定位置呈现应用程序的基础。以下是一些我们可以实现这一目标的方法:

  • Webpack module federation
  • NGINX
  • iFrames
  • Web components
  • H-include library
  • Single SPA library

在这里,我们将专注于单一SPA库,因为它有如下功能:

  1. 延迟加载代码可以改善初始加载时间
  2. 在单个页面上使用多个框架
项目结构

我们将构建三个模块,即React中的主应用、React中的子应用和Angular中的子应用。我们可以用create-react-app来创建React的main-app、sub-app,用Angular CLI来在Angular中创建子app。

开始构建

我们将不得不使用某些函数在主应用程序中注册我们的子应用程序,以便导出我们的子应用程序。幸运的是,我们不需要手动实现这些函数,因为在Angular和React中,单个SPA可以自己处理这些函数。

  1. 子应用程序中的实现:

要将一个模块导出为一个子应用程序,我们必须导出以下生命周期函数:

  • bootstrap——它将被调用一次,就在注册的应用程序第一次挂载之前。
  • mount -当注册的应用程序被挂载时,它将被调用。
  • unmount -当注册的应用程序被卸载时,这个函数将被调用。

我们还必须提供rootComponentdomElementGetter,其中rootComponent用于渲染React应用,在这种情况下,后者返回应用渲染到的DOM元素

下面是实现React应用入口文件的代码片段:

代码语言:javascript
复制
import React from 'react';
import ReactDOM from 'react-dom';
import singleSpaReact from 'single-spa-react';
import rootComponent from './App';

const reactLifecycles = singleSpaReact({
    React,
    ReactDOM,
    rootComponent,
    domElementGetter: () => document.getElementById('react-app')
});

export const bootstrap = [
    reactLifecycles.bootstrap,
];

export const mount = [
    reactLifecycles.mount,
];

export const unmount = [
    reactLifecycles.unmount,
];

我们必须在Angular文件中为single-spa-angular提供一个mainModule*(Angular根模块)、domElementGettertemplate。下面是实现Angular应用入口文件的代码片段:

代码语言:javascript
复制
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app/app.module';
import singleSpaAngular2 from 'single-spa-angular2';


const ng2Lifecycles = singleSpaAngular2({
  domElementGetter: () => document.getElementById('angular-app'),
  mainModule: AppModule,
  angularPlatform: platformBrowserDynamic(),
  template: `<app-root />`,
});

export const bootstrap = [
  ng2Lifecycles.bootstrap,
];

export const mount = [
  ng2Lifecycles.mount,
];

export const unmount = [
  ng2Lifecycles.unmount,
];

现在我们已经准备好了子应用程序,但是你必须考虑主应用程序如何找到引导、挂载和卸载函数。一旦这两个子应用程序都被执行,这些函数应该自动在一个 window.angularAppwindow.reactApp中被访问。因为我们在两个子应用程序中都使用单个SPA函数,所以子应用程序和模板都将知道使用全局名称空间的single SPA生命周期函数的位置。

问题是如何设置这些子应用的位置?

要设置子应用程序的位置,只需在Webpack配置文件中为每个子应用程序的module.exports.output对象添加两个条目。你可以在下面的代码片段中看到Angular应用的例子(你也可以对React应用做同样的事情)。按照下面的例子:

代码语言:javascript
复制
  module.exports = {
    output: {
      library: "angularApp",
      libraryTarget: "window"
    }
  };

实现主应用程序

  • 将单个SPA库添加到package.json文件。
  • 在一个SPA库中注册所有的子应用程序。

下面给出了启动SPA文件、registerReactApp和registerAngularApp的代码片段:

代码语言:javascript
复制
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as singleSpa from 'single-spa';
import {registerReactApp} from "./apps/react-app";
import {registerAngularApp} from "./apps/angular-app";

ReactDOM.render(<App/>, document.getElementById('root'));


registerReactApp();
registerAngularApp();

singleSpa.start();

使用下面的代码片段注册registerReactApp:

代码语言:javascript
复制
import * as singleSpa from "single-spa";
import {matchingPathname, runScript} from "./utils";

const loadReactApp = async () => {
    await runScript('http://localhost:3002/static/js/main.js');
    return window.reactApp;
};


export const registerReactApp = () => {
    singleSpa.registerApplication('react-app', loadReactApp, matchingPathname(['/react', '/']));
};

使用下面的代码片段注册registerAngularApp:

代码语言:javascript
复制
import * as singleSpa from "single-spa";
import {matchingPathname, runScript} from "./utils";

const loadAngularApp = async () => {
    await runScript('http://localhost:3001/inline.bundle.js');
    await runScript('http://localhost:3001/polyfills.bundle.js');
    await runScript('http://localhost:3001/styles.bundle.js');
    await runScript('http://localhost:3001/vendor.bundle.js');
    await runScript('http://localhost:3001/main.bundle.js');
    return window.angularApp;
};


export const registerAngularApp = () => {
    singleSpa.registerApplication(
        'angular-app', 
        loadAngularApp, 
        matchingPathname(['/angular', '/'])
    );
};

你一定已经注意到,子应用程序和子应用程序都将要求知道子应用程序容器的DOM元素ID。这时候你就必须考虑如何在应用程序之间实现通信系统

通信

这里的子应用程序彼此是完全独立的,但我们可以通过使用像 eev 事件总线这样的库让它们在某些事件上相互通信。eev事件总线是一个小而快速的零依赖事件发射器,它可以帮助我们在React和Angular应用之间交换信息。要了解更多关于这个发射器,请点击这里。您可以使用本机web浏览器事件机制进行通信,而且它不需要任何额外的库。

归纳

  • 在许多情况下,微前端简化了开发,它们基本上是前端微服务的实现。
  • 通过使用微前端,我们可以让它更容易理解、开发、测试和部署大型应用程序,即使是复杂的web应用程序。
  • 每个子应用程序可以在不同的堆栈上独立开发,当使用微前端时,可以由单个团队或多个团队拥有。
  • 使用这种方法有许多优点,但请记住,这应该会使您的工作变得简单。它们不适合用于小型应用程序。

总结

微前端确实很强大,许多大型组织现在都在大规模地使用它,以使开发过程更加精简。它是一个开源资源,正在不断开发,并正在探索和测试以改进它。你可以将较小的应用组合起来,使用微前端创建大型前端应用,但将其应用于所有类型的应用是不明智的。理解您的应用程序可以让你更清楚地了解实现微前端的场景,以便以最好的方式利用它们的好处。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-04-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端修罗场 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么微前端
  • 为什么需要微前端
  • 如何构建微前端
  • 准备
    • 项目结构
    • 开始构建
    • 实现主应用程序
      • 通信
      • 归纳
      • 总结
      相关产品与服务
      事件总线
      腾讯云事件总线(EventBridge)是一款安全,稳定,高效的云上事件连接器,作为流数据和事件的自动收集、处理、分发管道,通过可视化的配置,实现事件源(例如:Kafka,审计,数据库等)和目标对象(例如:CLS,SCF等)的快速连接,当前 EventBridge 已接入 100+ 云上服务,助力分布式事件驱动架构的快速构建。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档