Single-spa

一、single-spa 框架概述

1. Single-spa 是一种组织微前端路由的方案,每个微前端应用都是浏览器中的一个JS模块
2. Single-spa 通过劫持路由的方式来做子应用之间的切换,但接入方式需要融合自身的路由,有一定的局限性
3. Single-spa 为我们提供了基座化的微前端方案,将应用分为两类,基座应用和子应用
  • 基座应用: 会维护一个注册表-每个路由对应一个子应用,基座应用启动之后,当我们切换路由,如果是新的子应用,会动态获取子应用的js脚本,然后执行脚本并渲染出相应的页面; 如果是曾经访问过的页面,那么会从基座应用的缓存中获取已经缓存的子应用,激活子应用并渲染出对应的页面

子应用可以独立构建,运行时动态加载和主应用完全解耦,技术栈无关,靠的是协议接入(子应用必须导出boostrap、mount、unmount方法)

二、single-spa app 的主要组成部分

2.1 Configuring single-spa 用于启动子应用的基座配置文件,主要组成部分包括

1. 所有微前端应用共享的根HTML页面
2. 调用 singleSpa.registerApplication()注册子应用

// single-spa-config.js
import {registerApplication, start} from 'single-spa'


// 创建script标签将js脚本添加到当前上下文中
function createScript(url) {
	return new Promise((resolve, reject) => {
		const script = document.createElement('script');
		script.src = url;
		script.onload = resolve;
		script.onerror = reject;
		document.head.appendChild(script);
	})
}

// 异步加载子应用
fucntion loadApp(url, globalVar) {
	return async () => {
		await createScript(`${url}/js/chunk-vendors.js`);
		await createScript(`${url}/js/app.js`);
		return window[globalVar]
	}
}

// 注册子应用
registerApplication({
	name: 'app1',
	app: loadApp('http://localhost:8801', 'app1'),
	activeWhen: location => location.pathname.startsWith('/app1'),
	customProps: {
		name: 'micro app1'
	},
	// customProps: (name, loaction) => ({
		// name: 'micro app1',
	// })
})

注册配置参数:

  • name: 应用名称
  • app: 加载函数(loading funtion), 必须返回promise(resolve 之后的结果必须是一个可以解析的应用), 会在应用第一次被下载时调用
  • activeWhen: 激活函数(activity function), window.location 作为这个函数的第一个参数被调用,当函数的返回值是一个truth时应用会被激活,activity function 回根据window.location.path来决定该应用是否需要被激活, 在下面几种情况下,single-spa将会调用每个应用的活动函数
    • haschange 或者 popstate 事件触发时
    • pushstate 或者 replaceState 被调用时
    • 在single-spa上手动调用 triggerAppchange 的方法
    • checkActivityFunction 方法被调用时
  • customProps: 自定义属性, 这个参数的内容会被传递给子应用的生命周期函数中, 可以时一个对象,也可以时一个返回Object的函数,当时返回Object 的函数时,函数的参数是,name 和 location

3. 调用 singleSpa.start() 挂载子应用

  • 在start 方法被调用之前,应用会先被下载,但是不会初始化/挂载/卸载,只有调用start方法,应用才会被真正挂载

2.2 Single-spa Application: 子应用,除了在single-spa application 中没有html页面之外,其余特征和我们平时的单页应用是一样的。并且这些子应用可以使用不同的框架。

  • 子应用被注册之后只用维护自己的客户端路由,只用自己需要的框架或者类库
  • 可以通过Activity function来判断子应用是否已经被挂载了
  • 子应用在未挂载之前会一直处于休眠状态

2.2.1 注册应用的生命周期

  1. load: 下载, 注册的应用会被基座应用懒加载,注册应用在activity function 第一次返回truth 的时候,会执行下载。
    • 在下载的过程中要尽量较少各种操作的执行,可以在boostrap 生命周期再执行各项操作
    • 确实有需要执行的操作时,可以将代码放到子应用的入口文件中执行
  2. boostrap: 初始化,获取静态资源, 会在应用第一次挂载前执行一次
  3. mount: 当应用根据activity function 返回的truth 时,但是应用处于未挂载状态时,这个生命周期会被调用,调用时,函数会根据URL 来确定当前被激活的路由,创建DOM元素,监听dom事件等以向用户呈现渲染的内容。
    • 任何子路由的改变(haschange/popstate等)都不回再次出发mount,需要各应用自行处理
  4. unmount: 卸载应用,当activity function 返回false,但是该应用已经挂载时,卸载的生命周期函数旧会被调用。
    • unmount 被调用时,会清理在挂载应用时被创建的DOM元素、事件舰艇、内存、全局变量和消息订阅等
  5. unload: 移除应用
    • 移除的目的是,各应用在移除之前执行部分逻辑,一旦应用被一处,它的状态将会变成NOT_LOADED,下次激活是会被重新初始化
    • 移除函数的设计动机是对所有注册的应用实现热下载。不过在其他场景中也非常有用(如想重新初始化一个应用,且在重新初始化之前执行一些逻辑)
  6. 全局超时配置: 默认情况下,所有注册的应用遵循全局超时配置,但对于每个应用,也可以通过在主入口文件导出一个timeouts对象来重新定义
export function bootstarp(props) { ... }
export function mount(props) { ... }
export function unmount(props) { ... }

