微前端入门

最近打算改进一下现有网站的架构,微前端这个词屡次进入了个人视野。javascript

可是网上关于微前端文章老是说得似是而非,因而我找到这篇文章进行翻译。并大概理解微前端的理念。目前尚未肯定是否使用微前端架构,由于看起来业界对最佳实践并无达成一致。html

译文开始,有删节。原文连接前端


引言

把前端作好很难,让多个团队同时开发大型前端应用,就更难了。目前有一种趋势是将前端应用拆分红更小、更易于管理的小应用。这种体系结构是如何提升前端团队的效率的呢?java

本文将对这些问题进行阐述。除了讨论利弊,咱们还将介绍一些可用的例子,并深刻研究一个完整的示例应用。node


近年来,微服务已迅速普及,许多组织都使用这种体系结构样式来避免大型单体应用的局限性。尽管有不少介绍微服务的文章,但仍是有许多公司局限于单体式前端应用。react

假设你想构建一个渐进式的Web应用程序,可是你很难将新的功能实现于现有的总体应用中。好比你想开始使用新的 JS 语法(或TypeScript),可是你没法在现有的构建过程当中使用对应的构建工具。又或者,你只想扩展你的开发团队,以便多个团队能够同时处理一个产品,可是现有应用中的耦合和复杂度让每一个开发者互相掣肘。这些都是真实存在的问题,这些问题极大地下降了大型团队的开发效率。webpack

最近,咱们看到愈来愈多前端开始把注意力集中在复杂前端应用的架构上面。尤为是如何将前端总体分解,每一块能够独立开发、测试和部署,同时对用户而言还是一个总体。这种技术就是微前端,咱们将其定义为:nginx

一种将独立的前端应用组成一个更大的总体的架构风格git

固然,在软件体系结构方面没有免费的午饭。一些微型前端实现可能致使依赖关系很是重复,从而增长用户的下载量。并且,团队自治可能会致使团队分散。尽管如此,咱们认为风险是可控的,收益是高于成本的。github

微前端的优势

增量升级

对于许多团队而言,这是开始微前端之旅的首要缘由。技术债阻碍了项目的发展,只能重写。为了不彻底重写的风险,咱们更但愿 逐个替换旧的模块。

简单、解耦的代码库

每一个单独的微型前端应用的源代码都将比单个总体前端应用的源代码少得多。这些较小的代码库对于开发人员来讲更容易维护。尤为是咱们避免了组件间耦合所致使的复杂性。

独立部署

就像微服务同样,微前端的独立部署能力是关键。部署范围的减少,带来了风险的下降。每一个微前端应用都应具备本身的持续交付途径,不停地构建、测试、部署。

团队自治

每一个团队须要围绕业务功能垂直组建,而不是根据技术能力来组建。这为团队带来了更高的凝聚力。

总结

简而言之,微前端就是将大而恐怖的东西切成更小、更易于管理的部分,而后明确地代表它们之间的依赖性。咱们的技术选择,咱们的代码库,咱们的团队以及咱们的发布流程都应该可以彼此独立地操做和发展,无需过多的协调。

例子

想象一个订餐网站。从表面上看,这是一个很是简单的概念,可是若是你想作得好,会有不少使人惊讶的细节:

  • 应该有一个落地页,顾客能够浏览和搜索餐馆。这些餐厅应该能够经过许多属性进行搜索和过滤,包括价格、菜名或客户先前订购的内容
  • 每一个餐厅都须要有本身的页面,显示其菜单,并容许客户下单、选折扣和填写附加要求
  • 客户应该有我的资料页面,能够查看订单记录、自定义付款方式

每一个页面都足够复杂,从微前端的角度咱们能够把每一个页面交给一个专门的团队(译注:这些团队的人员能够重叠),而且每一个团队都应该可以独立于其余团队工做。他们应该可以开发、测试、部署和维护其代码,而没必要担忧与其余团队冲突。

集成

鉴于上面的定义至关宽松,全部有许多方法实现微前端。在本节中,咱们将显示一些示例并讨论它们的取舍之道。每一个页面都有一个容器应用,该容器能够:

  • 呈现常见的页面元素,例如页眉和页脚
  • 解决认证和导航等跨领域问题
  • 将各类微型前端应用集中到页面上,并告诉每一个微型前端什么时候以及在何处进行渲染

后端模板的集成

咱们用一个很是传统的方式开始,将多个模板渲染到服务器上的HTML里。咱们有一个index.html,其中包含全部常见的页面元素,而后使用 include 来引入其余模板:

