单体应用对比前端微服务化

普通的前端单体应用

微前端架构

1.基本概念

实现一套微前端架构,可以把其分成四部分(参考:https://alili.tech/archive/11052bf4/)

加载器:也就是微前端架构的核心,主要用来调度子应用,决定何时展示哪个子应用, 可以把它理解成电源。

包装器:有了加载器,可以把现有的应用包装,使得加载器可以使用它们,它相当于电源适配器。

主应用:一般是包含所有子应用公共部分的项目—— 它相当于电器底座

子应用:众多展示在主应用内容区的应用—— 它相当于你要使用的电器

所以是这么个概念:电源(加载器)→电源适配器(包装器)→️电器底座(主应用)→️电器(子应用)️

总的来说是这样一个流程:用户访问index.html后,浏览器运行加载器的js文件,加载器去配置文件,然后注册配置文件中配置的各个子应用后,首先加载主应用(菜单等),再通过路由判定,动态远程加载子应用。

2.预备知识

2.1 SystemJs

SystemJS提供通用的模块导入途径,支持传统模块和ES6的模块。

SystemJs有两个版本,6.x版本是在浏览器中使用的,0.21版本的是在浏览器和node环境中使用的,两者的使用方式不同。(参考:https://github.com/systemjs/systemjs)

在微服务中主要充当加载器的角色。

2.2 singleSpa

single-spa是一个在前端应用程序中将多个javascript应用集合在一起的框架。主要充当包装器的角色。(参考:https://single-spa.js.org/docs/getting-started-overview.html

3.微服务实践

3.1 创建应用

首先创建一个主应用iframe,这个主应用只需要简单的起一个服务访问静态资源即可。

用npm init初始化,创建一个index.html,简单写个hello world,安装依赖 npm i serve --s。

在package.json中的scripts中增加启动命令"serve": "serve -s -l 7000"。运行后可以看到hello world。

然后在创建3个子应用,我用的是vue-cli2.0,分别创建navbar应用(用来写路由),program1(应用1),program2(应用2)。

navbar应用中只放两个链接就好了,如图:

  

子应用program1和program2的路由都相应的加上项目名称前缀,都增加一个about路由来作为子应用的路由切换,大致如下:

3.2 改造子应用

首先包装子应用,各个子应用都需要安装依赖 npm i single-spa-vue systemjs-webpack-interop,修改入口文件main.js如下:

其中 single-spa-vue是针对vue项目的包装器,systemjs-webpack-interop是社区维护的npm库,它可以帮助您使webpack和systemjs一起正常工作。

除此之外还需要在webpack配置中的output中增加设置

3.3 修改主应用文件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<meta name="importmap-type" content="systemjs-importmap">
<script type="systemjs-importmap">
{
"imports": {
"navbar": "http://localhost:8080/app.js",
"program1": "http://localhost:8081/app.js",
"program2": "http://localhost:8082/app.js",
"single-spa": "https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.7/system/single-spa.min.js"
}
}
</script>
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.7/system/single-spa.min.js" as="script" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/system.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/amd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/named-exports.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/named-register.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/use-default.min.js"></script>
</head>
<body>
<script>
(function(){
System.import('single-spa')
.then((res)=>{
var singleSpa=res; singleSpa.registerApplication('navbar',()=>System.import('navbar'),location=>true); singleSpa.registerApplication('program1',()=>System.import('program1'),(location)=>{
return location.hash.startsWith(`#/program1`);
}); singleSpa.registerApplication('program2',()=>System.import('program2'),(location)=>{
return location.hash.startsWith(`#/program2`);
}); singleSpa.start();
})
})()
</script>
</body>
</html>
registerApplication函数包含四个参数,
appName: 注册的应用名称;
applicationOrLoadingFn:应用入口文件(必须是一个函数,返回一个函数或者一个promise);
activityFn:控制应用是否激活的函数(必须是一个纯函数,接受window.location作为参数,返回一个boolean);
customProps:在包装器生命周期函数中传递给子应用的props(应该是一个对象,可选)。
 
start函数必须在子应用加载完后才能调用。在调用之前,子应用已经加载了只是未被渲染。
 
3.4 运行项目
分别运行navbar,program1,progarm2项目,然后运行iframe项目。iframe项目运行在7000端口,其他子应用分别运行在8080,8081,8082端口。从7000端口去请求其他端口的入口文件会跨域,所以在子应用中增加跨域设置。
在子应用的webpack.dev.config.js中找到devSever配置项,增加headers:{"Access-Control-Allow-Origin":"*"}配置
然后重新运行项目即可。
 

 4.项目整合

以上只是在开发环境中使用,接下来尝试不分别启动服务,只启用一个服务来跑项目。大体思路是使用express搭建一个服务,将子应用全部打包到项目上作为静态资源访问,入口html使用ejs模板来实现项目配置,而不再写死。

4.1 使用express生成器生成项目

4.2 修改子应用打包配置

这样子应用就全部打包到express应用中作为静态资源使用了。

4.3 增加应用配置文件

将iframe的index.html的内容复制到express的入口ejs中。增加配置文件apps.config.json和apps.config.js。

apps.config.js作用就是根据apps.config.json在静态资源文件夹下生成一份新的配置文件,将配置文件中的资源名称通过正则匹配成完整的资源路径。并且监听文件变化来更新静态资源文件夹下的配置文件。

生成的配置文件

4.4根据这个生成的配置文件去修改ejs,将项目注册过程循环出来,而不再是写死的。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<meta name="importmap-type" content="systemjs-importmap">
<script type="systemjs-importmap">
{
"imports": {
<%for(var i=0;i<apps.length;i++){%>
"<%= apps[i].name %>":"<%= apps[i].server %><%=apps[i].resourceEntryUrl %>",
<%}%>
"single-spa": "https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.7/system/single-spa.min.js"
}
}
</script>
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.7/system/single-spa.min.js" as="script" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/system.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/amd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/named-exports.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/named-register.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/use-default.min.js"></script>
</head>
<body>
<script>
(function(){
Promise.all([
System.import('single-spa'),
System.import('./apps.config.json')
])
.then((res)=>{
var singleSpa=res[0];
var configs=res[1].default; configs.apps.forEach( project => {
if(project.resource.length>0){
Promise.all(project.resource.map(i=>{
return System.import(project.server+i)
})).then(function(){
singleSpa.registerApplication(project.name,()=>System.import(project.name),(location)=>{
return project.base?true:location.hash.startsWith(`#/${project.name}`);
});
})
}else{
singleSpa.registerApplication(project.name,()=>System.import(project.name),(location)=>{
return project.base?true:location.hash.startsWith(`#/${project.name}`);
});
}
}); singleSpa.start();
})
})()
</script>
</body>
</html>

实际渲染出来是

4.5 优化打包配置

因为三个子项目都用到了相同的一部分依赖,可以考虑将公用的依赖不打包进去,改为在主项目主引入来提高打包效率

修改子应用的webpack.base.config.js,增加配置项

在主应用中引入依赖

4.5 增加react应用

同样是使用webpack打包,不同是包装器不一样。其他基本上是一样的思路即可。

最终demo

转载 https://www.cnblogs.com/scdisplay/p/11648701.html#4391495

微前端框架 single-spa的更多相关文章

  1. 极致简洁的微前端框架-京东MicroApp开源了

    前言 MicroApp是一款基于类WebComponent进行渲染的微前端框架,不同于目前流行的开源框架,它从组件化的思维实现微前端,旨在降低上手难度.提升工作效率.它是目前市面上接入微前端成本最低的 ...

  2. 微前端框架single-spa初探

    前言 最近入职的一家公司采用single-spa这个微前端框架,所以自学了此框架. single-spa这个微前端框架虽然有中文文档,但是有些零散和晦涩. 所以我想在学习之余,写篇博客拉平一下这个学习 ...

  3. 微前端框架 single-spa 技术分析

    在理解微前端技术原理中我们介绍了微前端的概念和核心技术原理.本篇我们结合目前业内主流的微前端实现 single-spa 来说明在生产实践中是如何实现微前端的. single-spa 的文档略显凌乱,概 ...

  4. 微前端框架 qiankun 技术分析

    我们在single-spa 技术分析 基本实现了一个微前端框架需要具备的各种功能,但是又实现的不够彻底,遗留了很多问题需要解决.虽然官方提供了很多样例和最佳实践,但是总显得过于单薄,总给人一种&quo ...

  5. 微前端框架 之 qiankun 从入门到源码分析

    封面 简介 从 single-spa 的缺陷讲起 -> qiankun 是如何从框架层面解决 single-spa 存在的问题 -> qiankun 源码解读,带你全方位刨析 qianku ...

  6. 基于 iframe 的微前端框架 —— 擎天

    vivo 互联网前端团队- Jiang Zuohan 一.背景 VAPD是一款专为团队协作办公场景设计的项目管理工具,实践敏捷开发与持续交付,以「项目」为核心,融合需求.任务.缺陷等应用,使用敏捷迭代 ...

  7. 微前端大赏二-singlespa实践

    微前端大赏二-singlespa实践 微前端大赏二-singlespa实践 序 介绍singleSpa singleSpa核心逻辑 搭建环境 vue main react child 生命周期 结论 ...

  8. 微前端 & 微前端实践 & 微前端教程

    微前端 & 微前端实践 & 微前端教程 微前端 micro frontends https://micro-frontends.org/ https://github.com/neul ...

  9. vue-qiankun公司微前端项稳定目落地后的总结(附github仓库demo,将会持续更新)

    ️本文为博客园社区首发文章,未获授权禁止转载 大家好,我是aehyok,一个住在深圳城市的佛系码农‍♀️,如果你喜欢我的文章,可以通过点赞帮我聚集灵力️. 个人github仓库地址: https:gi ...

随机推荐

  1. (生鲜项目)05. RESTful api, 和 VUE

    第一步: 什么是 RESTful api 总结: 使用http协议作为介质, 达到客户端修改服务器端资源的目的, 服务器只需要提供指定的api接口, 客户端根据http协议中的post/get/put ...

  2. B/S开发——文件夹的上传和下载

    本人在2010年时使用swfupload为核心进行文件的批量上传的解决方案.见文章:WEB版一次选择多个文件进行批量上传(swfupload)的解决方案. 本人在2013年时使用plupload为核心 ...

  3. java 值传递、引用传递

    class Demo02 { public static void main(String[] args) { int a=1; get(a);//值传递 System.out.println(a); ...

  4. SVN 常用 下载仓库

    仓库的基本使用: 1.管理仓库的人会给你一个SVN的仓库地址,如: https://192.168.2.98:8443/svn/建筑工程健康监测系统 2.然后就下载仓库里面的所有文件 3.对仓库做增删 ...

  5. 洛谷P4380 [USACO18OPEN]Multiplayer Moo

    题目 第一问: 用广搜类似用\(floodfill\)的方法. 第二问: 暴力枚举加剪枝,对于每个连通块,枚举跟这个连通块相连的其他与他颜色不同的连通块,然后向外扩展合并颜色与他们俩相同的连通块.扩展 ...

  6. 「HNOI2016」序列

    传送门 Description 有 \(q\) 个询问,每个询问给定两个数\(l\) 和\(r\),求 \(a[l:r]\) 的不同子序列的最小值之和 Solution  校内模拟赛用了这道题,但是莫 ...

  7. html5 css3 背景视频循环播放代码

    <div style ="position: absolute; z-index: -1; top: 0px; left: 0px; bottom: 0px; right: 0px; ...

  8. python项目总结--学生选课

    题目要求: 根据业务需求,现要对慕课学院(1)班的所有学员进行选修课程分配,使得每一名学生都可以选修到一门课程.具体要求如下: 1.自定义学生信息.课程信息.教师信息三者的具体描述 2.自定义exam ...

  9. 实验与作业(Python)-03 Python程序实例解析(函数、循环、range、turtle)

    截止日期: 要求: 下周实验课前上交,做好后在实验课上检查可获取平时分. 做出进阶或选做的的请用清晰的标致标识出来,方便老师批改 本次作业:可提交也可不提交.作业算平时成绩. 本次作业内容量较大,请组 ...

  10. javacpp, javacv: 封装了FFmpeg、OpenCV等计算机视觉编程人员常用库的接口

    jvavacpp:     一个java调用jni的库,支持安卓. javacv:      封装了FFmpeg.OpenCV等计算机视觉编程人员常用库的接口,可以通过其中的Utility类方便的在包 ...