微前端-技术调研
微前端是近两年比较火热的话题,从国外的 single-spa 到阿里的 qiankun,从京东的 micro-app 到欢聚时代的 emp ,各家大厂使尽浑身解数推出自家的微前端框架,那么微前端到底是什么呢
什么是微前端
网上看到一句话对其总结的鞭辟入里
“微前端是一种架构风格,其中众多独立交付的前端应用组合成一个大型整体。”
微前端的概念最早在 2016 年底被提出,微前端不是单纯的前端框架或者工具,而是一套架构体系,它将微服务的概念扩展到前端世界。在该技术架构下,新的/改造好之后的前端应用可由多个子应用构成,这些子应用间独立开发、独立部署、独立运行时、技术栈无关
微前端有如下特性:
技术栈无关
独立开发/部署
增量升级
既然微前端这么好,为什么直到 16 年才被提出来呢
其实早在上古时代,iframe
就可称为微前端,为什么这么说呢,因为iframe
可以做到完美隔离 javascript/css ,并且可适用 url 快速接入。那既然这么简单,为啥没有流行起来呢(在微前端领域)?因为iframe
缺点同样明显:隔离过于简单粗暴,导致应用间数据交互困难;整个应用全量加载,性能较差;弹窗类业务无法正常施展。。。
为什么要做微前端
微前端既可将多个应用/项目整合到一起,又可减小各应用间的耦合性,提高项目的可扩展性
实现微前端有哪些方案
从集成方式出发可以大致分为构建时集成、运行时集成
构建时集成
最常见的是将子应用独立开发为一个单独的可发布的 Javascript 包,在主应用中引用并加载。但是,这种方法意味着我们必须重新编译并发布每个微前端,才能发布对产品任何单个部分的更改
运行时集成
和构建时集成相反,在运行时动态加载各应用
最简单的事通过 nginx 来分发
<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>
server {
listen 8080;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
ssi on;
# Redirect / to /browse
rewrite ^/$ http://localhost:8080/browse redirect;
# Decide which HTML fragment to insert based on the URL
location /browse {
set $PAGE 'browse';
}
location /order {
set $PAGE 'order';
}
location /profile {
set $PAGE 'profile'
}
# All locations should render through index.html
error_page 404 /index.html;
}
这种方式也可勉强称为微前端,因为我们将每个业务都拆分到一个独立的应用中,可以交由独立的团队维护。除了这种服务端集成,在客户端也可以通过一定的手段拆分-集成
<html>
<head>
<title>Feed me!</title>
</head>
<body>
<h1>Welcome to Feed me!</h1>
<!-- These scripts don't render anything immediately -->
<!-- Instead they attach entry-point functions to `window` -->
<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">
// These global functions are attached to window by the above scripts
const microFrontendsByRoute = {
"/": window.renderBrowseRestaurants,
"/order-food": window.renderOrderFood,
"/user-profile": window.renderUserProfile,
};
const renderFunction = microFrontendsByRoute[window.location.pathname];
// Having determined the entry-point function, we now call it,
// giving it the ID of the element where it should render itself
renderFunction("micro-frontend-root");
</script>
</body>
</html>
在这里,我们将每个应用打包成一个 javascript 文件,在匹配到 URL 后执行对应的代码,渲染页面。
除了使用 javascript ,还可使用开篇提到的 iframe 集成,但 iframe 缺点过于明显就不讨论。此外,还可使用 web components 来实现,其也属于 javascript 因此不另列
<html>
<head>
<title>Feed me!</title>
</head>
<body>
<h1>Welcome to Feed me!</h1>
<!-- These scripts don't render anything immediately -->
<!-- Instead they each define a custom element type -->
<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">
// These element types are defined by the above scripts
const webComponentsByRoute = {
"/": "micro-frontend-browse-restaurants",
"/order-food": "micro-frontend-order-food",
"/user-profile": "micro-frontend-user-profile",
};
const webComponentType = webComponentsByRoute[window.location.pathname];
// Having determined the right web component custom element type,
// we now create an instance of it and attach it to the document
const root = document.getElementById("micro-frontend-root");
const webComponent = document.createElement(webComponentType);
root.appendChild(webComponent);
</script>
</body>
</html>
除了这两种分类,还可从拆分粒度来分类
基于路由分发
上面介绍的基本都是一个页面一个应用,那么还有没有粒度更细一点的:想在一个页面加载多个应用?🤔
前端微服务化
每个前端应用都是独立的、自主运行的,最后通过模块化的方式组合出完整的前端应用
比如借助上面的 Web Components 实现
<html>
<head>
<title>Feed me!</title>
</head>
<body>
<h1>Welcome to Feed me!</h1>
<!-- These scripts don't render anything immediately -->
<!-- Instead they each define a custom element type -->
<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">
<micro-frontend-browse-restaurants />
<micro-frontend-order-food />
<micro-frontend-user-profile />
</div>
</body>
</html>
在这里,我们加载的 js 资源可以是任何借助框架构建后生成的 web component 组件文件
总结
微前端是一种架构风格,其中众多独立交付的前端应用组合成一个大型整体。
微前端技术方案可分为运行时集成/构建时集成,或者按照拆分粒度划分为路由分发式和微服务化