<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Feed me</title>
  </head>
  <body>
    <h1>🍽 Feed me</h1>
    <!--# include file="$PAGE.html" -->
  </body>
</html>
复制代码

而后配置 nginx

server {
    listen 8080;
    server_name localhost;

    root /usr/share/nginx/html;
    index index.html;
    ssi on;

    # 将 / 重定向到 /browse
    rewrite ^/$ http://localhost:8080/browse redirect;

    # 根据路径访问 html 
    location /browse {
      set $PAGE 'browse';
    }
    location /order {
      set $PAGE 'order';
    }
    location /profile {
      set $PAGE 'profile'
    }

    # 全部其余路径都渲染 /index.html
    error_page 404 /index.html;
}
复制代码

这是至关标准的服务器端应用。咱们之因此能够称其为微前端,是由于咱们让每一个页面独立,可由一个独立的团队交付。

为了得到更大的独立性,能够有一个单独的服务器负责渲染和服务每一个微型前端,其中一个服务器位于前端,向其余服务器发出请求。经过缓存,能够把延迟降到最低。

这个例子说明了微前端不必定是一种新技术,也没必要太复杂。只要咱们保证代码隔离和团队自治,不管咱们采用何种技术栈,咱们均可以达到相同的效果。

package 集成

有人会用到的一种方法是将每一个微前端发布为一个 node 包,并让容器应用程序将全部微前端应用做为依赖项。好比这个 package.json:

{
  "name": "@feed-me/container",
  "version": "1.0.0",
  "description": "A food delivery web app",
  "dependencies": {
    "@feed-me/browse-restaurants": "^1.2.3",
    "@feed-me/order-food": "^4.5.6",
    "@feed-me/user-profile": "^7.8.9"
  }
}
复制代码

乍看彷佛没什么问题,这种作法会产生一个可部署的包,咱们能够轻松管理依赖项。

可是,这种方法意味着咱们必须从新编译并发布每一个微前端应用,才能发布咱们对某个应用做出的更改。咱们强烈不建议使用这种微前端方案。

经过 iframe 集成

iframe 是集成的最简单方式之一。本质上来讲,iframe 里的页面是彻底独立的,能够轻松构建。并且 iframe 还提供了不少的隔离机制。

<html>
  <head>
    <title>Feed me!</title>
  </head>
  <body>
    <h1>Welcome to Feed me!</h1>

    <iframe id="micro-frontend-container"></iframe>

    <script type="text/javascript"> const microFrontendsByRoute = { '/': 'https://browse.example.com/index.html', '/order-food': 'https://order.example.com/index.html', '/user-profile': 'https://profile.example.com/index.html', }; const iframe = document.getElementById('micro-frontend-container'); iframe.src = microFrontendsByRoute[window.location.pathname]; </script>
  </body>
</html>
复制代码

iframe 并非一项新技术,因此上面代码也许看起来并不那么使人兴奋。

可是,若是咱们从新审视先前列出的微前端的主要优点,只要咱们谨慎地划分微应用和组建团队的方式,iframe便很适合。

咱们常常看到不少人不肯意选择iframe。由于 iframe有点使人讨厌,但 iframe 实际上仍是有它的优势的。上面提到的容易隔离确实会使iframe不够灵活。它会使路由、历史记录和深层连接变得更加复杂,而且很难作成响应式页面。

使用 JS 集成

这种方式多是最灵活的一种,也是被采用频率最高的一种方法。每一个微前端都对应一个 <script> 标签,而且在加载时导出一个全局变量。而后,容器应用程序肯定应该安装哪些微应用,并调用相关函数以告知微应用什么时候以及在何处进行渲染。

<html>
  <head>
    <title>Feed me!</title>
  </head>
  <body>
    <h1>Welcome to Feed me!</h1>

    <!-- 这些脚本不会立刻渲染应用 -->
    <!-- 而是分别暴露全局变量 -->
    <script src="https://browse.example.com/bundle.js"></script>
    <script src="https://order.example.com/bundle.js"></script>
    <script src="https://profile.example.com/bundle.js"></script>

    <div id="micro-frontend-root"></div>

    <script type="text/javascript"> // 这些全局函数是上面脚本暴露的 const microFrontendsByRoute = { '/': window.renderBrowseRestaurants, '/order-food': window.renderOrderFood, '/user-profile': window.renderUserProfile, }; const renderFunction = microFrontendsByRoute[window.location.pathname]; // 渲染第一个微应用 renderFunction('micro-frontend-root'); </script>
  </body>