export const timeouts = {
	bootstrap: {
		millis: 5000, // 最终控制台输出警告的毫秒数
		dieOnTimeout: true,
		warningMillis: 2500, // 将警告打印到控制台的毫秒数
	},
	mount: {
		millis: 5000,
		dieOnTimeout: false,
		warningMillis: 2500,
	},
	unmount: {
		millis: 5000,
		dieOnTimeout: false,
		warningMillis: 2500,
	},
	unload: {
		millis: 5000,
		dieOnTimeout: false,
		warningMillis: 2500,
	}
}

四、 Parcel

Parcel 是 single-spa 的一个高级特性。指一个与框架无关的组件,封装一系列的功能,可以被应用手动卸载

  1. parcel 和注册应用的api一致,区别在于,parcel 需要手动挂载, 而不是通过activity function 激活
  2. 一个 parcel 可以大到一个应用,也可以小刀一个组件,可以用任何语言实现,只要最后能导出正确的生命周期时间即可
  3. 如果我们只使用了一种框架,建议使用框架组件(React, vue, angular),而不是parcel 共享功能
  4. parcel 比起框架组件中间多包裹了一层中间层,而框架组件在应用之间调用起来更容易,可以通过import语法直接导入

只有在涉及到跨框架的应用之间进行组件调用时才需要考虑parcel

// parcel 实现
const parcelConfig = {
	bootstrap() {
		// 初始化
		retrun Promise.resolve()
	},
	mount() {
		// 使用某个框架来创建和初始化dom
		return Promise.resolve()
	},
	unmount() {
		// 使用某个框架来卸载dom,进去其他的清理工作
		return Promise.resolve()
	}
}

// 挂载parcel
const domElement = document.getElementById('parcel-in-dom-to-mount-parcel');
const parcelProps = {domElement, customProps1: 'foo'};
const parcel = singleSpa.mountRootParcel(parcelConfig, parcelProps);

// parcel 被挂载之后在mountPromise 中结束挂载
parcel.mountPromise.then(() => {
	console.log(('finished mounting parcel');
	// 如果想重新渲染parcel,可以调用update生命周期方法,其返回值是一个promise
	parcelProps.customProp1 = 'bar';
	return parcel.update(parcelProps);
})
.then(() => {
	// 此处调用unmount生命周期方法来卸载parcel,返回一个promise
	 return parcel.unmount()
})

4.1 parcel 生命周期
  1. Bootstrap: 初始化, 在parcel第一次挂载时调用一次
  2. Mount: 挂载,在mountParcel方法被调用且parcel未挂载时触发,一般会创建DOM元素、初始化事件监听等,从而为用户展示内容
  3. Unmount: 卸载, parcel 已被卸载并且满足 unmount()被调用 + 父parcel或者父应用 被卸载时触发,被调用时这个方法会清除dom元素、dom事件监听,亲历内存泄漏,全局变量,事件订阅等在挂载parcel时创建的内容
  4. Update: 触发更新生命周期函数

五、single-spa 优势

  1. 能支持大部分主流的前端框架,也能支持传统的前端框架
  2. 提供更好的用户体验,不需要页面跳转,直接在当前页面载入
  3. 方便迁移旧的遗留系统

六、 single-spa 缺陷

  1. 系统构建复杂,应用需要集成在一起进行构建
  2. 不支持不同应用的部署分离
  3. 代码结构复杂
  4. 学习成本高

七、single-spa 遗留了哪些问题?

single-spa 实现了路由切换时,对子应用的加载、卸载,但是single-spa 没有解决资源加载、沙箱、全局状态管理的问题,qiankun 基于single-spa进行封装,完善了这些问题

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作为一个AI语言模型,我无法像人类一样编写代码。但是我可以为您提供single-spa的应用的基本理解和示例。 Single-spa是一个前端微服务框架,它允许您在同一个页面上使用多个JavaScript框架,例如React、Angular和Vue等。它提供了一个统一的入口点,负责管理不同的应用程序,从而使多个应用程序之间的通信更轻松。 下面是一个简单的single-spa应用示例,它使用React和Vue框架: 1. 首先,您需要使用npm安装single-spa: npm install single-spa --save 2. 然后,创建一个React应用程序: import React from 'react'; import ReactDOM from 'react-dom'; class ReactApp extends React.Component { render() { return ( <div> <h1>React App</h1> <p>Hello, World!</p> </div> ); } } ReactDOM.render(<ReactApp />, document.getElementById('react-app')); 3. 接下来,创建一个Vue应用程序: import Vue from 'vue'; import App from './App.vue'; new Vue({ el: '#vue-app', render: h => h(App) }); 4. 最后,在单一页面应用程序中使用这两个应用程序: import { registerApplication, start } from 'single-spa'; registerApplication( 'react-app', () => import('./react-app'), () => location.pathname === '/react' ); registerApplication( 'vue-app', () => import('./vue-app'), () => location.pathname === '/vue' ); start(); 这将在页面上注册两个应用程序:一个React应用程序和一个Vue应用程序。它使用location.pathname来检查当前路径是否与每个应用程序的路径匹配。如果是,则加载相应的应用程序。 如果您想了解更多关于single-spa的信息,请访问官方网站:https://single-spa.js.org/

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值