微前端大赏二-singlespa实践

介绍singleSpa

singleSpa是一个javascript库
它可以让很多小页面、小的组件、不通架构的前端组件在一个页面应用程序中共存。

这里有一个演示: (https://single-spa.surge.sh/)

这个库可以让你的应用可以使用多个不同的技术栈(vue、react、angular等等),这样我们就可以做同步开发,最后再使用一个公用的路由即可实现路由完美切换。也可以使用一样的技术栈,分不同的团队进行开发,只需要最后使用这个库把它们整合在一起,设置不用的路由名称就可以了。

优点:

  • 敏捷
    独立开发和更快的部署周期: 开发团队可以选择自己的技术并及时更新技术栈。 一旦完成其中一项就可以部署,而不必等待所有事情完毕。

  • 风险下降
    降低错误和回归问题的风险,相互之间的依赖性急剧下降。

  • 更小单元
    更简单快捷的测试,每一个小的变化不必再触碰整个应用程序。

  • 持续交付
    更快交付客户价值,有助于持续集成、持续部署以及持续交付。

缺点:

  • 配置复杂
    singlespa相对来说配置复杂,当然我们还有更简单一点的qiankun,也可以基于singlespa封装一套更适合自己的框架。
  • 一定的资源浪费
    由于核心逻辑还是在于请求manifest,拿到js文件后执行渲染,这个过程不可避免会产生一些冗余,对于C端的应用来说,这个问题比较致命,当然,对于B端来说,这个是可以接受的,在可控制的范围之内

singleSpa核心逻辑

几张图可以解决singleSpa的核心逻辑

第一张图,很显然,第一步,在我们的webpack应用里生成一个manifest.json文件,这个文件内容差不多如下:

{
"files": {
"static/js/0.chunk.js": "/static/js/0.chunk.js",
"static/js/0.chunk.js.map": "/static/js/0.chunk.js.map",
"static/js/1.chunk.js": "/static/js/1.chunk.js",
"static/js/1.chunk.js.map": "/static/js/1.chunk.js.map",
"main.js": "/static/js/main.chunk.js",
"main.js.map": "/static/js/main.chunk.js.map",
"runtime-main.js": "/static/js/bundle.js",
"runtime-main.js.map": "/static/js/bundle.js.map",
"index.html": "/index.html",
"static/media/logo.svg": "/static/media/logo.103b5fa1.svg"
},
"entrypoints": [
"static/js/bundle.js",
"static/js/0.chunk.js",
"static/js/main.chunk.js"
]
}

关键点在 entrypoints 这个属性,我们可以通过manifest拿到项目的依赖表并可以使用script标签动态加载出来,这个时候我们就可以实现动态加载不同的微前端应用了。

第二张图,我画出了更加具体的,singlespa在渲染过程中的核心逻辑
1、 首先我们有 main(主app) child(子app),主app只有一个,子app可以有多个
2、 其次,主app上一般我们可以在index.html里面,写多几个空间,也就是多几个div
例如:

<div id=”react-app”></div>
<div id=”vue-app”></div>

3、然后,在我们的child上,我们要用webpack插件,生成一个带有所有需要加载的依赖文件的manifest.json
4、主应用去加载这个manifest.json,获取到具体的js,使用script标签把它放到主应用上,进行渲染

至此我们就可以完全搞清楚,为什么singlespa这么神奇了,接下来让我们搭建一个简易版的singlespa

搭建环境

vue main

由于我们需要使用webpack配置,而最新版本的vue-cli默认只有babel,我们用这个步骤来安装一个vue版本的main
1、装包

 npm install @vue/cli @vue/cli-init  -g

2、创建一个项目

vue init webpack demo-single

3、cd demo-single

4、装包

npm i single-spa single-spa-vue axios --save

5、在src目录创建一个singlespa配置文件 single-spa-config.js

    // single-spa-config.js
import * as singleSpa from 'single-spa'; //导入single-spa
import axios from 'axios' /*
runScript:
一个promise同步方法。可以代替创建一个script标签,然后加载服务
*/
const runScript = async (url) => {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = url;
script.onload = resolve;
script.onerror = reject;
const firstScript = document.getElementsByTagName('script')[0];
firstScript.parentNode.insertBefore(script, firstScript);
});
}; const getManifest = (url, bundle) => new Promise(async (resolve) => {
const { data } = await axios.get(url);
// eslint-disable-next-line no-console
const { entrypoints } = data; for (let i = 0; i < entrypoints.length; i++) {
await runScript('http://127.0.0.1:3000/' + entrypoints[i]).then(() => {
if (i === entrypoints.length - 1) {
resolve()
}
})
}
}); singleSpa.registerApplication( //注册微前端服务
'singleDemoVue', async () => {
let singleVue = null;
await getManifest('http://127.0.0.1:3000/asset-manifest.json').then(() => {
singleVue = window.singleReact;
});
return singleVue;
},
location => location.pathname.startsWith('/react') // 配置前缀
); singleSpa.start(); // 启动