</html>
复制代码

上面是一个很基本的例子,演示了 JS 集成的大致思路。

与 package 集成不一样,咱们能够用不一样的bundle.js独立部署每一个应用。

与 iframe 集成不一样的是,咱们具备彻底的灵活性,你能够用 JS 控制何时下载每一个应用,以及渲染应用时额外传参数。

这种方法的灵活性和独立性使其成为最经常使用的方案。当咱们展现完整的示例时,会有更详细的探讨。

经过 Web Component 集成

这是前一种方法的变体,每一个微应用对应一个 HTML 自定义元素,供容器实例化,而不是提供全局函数。

<html>
  <head>
    <title>Feed me!</title>
  </head>
  <body>
    <h1>Welcome to Feed me!</h1>

     <!-- 这些脚本不会立刻渲染应用 -->
    <!-- 而是分别提供自定义标签 -->
    <script src="https://browse.example.com/bundle.js"></script>
    <script src="https://order.example.com/bundle.js"></script>
    <script src="https://profile.example.com/bundle.js"></script>

    <div id="micro-frontend-root"></div>

    <script type="text/javascript"> // 这些标签名是上面代码定义的 const webComponentsByRoute = { '/': 'micro-frontend-browse-restaurants', '/order-food': 'micro-frontend-order-food', '/user-profile': 'micro-frontend-user-profile', }; const webComponentType = webComponentsByRoute[window.location.pathname]; // 渲染第一个微应用(自定义标签) const root = document.getElementById('micro-frontend-root'); const webComponent = document.createElement(webComponentType); root.appendChild(webComponent); </script>
  </body>
</html>
复制代码

主要区别在于使用 Web Component 代替全局变量。若是你喜欢 Web Component 规范,那么这是一个不错的选择。若是你但愿在容器应用程序和微应用之间定义本身的接口,那么你可能更喜欢前面的示例。

样式

CSS 没有模块系统、命名空间和封装。就算有,也一般缺少浏览器支持。在微前端环境中,这些问题会更严重。

例如,若是一个团队的微前端的样式表为 h2 { color: black; },而另外一个团队的则为 h2 { color: blue; },而这两个选择器都附加在同一页面上,就会冲突!

这不是一个新问题,但因为这些选择器是由不一样的团队在不一样的时间编写的,而且代码可能分散在不一样的库中,所以更难避免。

多年来,有许多方法可让 CSS 变得更易于管理。有些人选择使用严格的命名约定,例如 BEM,以确保选择器的范围是足够小的。其余一些人则使用预处理器,例如 SASS,其选择器嵌套能够用做命名空间。一种较新的方法是经过 CSS 模块 或各类 CSS-in-JS 库,以编程的方式写 CSS。某些开发者还会使用 shadow DOM 来隔离样式。

只要你选择一种能确保开发人员的样式互不影响的方案便可。

共享组件库

上面咱们提到,视觉一致性很重要,一种解决方法是应用间共享可重用的 UI 组件库。

提及来容易,作起来难。建立这样一个库的主要好处是减小工做量。此外,你的组件库能够充当样式指南,做为开发人员和设计师之间进行协做的重要桥梁。

第一个容易出错的点,就是过早地建立了太多组件。好比你试图建立一个囊括全部常见 UI 组件的组件库。可是,经验告诉咱们,在实际使用组件以前,咱们很难猜想组件的 API 应该是什么样的,强行作组件会致使早期的混乱。所以,咱们宁愿让团队根据需求建立本身的组件,即便这最初会致使某些重复。

让 API 天然出现,一旦组件的 API 变得显而易见,就能够将重复的代码整合到共享库中。

与任何共享内部库同样,库的全部权和治理权很难分配。一种人认为,全部开发成员都拥有库的全部权,实际上这意味着没有人拥有库的全部权。若是没有明确的约定或技术远见,共享组件库很快就会成为不一致代码的大杂烩。若是取另外一个极端,即彻底集中式的开发共享库,后果就是建立组件的人与使用这些组件的人之间将存在很大的脱节。

咱们见过的最好的合做方式是,任何人均可觉得库贡献代码,可是有一个 托管者(一我的或一个团队)负责确保这些代码的质量、一致性和有效性。

维护共享库的人须要技术很强,同时沟通能力差也很强。

跨微应用通讯

