@hollysys-mirco-front-end/framework
v0.0.33
Published
微前端基座,负责管理微前端各个应用
Downloads
2
Maintainers
Readme
前言
由于项目未来的需要,最近在构思一个服务于前端的“微服务”架构,即微前端.
说到这里,可能有人要卧槽,一个微服务就够折腾了,怎么前端也要 "微服务" 化,放在一起开发不香吗?
考虑一下,如果你的系统是一个巨无霸系统,里面涵盖了N多模块,代码千千万,依赖稀巴烂,构建超级慢,改一个bug,发一个版,测试要从头测到晚
那我希望你能看下去,更欢迎您与我一起 maintain 这个框架
当然,如果你的系统很简单,微前端,不适合。老老实实用大锅炉吧,一锅端比较好
什么是微前端
微前端与微服务的概念类似,是将复杂的系统前端模块进行拆分细化成各个子应用,
每个子应用可以拥有独立repository仓库,独立development开发,独立build构建,独立deployment部署,
我们把这些子应用称为“微应用”,类似于微服务
我们把管理子应用的应用称为“主应用”,有点像Console、Nacos等微服务注册中心的概念
虽然看起来有点 "偷天换日" ,但是不这样做,怎么装X....
微前端的好处
1.可以将复杂系统的前端代码拆分细化到不同团队
2.每个微应用不再局限于同一种框架
3.每个微应用独立开发、构建、部署
4.主应用与微应用开发、构建、部署分离,实现真正的“可插拔式”架构
5.每个微应用独立访问时页面看起来与访问主应用一样,实现共享页面
6.方便测试,每个微应用都是独立的
7.丰富微服务,微服务不再单纯的提供API,也可输出web页面
…………
微前端的坏处
1.打破传统前端开发模式,开发人员有阵痛期
2.对开发人员技术水平有一定要求,尤其是对npm package、webpack、esm,commonjs、umd等前端模块化、mvvm框架基本原理、docker等有一定掌握
…………还有不少坏处,这里我就不列举了,害怕你们受不了
微前端入门必修知识
1.如何构建发布同一个组织机构下的npm package?这里罗列vue旗下的几个package,大家感受一下:
@vue/vue-cli,@vue/vue-router………
比如我们要做一个微前端框架,就需要在npm 上发布类似下面的包:
@hollysys-mirco-front-end/framework等等
2.如何利用构建工具,比如rollup、webpack,打包出一个library库,像ant-design、element-ui等
3.webpack library、externals概念,以及动态生成html的插件webpackHtmlPlugin
4.设计模式之工厂模式、模板模式
5.umd、commonjs、es module等前端模块规范
………这些知识如果不懂,那我建议你去查查资料,不一定为了学习微前端,而是为了你自己
微前端架构要考虑以下列几件事情:
1.主应用、各个微应用如何独立开发、构建、部署
2.主应用与微应用如何共享一套html或者说dom,以此来实现当单独访问微应用
或者从主应用内部访问微应用时,用户看到的界面效果是一致的
3.微应用该如何暴露自己,通过什么方式暴露
4.主应用如何注册微应用,何时加载微应用,何时卸载,通过什么方式加载与卸载
5.主应用如何与微应用进行信息共享或者数据通讯,比如像jwt等等
6.微应用与微应用之间如何互相依赖
7.主应用、微应用如何样式隔离、变量隔离,做到沙箱sandbox
……应该还有一些坑,还在使劲踩的过程中
解决方案
针对上述问题,我们进行一步步分析,有点鱼骨图拔刺的味道了
独立开发、构建、部署
1.利用github或者gitlab,主应用与每个微应用创建属于自己的repo。
主应用仓库类似于:https://github.com/arashiquan33/hollysys-mirco-front-end-framework
各个微应用也拥有属于自己的repo,但是就像vue、react框架那样,我们需要提供创建微应用工程的脚手架hmfe-cli(hollysysMircoFrontEnd-cli),方便微应用在几乎一样的规则下开发
微应用脚手架模板类似于:https://github.com/arashiquan33/hollysys-mirco-front-end-app-vue-example
在拥有各自的仓库后,就可以进行独立开发,并且每个工程集成webpack或者rollup这样的工具进行独立构建打包
至于部署,可结合docker完成或者根据你们整体架构的方式来进行
应用间依赖
说到依赖,就不得不提npm package,大多数情况下我们都在使用别人写的package,这次我们翻身做主人,创建属于自己的package!!!
你一定看到过类似于这样的package:@webpack/webpack-cli,@webpack/webpack-devserve .....
没错,我们就要实现像这样带组织机构的package,进行统一管理,要搞就要搞的像回事!
主框架的package:@hollysys-mirco-front-end/framework
提示 要发布一个npm package,需要在工程目录下package.json动动手脚,具体可以查看 https://www.npmjs.com 文档
package.json 部分内容:
"name": "@hollysys-mirco-front-end/framework", //包名称
"author": {
"name": "quantianchao",
"email": "[email protected]"
},
"version": "0.0.31", // 包版本
"description": "微前端基座,负责管理微前端各个应用",
"main": "dist/hollysys-mirco-front-end-framework.js", //入口文件
"types": "types/hollysys-mirco-front-end-framework.d.ts",
"module": "dist/hollysys-mirco-front-end-framework.js",
各个微应用的package:@hollysys-mirco-front-end/app-vue-example
提示 app-vue-example是其中一个微应用的名称,通过dependenices来依赖主框架
package.json 部分内容:
"name":@hollysys-mirco-front-end/app-vue-example", //包名称
"version": "0.0.25", //版本
"description": "微前端应用示例",
"main": "lib/hollysys-mirco-front-end-app-vue-example.umd.js",
"module": "lib/hollysys-mirco-front-end-app-vue-example.umd.js",
"dependencies": {
"@hollysys-mirco-front-end/framework": "^0.0.32", // 依赖主框架
"core-js": "^3.6.5",
"vue": "^2.6.11"
},
app-vue-example微应用可以通过 dependenices 依赖来引入主应用framework暴露的一切
说到这来,可能有人要问,那要每个微应用都通过 dependenices 来依赖 framework
打包的时候岂不是重复打入了framework 代码? 这部分内容,我们可以通过 webpack externals 来完成,,这部分一会介绍framework的时候会详细说.
anyway,应用之间的依赖关系我们通过npm package 来解决。
主应用如何注册微应用,何时加载微应用,何时卸载,通过什么方式加载与卸载
咋一看,这部分我们要解决的内容很多,看起来很复杂,没关系,我们来捋一捋,我们可以通过抽象来把这事情讲清楚,大家就懂
1.抽象微应用,定义每个微应用该有的一些属性和方法
//抽象类
abstract class AbstractHollysysMircoFrontEndApp {
constructor(name: string, mountTo: HTMLElement,props:any) {
this.name = name;
this.mountTo = mountTo;
this.props=props;
}
//微应用名称
private name: string;
//挂载的DOM节点,即微应用在html中显示到哪个区域
private mountTo: HTMLElement;
//应用接收外部传递的props共享信息
private props:any
//定义一系列 hook,微应用可自行实现hook,返回Promise,解决函数体内有可能出现的异步情况
//应用安装前
abstract beforeInstall(): Promise<any>;
//应用安装
abstract install():Promise<any>;
//应用卸载
abstract uninstall():Promise<any>;
//应用卸载前
abstract beforeUninstall():Promise<any>;
}
由于javascript语言的特性以及多数前端开发人员的习惯,我们可通过构造函数参数的形式来定义一个微应用Class
export class HollysysMircoFrontEndApp {
constructor(appConstructorArguments:AppConstructorArguments) {
let {name,beforeInstall,install,uninstall,beforeUninstall,pathPrefix} = appConstructorArguments;
this.name=name;
this.pathPrefix=pathPrefix;
this.beforeInstall=beforeInstall;
this.install=install;
this.uninstall=uninstall;
this.beforeUninstall=beforeUninstall;
}
//微应用名称
private name: string;
public beforeInstall:() => Promise<void>;
public install:(installFunctionArguments:InstallFunctionArguments) => Promise<void>;
public uninstall:() => Promise<void>;
public beforeUninstall:() => Promise<void>;
}
2.实现一个具体的微应用,通过npm package 引入 @hollysys-mirco-front-end/framework 暴漏的微应用Class
以上述示例中app-vue-example为例,实例化一个HollysysMircoFrontEndApp,将vue对象的实例化包裹到微应用的安装方法内,最后把这个HollysysMircoFrontEndApp实例暴漏出去:
import Vue from "vue";
import App from "./App.vue";
import {
HollysysMircoFrontEndApp,
HollysysMircoFrontEndAppManager
} from "@hollysys-mirco-front-end/framework";
const hollysysMircoFrontEndAppVueExample = new HollysysMircoFrontEndApp({
name: process.env.npm_package_name,
beforeInstall: function() {
return Promise.resolve();
},
install: function({ mountTo, props,routerBasePath='' }) {
let routes = getRoutes(routerBasePath);
let router = new VueRouter({
routes // (缩写) 相当于 routes: routes
});
this.instance = new Vue({
props,
router,
render: h => h(App)
}).$mount(mountTo);
return Promise.resolve();
},
uninstall: function() {
this.install = null;
return Promise.resolve();
},
beforeUninstall: function() {
return Promise.resolve();
}
});
//很关键,把自己暴漏出去
export default hollysysMircoFrontEndAppVueExample;
这个例子其实很好的证明了,作为微应用的开发者,你只需要把你利用vue/react/angular等框架的初始化代码包裹到install方法就好,其他和之前的开发模式一模一样
3.定义应用管理者(单例),管理微应用的注册、下载、安装、卸载等等.
- 注册微应用(registerApp)
- 启动工程 (bootstrap)
- 监听浏览器url-hash变化,找出当前hash对应的已经注册的微应用 (addHashchangeListener)
- 卸载旧应用 (uninstallApp)
- 下载新的微应用 (downloadApp)
- 安装微应用 (installApp)
export class HollysysMircoFrontEndAppManager {
//私有化构造函数,不能通过new 来实例对象,只能通过getInstance()方法
private constructor(){}
//缓存单例
private static instance:HollysysMircoFrontEndAppManager;
/**
* 获取单例
*/
public static getInstance(): HollysysMircoFrontEndAppManager {
if (this.instance == null) {
this.instance = new HollysysMircoFrontEndAppManager();
}
return HollysysMircoFrontEndAppManager.instance;
}
//微应用挂载的节点ID
private _appMountTo='#mountTo';
private _menuMountTo='#menu';
private _isBootstrapCompleted:boolean=false;
//已经注册的所有微应用
private _hasRegisterApps: RegisterAppArguments[]=[];
/**
* @description 注册应用
* @param registerAppArguments
*/
public registerApp(registerAppArguments: RegisterAppArguments) {
this._hasRegisterApps.push(registerAppArguments);
}
/**
* @description 获取注册的应用
*/
public getRegisterApps():RegisterAppArguments[]{
return this._hasRegisterApps;
}
public downloadApp(registerAppArguments:RegisterAppArguments):Promise<any>{}
/**
* @description 下载装配应用
* @param appConfig
*/
public async installApp(app: HollysysMircoFrontEndApp) {
await app.beforeInstall();
await app.install({
mountTo:this._appMountTo,
props:{a:1}
});
}
/**
* @description 卸载应用
* @param appConfig
*/
public uninstallApp() {}
/**
* @description 启动
*/
public bootstrap(){}
/**
* @description 绑定hashchange
*/
private addHashchangeListener(){}
/**
* @description 浏览器hashchange变化的回调函数
*/
private async hashChangeHandler(){}
}
共享HTML
1.@hollysys-mirco-front-end/framework 这个package 需要打包出一个可以共享的html,里面定义整个应用看起来应该有的模样
2.微应用在开发时,可通过webpack 插件 HtmlWebpackPlugin 来指定微应用应该使用的html。例如:
vue.config.js中这样配置
config.plugin("html").tap(args => {
args[0].template =
"node_modules/@hollysys-mirco-front-end/framework/dist/standalone.html";
return args;
});
如果是webpack.config.js
new HtmlWebpackPlugin({
title: 'hollysys-mirco-front-end-app-standalone',
template: 'node_modules/@hollysys-mirco-front-end/framework/dist/standalone.html',
filename:'standalone.html',
})
微应用如何暴漏自己
1.前端模块化目前有好几种方案,amd/commonjs/es module/umd/system.js 等,这几种方案中,umd算是兼容性最好的
2.微应用通过export语法把实例化后的 HollysysMircoFrontEndApp 导出,再配合webpack打包library的功能,打包出一个脚本文件
3.以上述app-vue-example微应用为例,打包出一个 hollysys-mirco-front-end-app-vue-example.umd.js 脚本
可查看 https://github.com/arashiquan33/hollysys-mirco-front-end-app-vue-example 这个示例
如何下载微应用并且获取微应用实例
1.目前框架采用了动态创建script标签来加载微应用打包出来的js脚本,脚本加载完成后,获取应用注册时配置的脚本可以暴漏出来的变量,以此来获取微应用暴漏的 HollysysMircoFrontEndApp对象
注册微应用:
//获取实例
const hollysysMircoFrontEndAppManager = HollysysMircoFrontEndAppManager.getInstance();
//注册微应用
hollysysMircoFrontEndAppManager.registerApp({
name:'@hollysys-mirco-front-end/app-vue-example',
number:'0.0.24',
appModuleName:'hollysysMircoFrontEndAppVueExample',
appModuleUrl:'https://unpkg.com/@hollysys-mirco-front-end/[email protected]/lib/hollysys-mirco-front-end-app-vue-example.umd.js',
routerBasePath:'/app-vue-example'
})
public downloadApp(registerAppArguments:RegisterAppArguments):Promise<any>{
return new Promise((resolve,reject)=>{
//获取head的标签
var head= document.getElementsByTagName('head')[0];
//创建script标签
var script= document.createElement('script');
//属性赋值
script.type= 'text/javascript';
//添加src属性值
script.src= registerAppArguments.appModuleUrl;
head.appendChild(script);
//回调
script.onload = function(e) {
const module = window[registerAppArguments.appModuleName];
resolve(module);
};
})
}
2.后期会引入system.js模块系统来做到不用创建script标签来加载微应用,防止出现变量冲突的情况
运行主应用
1.yarn install
2.yarn serve
可查看目前已经做好的一个demo
该demo中注册了一个微应用 https://www.npmjs.com/package/@hollysys-mirco-front-end/app-vue-example
运行微应用
请以至 https://github.com/arashiquan33/hollysys-mirco-front-end-app-vue-example
结语
目前框架还在持续丰富中....