注: 可以看到,runScript就是个创建script标签的方法,getManifest是一个简单的获取manifest并创建script的方法

6、在main.js里引入这个文件

import './single-spa-config'

7、运行

npm run dev

最终得到这样一个工程

这样我们就完成了一个入口的配置,当然它还很简单,更复杂的操作我们应该放在具体的工程上去做

react child

上面的代码可以看到,我们register了一个react应用 http://127.0.0.1:3000/asset-manifest.json 并且访问了它的manifest文件,现在我们需要创建一个react子应用,也是直接通过几个步骤来完成,我们使用create-react-app来快速搭建:

1、装包

npm install create-react-app -g

2、创建

npx create-react-app my-app

3、创建完成后,注意我们需要对webpack做一点修改,默认create-react-app会有一个git本地分支,让我们先提交到本地仓库一下

git status
git add ./
git commit -m ttt

4、拿到webpack配置文件,create-react-app默认隐藏了webpack配置文件

yarn eject 或 npm run eject

5、修改webpack文件
修改 /config/webpack.config.js 在output增加:

output: {
... 这里忽略了原有的
library: 'singleReact',
libraryTarget: 'window'
}

修改 /scripts/start.js文件,在const devServer = new ...这个地方,增加一个header的设置:

const devServer = new WebpackDevServer(compiler, {
...serverConfig,
// 这里上增加的header设置
headers: {
'Access-Control-Allow-Origin': '*',
} });

6、修改src/index.js
一个是要把root改为动态渲染,一个是注册生命周期

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import singleSpaReact, {SingleSpaContext} from 'single-spa-react'; const rootComponent = () => {
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>
,
document.getElementById('react-root')
);
} // ReactDOM.render(
// ,
// document.getElementById('root')
// ); const reactLifecycles = singleSpaReact({
React,
ReactDOM,
rootComponent,
errorBoundary(err, info, props) {
// https://reactjs.org/docs/error-boundaries.html
console.error(err)
return (
<div>This renders when a catastrophic error occurs</div>
);
},
});
export const bootstrap = reactLifecycles.bootstrap;
export const mount = reactLifecycles.mount;
export const unmount = reactLifecycles.unmount; // If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

7、运行
npm run start

8、在main的vue那里,访问/react 你会看到下面有一个react渲染和vue的一起出现,大功告成

生命周期

生命周期函数共有4个:bootstrap、mount、unmount、update。生命周期可以传入 返回Promise的函数也可以传入 返回Promise函数的数组。
引用一个大佬完整的说明, 非常的详细:
https://github.com/YataoZhang/my-single-spa/issues/4

结论

single spa可以给我们提供一整套方案,去搭建一套微前端集成框架,但它并不是一个开箱即用的封装,它有很多的坑等着我们去踩。
一般情况下,我们选择使用qiankun,它的封装程度更好,api更加友好一些。待积攒足够多的使用经验,可以考虑自研一套自己的微前端框架,增加整体的前端研发效率。
下节我将给大家带来qiankun对singlespa的封装,在具体应用中的实践。待完结框架篇后,我们可以再深入探究singlespa的实现原理以及各种概念。

参考文章

single-spa 文档: https://single-spa.js.org/docs/getting-started-overview/

微前端 single-spa: https://juejin.cn/post/6844903896884707342