关于微前端的最多见问题之一是如何让应用彼此通讯。咱们建议应该尽量少地通讯,由于这一般会引入没必要要的耦合。

不过跨应用通讯的需求仍是存在的。

  1. 使用自定义事件通讯,是下降耦合的一种好方法。不过这样作会使微应用之间的接口变得模糊。
  2. 能够考虑 React 应用中常见的机制:自上而下传递回调和数据。
  3. 第三种选择是使用地址栏做为通讯桥梁,咱们将在后面详细探讨 。

若是你使用的是 Redux,那么一般你会为整个应用建立一个全局状态。但若是每一个微应用是独立的,那么每一个微应用就都应该有本身的 Redux 和全局状态。

不管选择哪一种方法,咱们都但愿咱们的微应用经过消息或事件进行通讯,并避免任何共享状态,以免耦合。

你还应该考虑如何自动验证集成没有中断。功能测试是解法之一,可是因为实现和维护成本,咱们倾向于只作一部分功能测试。或者,你能够实施消费者驱动接口,让每一个微应用指定它对其余微应用的要求,这样你就不用实际将它们所有集成在一块儿并在浏览器中测试。

后端通信

若是咱们有独立的团队独立处理前端应用,那么后端开发又是怎样的呢?

咱们坚信全栈团队的价值,从界面代码一直到后台 API 开发,再到数据库和网站架构。

咱们推荐的模式是 Backends For Frontends 模式,其中每一个前端应用程序都有一个相应的后端,后端的目的仅仅是为了知足该前端的需求。BFF模式起初的粒度多是每一个前端平台(PC页面、手机页面等)对应一个后端应用,但最终会变为每一个微应用对应一个后端应用。

这里要说明一下,一个后端应用可能有独立业务逻辑和数据库的,也可能只是下游服务的聚合器。 若是微前端应用只有一个与之通讯的API,而且该API至关稳定,那么为它单独构建一个后台可能根本没有太大价值。指导原则是:构建微前端应用的团队没必要等待其余团队为其构建什么事物。

所以,若是一个微前端用到的新功能须要后端接口的变动,那么这一前一后两个地方就应该交给一个团队来开发。

另外一个常见的问题是,如何作身份验证和鉴权?

显然用户只须要进行一次身份验证,所以身份验证应该放在容器应用里。容器可能具备某种登陆形式,经过该登陆形式咱们能够得到某种令牌。该令牌将归容器全部,并能够在初始化时注入到每一个微前端中。最后,微前端能够将令牌发送到服务器,而后服务器进行验证。

测试

在测试方面,咱们看不到单体式前端和微前端之间的太大差别。

显而易见的差距是容器应用程序对各类微前端的集成测试。

详细的例子

接下来咱们来实现一个详细的例子。

主要介绍容器应用和微应用如何用 JavaScript 集成在一块儿,由于这多是最有趣和最复杂的部分。

你能够在 demo.microfrontends.com 上查看最终部署的结果,完整的源代码能够在 Github 上看到。

该项目使用 React.js 实现,值得一提的是 React 不是惟一选择。

容器

咱们将从 容器 开始,由于它是咱们的切入点。package.json:

{
  "name": "@micro-frontends-demo/container",
  "description": "Entry point and container for a micro frontends demo",
  "scripts": {
    "start": "PORT=3000 react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test"
  },
  "dependencies": {
    "react": "^16.4.0",
    "react-dom": "^16.4.0",
    "react-router-dom": "^4.2.2",
    "react-scripts": "^2.1.8"
  },
  "devDependencies": {
    "enzyme": "^3.3.0",
    "enzyme-adapter-react-16": "^1.1.1",
    "jest-enzyme": "^6.0.2",
    "react-app-rewire-micro-frontends": "^0.0.1",
    "react-app-rewired": "^2.1.1"
  },
  "config-overrides-path": "node_modules/react-app-rewire-micro-frontends"
}
复制代码

能够看出,这是一个用 create-react-app 建立的 React 应用。

要注意我并无把其余微应用包含到 package.json 的依赖里。

若是你想知道如何选择和展现微应用,能够看一下 App.js。咱们使用React Router 将当前URL与预约义的路由列表进行匹配,并渲染相应的组件:

<Switch>
  <Route exact path="/" component={Browse} />
  <Route exact path="/restaurant/:id" component={Restaurant} />
  <Route exact path="/random" render={Random} />
</Switch>
复制代码

Browser 和 Restaurant 组件是这样的:

