背景:
此前接手了一个老我的项目(3、4年前开始的一个我的项目),面临的一个最大的问题是老旧代码的保护和迭代。保护老旧代码的可选形式并不多:
- 推倒重来,全副进行重构 => 工作量沉重,老本极高
- 按照旧有技术选型进行保护和迭代 => emmmm,一言难尽
- 对于迭代需要采纳新的技术架构和选型,与已有性能解耦,尽量减少对旧代码的依赖和旧逻辑的批改
出于工作量和我的项目后续的可维护性和迭代性相对而言第3种计划比拟可行。因而调研了一下微前端计划来进行革新。
调研:
微前端入门
每日优鲜微前端革新
Alibaba-console-os VS Single-Spa
Alibaba-console-os
接入办法
- main.js 导出Vue做如下革新
import App from './App.vue' import { mount } from '@alicloud/console-os-vue-portal' export default mount({ el: '#app', render: h => h(App) })
- vue.config.js 做如下配置,减少 consoleOs插件,并设定相应id
module.exports = { publicPath: 'http://localhost:8080/', "pluginOptions": { "consoleOs": { "id": "os-example-vue" } } }
- 在 Host App中通过manifest.json文件引入相应子利用
import { start } from "@alicloud/console-os-kernal"; import Application from "@alicloud/console-os-react-app"; function App() { return ( <div className="App"> <div className="vue"> <Application id="os-example-vue" manifest="http://localhost:8080/os-example-vue.manifest.json"/> </div> </div> ); }
Single-Spa
Ref: https://www.jianshu.com/p/c0f4b837dbea
Demo
- https://github.com/single-spa/single-spa
- https://juejin.im/post/5d3925615188257f3850de5a
接入办法
- main.js vue导出文件做如下革新
import Vue from 'vue'; import singleSpaVue from 'single-spa-vue'; import Hello from './main.vue' const vueLifecycles = singleSpaVue({ Vue, appOptions: { el: '#vue', render: r => r(Hello) } }); export const bootstrap = [ vueLifecycles.bootstrap, ]; export const mount = [ vueLifecycles.mount, ]; export const unmount = [ vueLifecycles.unmount, ];
- single-spa.config.js 注册利用
import { registerApplication, start } from 'single-spa' registerApplication( 'vue', () => import('./src/vue/main.js'), () => location.pathname === "/react" ? false : true); start();
- index.html 配置
<html> <head></head> <body> <div id="react"></div> <div id="vue"></div> <script src="/dist/single-spa.config.js"></script> </body> </html>
- webpack配置
module.exports = { entry: { 'single-spa.config': './single-spa.config.js', }, }
Alibaba-console-os | SingleSpa | |
---|---|---|
子利用技术栈 | React、Vue、Angular | React、Vue、Angular |
主利用技术栈 | React、Angular | 不限 |
子利用资源配置模式 | manifest.json | single-spa.config.js |
抉择SingleSpa的起因
- Alibaba-console-os 的Host App不反对Vue,咱们团队的主技术栈是Vue
- Alibaba-console-os子利用资源配置通过manifest.json引入,不实用咱们公司的资源部署形式
Single-Spa实际:
架构
- 加载器:用来调度子利用,决定何时展现哪个子利用。
- 包装器:对现有的利用包装,使得加载器能够应用它们
- 主利用:个别是蕴含所有子利用公共局部的我的项目,
- 子利用:各个展现在主利用内容区的利用
大略是这样一个流程:用户拜访页面,浏览器运行加载器的js文件,加载器去获取配置文件,并注册配置文件中的各个子利用,首先加载主利用(比方菜单导航等),而后通过路由断定去动静加载子利用。
接入流程
- 创立子利用,将admin工程拆分为edu-nav(菜单导航工程)、-old(原有业务性能工程)、edu-mis(新业务性能工程)
革新子利用,通过singleSpa对子利用进行包装。须要引入single-spa-vue以及systemjs-webpack-interop。
- single-spa-vue是针对vue我的项目的包装器,包导出4个生命周期函数:bootstrap、mount、unmount、update。
- systemjs-webpack-interop能够使webpack和systemjs一起失常工作
创立主利用,充当加载器的性能,有以下几个工作。
- 配置资源map,用于后续资源SystemJs引入
- 通过SystemJs引入资源文件
- 挂载Publisher,用于子利用之间的通信。
- registerApplication注册子利用,参数顺次为:注册的子利用名称、子利用入口文件(须要是一个函数)、管制利用是否激活的函数。
- singleSpa.start。启动函数。
- 配置资源map,用于后续资源SystemJs引入
通过上述步骤,整个工程singleSpa革新实现。
实际中发现的一些问题
- 须要思考隔离js,防止css抵触,并思考按需加载资源
- 专用数据信息的同步:菜单或业务线的切换产生时会通过Publisher进行告诉,然而在切换业务线后再从子利用A切换到子利用B时会呈现子利用B未曾接管到Publisher业务线切换音讯,导致业务线不精确。因而,须要在菜单工程中非凡解决,对路由进行拦挡判断,并再次进行音讯告诉。
- 要分外留神在原型上挂载一些全局变量或全局函数的行为,容易被后者笼罩。