这可能是你见过最完善的微前端解决方案!: https://www.infoq.cn/article/o6GxRD9iHQOplKICiDDU

single-spa微前端: http://www.soulapp.tech/2019/09/25/single-spa微前端/

Single-Spa + Vue Cli 微前端落地指南 (项目隔离远程加载,自动引入) : https://juejin.cn/post/6844904025565954055

微前端大赏二-singlespa实践的更多相关文章

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

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

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

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

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

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

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

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

  5. vivo 商品中台的可视化微前端实践

    一.背景 在电商领域内,商品是一个重要组成部分,与其对应的商品管理系统,则负责商品的新建.编辑.复制等功能.随着商品管理系统的成熟稳定和业务上的扩展需求,催化出了商品中台的诞生.它可以将现有商品功能最 ...

  6. 基于微前端qiankun的多页签缓存方案实践

    作者:vivo 互联网前端团队- Tang Xiao 本文梳理了基于阿里开源微前端框架qiankun,实现多页签及子应用缓存的方案,同时还类比了多个不同方案之间的区别及优劣势,为使用微前端进行多页签开 ...

  7. 前端微服务初试(singleSpa)

    1.基本概念 实现一套微前端架构,可以把其分成四部分(参考:https://alili.tech/archive/11052bf4/) 加载器:也就是微前端架构的核心,主要用来调度子应用,决定何时展示 ...

  8. 微前端框架 single-spa

    单体应用对比前端微服务化 普通的前端单体应用 微前端架构 1.基本概念 实现一套微前端架构,可以把其分成四部分(参考:https://alili.tech/archive/11052bf4/) 加载器 ...

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

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

随机推荐

  1. 快速傅里叶变换学习笔记(FFT)

    什么是FFT FFT是用来快速计算两个多项式相乘的一种算法. 如果我们暴力计算两个多项式相乘,复杂度必然是\(O(n^2)\)的,而FFT可以将复杂度降至\(O(nlogn)\) 如何FFT 要学习F ...

  2. ZOJ 1006 Do the Untwish

    Do the Untwish 题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1006 题意:给定密文按公式解密 注 ...

  3. Java入门(4)

    阅读书目:Java入门经典(第7版) 作者:罗格斯·卡登海德 面向对象编程(OOP)将程序视为对象的集合,确定程序要完成的任务,然后将这些任务指派给最适合完成它们的对象.换言之,计算机程序是一组对象, ...

  4. STM32CubeIDE下载安装-GPIO基本配置操作-Debug调试(基于CMSIS DAP Debug)

    1.在ST官网下载STM32CubeIDE而不是STM32CubeMX,并且STM32CubeIDE是免费的.(STM32CubeIDE不支持中文路径,不然编译会出错) 2.如果你用的是keil开发环 ...

  5. How to Convert and Import VHD to VMDK (VMWare)

    VHD or Virtual Hard Disk is the disk image format used by Microsoft virtualization software such as ...

  6. ubuntu下安装RabbitMQ

    ubuntu下安装RabbitMQ 安装erlang 由于rabbitMq需要erlang语言的支持,在安装rabbitMq之前需要安装erlang sudo apt-get install erla ...

  7. 不断要求用户输入学生姓名,输入q结束.

    while (true) { Console.WriteLine("请输入学生姓名"); string a = Console.ReadLine(); if (a == " ...

  8. ubuntu下安装nginx -php

    mysql : sudo apt-get install mysql-server mysql-client nginx: sudo apt-get install nginx安装Nginx稳定版本 ...

  9. 【故障公告】Memcached 的“惹祸”,不知在为谁背锅

    在 .NET 5.0 背锅 . Memcached 的惹祸 .缓存雪崩之后,我们没有找到问题的真正原因,我们知道没有找到根源的故障总是会再次光临的,不是在这周就是在下周,也许就在双11前后. 就在今天 ...

  10. 比特魔方原创,用十分钟在Cocos-BCX上发行了自己的NFT

    比特魔方原创 作者 | 第二个区块 出品 |比特魔方 NFT正在积累越来越多的共识.每看到人们讨论NFT,我隐约就能联想到2019年人们谈论DeFi的时候.隐约让我感到欠缺的是,相对2019年的DeF ...