const Browse = ({ history }) => (
  <MicroFrontend history={history} name="Browse" host={browseHost} />
);
const Restaurant = ({ history }) => (
  <MicroFrontend history={history} name="Restaurant" host={restaurantHost} />
);
复制代码

两个组件都渲染了一个 MicroFrontend 组件。除了 history 对象(稍后将变得很重要)以外,咱们还指定应用程序的惟一名称,以及对应的后端 host。host 的值多是 http://localhost:3001browse.demo.microfrontends.com

MicroFrontend 只是另外一个 React 组件:

class MicroFrontend extends React.Component {
  render() {
    return <main id={`${this.props.name}-container`} />; } } 复制代码

渲染时,咱们要作的只是在页面上放置一个容器元素,其ID对于微前端应用来讲是惟一的。咱们使用React componentDidMount做为下载和安装微应用的触发器:

// class MicroFrontend
  componentDidMount() {
    const { name, host } = this.props;
    const scriptId = `micro-frontend-script-${name}`;

    if (document.getElementById(scriptId)) {
      this.renderMicroFrontend();
      return;
    }

    fetch(`${host}/asset-manifest.json`)
      .then(res => res.json())
      .then(manifest => {
        const script = document.createElement('script');
        script.id = scriptId;
        script.src = `${host}${manifest['main.js']}`;
        script.onload = this.renderMicroFrontend;
        document.head.appendChild(script);
      });
  }
复制代码

必须从 manifest 文件中获取脚本的 URL,由于 react-scripts 输出的编译的 JavaScript 文件的文件名中带有哈希值以方便缓存。

设置脚本的URL后,剩下的就是将其添加到文档并初始化:

// class MicroFrontend
  renderMicroFrontend = () => {
    const { name, history } = this.props;

    window[`render${name}`](`${name}-container`, history);
    // E.g.: window.renderBrowse('browse-container', history);
  };
复制代码

最后要作的是清理工做。当 MicroFrontend 从页面中删除组件时,咱们也应该卸载相关的微应用。

componentWillUnmount() {
    const { name } = this.props;

    window[`unmount${name}`](`${name}-container`);
  }
复制代码

微前端应用

接下来介绍 window.renderBrowse 方法是怎么实现的:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

window.renderBrowse = (containerId, history) => {
  ReactDOM.render(<App history={history} />, document.getElementById(containerId)); registerServiceWorker(); }; window.unmountBrowse = containerId => { ReactDOM.unmountComponentAtNode(document.getElementById(containerId)); }; 复制代码

上面代码用到了 ReactDOM.render 和 ReactDOM.unmountComponentAtNode。

为了独立开发和运行微前端。每一个微前端应用还具备额外的 index.html,以在容器外部独立呈现:

<html lang="en">
  <head>
    <title>Restaurant order</title>
  </head>
  <body>
    <main id="container"></main>
    <script type="text/javascript">
      window.onload = () => {
        window.renderRestaurant('container');
      };
    </script>
  </body>
</html>
复制代码

从如今开始,微前端大多只是普通的 React 应用程序。'browser' 应用餐厅列表,提供 <input> 用来搜索和过滤,并用 <Link> 把结果包裹起来,用户点击时导航到一个特定的餐厅。而后,咱们将切换到第二个 'order' 微应用,展现一个带有菜单的餐厅页面。

经过路由进行跨应用程序通讯

咱们以前提到过 ,应将跨应用通讯保持在最低限度。在此示例中,咱们惟一的通讯是 browser 页面须要告诉 order 页面要加载哪一个餐厅。咱们使用路由来解决此问题。

涉及到三个 React 应用,都用React Router进行路由,可是以两种略有不一样的方式进行初始化。

对于容器应用程序,咱们建立一个,它会在内部实例化一个history对象,咱们使用该对象来处理客户端历史记录,也可使用它来将多个React Router 连接在一块儿。初始化路由的方式为

<Router history={this.props.history}>
复制代码

这个 histroy 是由容器应用提供的,全部微应用共用这个 history 对象。这使得用 url 做为消息传递方式变得十分简便。例如,咱们有一个像这样的连接:

<Link to={`/restaurant/${restaurant.id}`}>
复制代码

单击此连接后,该路径将在容器中更新,该容器将看到新的URL并肯定应该安装和呈现餐厅微应用。而后,该微应用本身的路由逻辑将从URL中提取餐厅ID。

我但愿这个示例可以显示 URL 的灵活性和强大功能。使用 URL 做为消息传递应该知足一下条件:

  • URL 的结构是开放透明的
  • URL 的访问权限是全局的
  • URL 的长度是有限的
  • 面向用户建模,URL 应该易于理解
  • 它是声明式的,而不是命令式的。即 URL 表示当前页面的位置,而不是当前页面该作什么
  • 它迫使微前端应用进行间接通讯,而不是直接依赖

当使用路由做为微前端应用之间的通讯方式时,咱们选择的路由即构成合同。合同一旦肯定,不能轻易修改,因此咱们应该进行自动化测试,以检查合同是否获得遵照。

共享内容

虽然咱们但愿每一个团队和微应用尽量独立,可是有些事情仍是会共享的。

上面提过共享组件库,可是对于这个小型应用而言,组件库会显得过大。所以,咱们有一个小 的公共内容库,其中包括图像、JSON数据和CSS,这些内容被全部其余微应用共享。

还有一个重要的东西须要共享:依赖库。重复的依赖项是微前端的一个常见缺点。即便在应用程序之间共享这些依赖也很是困难,咱们来讨论如何实现依赖库的共享。

第一步是选择要共享的依赖项。对咱们已编译代码的分析代表,大约50%的代码是由 react 和 react-dom 贡献。这两个库是咱们最核心的依赖项,所以若是把这两个库单独提取出来做为共享库,会很是有效。最后,它们是很是稳定和成熟的库,升级也很慎重,因此升级工做应该不会太困难。

至于如何提取,咱们须要作的就是在 webpack 配置中将库标记为外部库(externals):

module.exports = (config, env) => {
  config.externals = {
    react: 'React',
    'react-dom': 'ReactDOM'
  }
  return config;
};
复制代码

而后,用 script 向每一个index.html 文件添加几个标签,以从共享内容服务器中获取这两个库:

<body>
  <div id="root"></div>
  <script src="%REACT_APP_CONTENT_HOST%/react.prod-16.8.6.min.js"></script>
  <script src="%REACT_APP_CONTENT_HOST%/react-dom.prod-16.8.6.min.js"></script>
</body>
复制代码

缺点

与全部架构同样,微前端架构中也存在一些折衷。咱们获得好处的同时,也伴随着成本。

下载量

独立构建的 JavaScript 文件可能致使重复的公共依赖,从而增长用户的下载量。例如,若是每一个微应用都包括本身的 React 副本,那么用户就得屡次下载 React。

这个问题不容易解决,那能够获得缓解。首先,即便咱们不作任何优化,每一个单独页面的加载速度也有可能比构建单个总体式前端要快。缘由是若是独立地编译每一个页面,咱们就能够有效地进行代码拆分,页面只加载当前页面的依赖项。这可能会致使初始页面加载很快,但随后的导航速度变慢,由于用户被迫在每一个页面从新下载相同的依赖项。咱们能够对用户常去的页面进行分析,而后单独优化他们的依赖项。

每一个项目是不一样的,你必须针对性地进行分析。

环境差别

当微应用愈来愈多,你在本地开发时确定没法把全部微应用和对应的后端都启动起来,那么你就不得不在本地进行环境的简化。

若是开发环境和生成环境的环境是不一样的,这每每会形成问题。因此你须要保证,若是开发者想要彻底模拟生成环境,也是能够作到的。只不过会很是耗时。

治理复杂性

微前端做为一个更加分布式的体系结构,将不可避免地要管理更多的东西:更多的代码库、更多的工具、更多的构建管道、更多的服务器、更多的域名等。所以在采用这样的体系结构以前,您须要考虑几个问题:

  • 你是否有足够的自动化措施来配置和管理所需的其余基础架构?
  • 你的前端开发、测试和发布过程是否能够扩展到多个应用程序?
  • 你是否准备好了让决策变得更加分散,甚至难以控制感?
  • 你将如何确保多个独立的前端代码库的质量、一致性和或治理水平?

结论

多年来,随着前端不断变复杂,咱们看到了对更可扩展的体系结构日益增加的需求。咱们应该可以经过独立的自治团队来开发软件。

虽然微前端不是惟一的办法,但咱们已经看到了许多微前端达到这些目标的实际案例,而且随着时间的推移,咱们已经可以逐渐将这项技术应用于旧网站。不管微型前端对你和你的团队是否是正确的方法,微前端都是一种趋势,在这种趋势下,前端工程化和前端体系结构都将变得愈来愈重要。


译文完。

更多深刻阅读:

相关文章
相关标签/搜索