单体html整合vue,GitHub - QxQstar/single-spa-vue: 微前端框架single-spa 整合vue项目

运行demo

sudo npm run install:all

sudo npm run start

访问http://localhost:5000/

概念

微前端的概念是从后端的微服务的迁移过来的。将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用还可以独立运行、独立开发、独立部署。

微前端只在前后端分离的单页应用中讨论才有意义。单页应用的核心是:在特定的时刻将一段由js运行生成的html代码片段插入到一个特定的位置。微前端项目并没有改变这个核心。微前端的项目与单体项目的差别是:生成html片段的js代码可能位于不同的域名下,所以各个资源的路径最好不要使用相对路径。

微前端项目是由多个子项目组成的,所以需要在微前端项目中声明这个项目是由哪些子项目组成的,这个步骤称为子项目注册。子项目注册做的事情是:给这个项目命名,指定这个项目在什么情况下装载在html文档中,在什么情况从html文档中卸载,所以就会涉及到生命周期的钩子函数。

项目结构图

c61d3c20d2a68d8f84df9bb84273b4fc.png

在线访问地址

需要解决的问题

子项目的注册、异步加载和生命周期管理;

子项目之间、主从之间的消息机制;

子项目之间的安全隔离措施;

子项目的框架无关、版本无关;

子项目之间、主从之间的公共依赖的库、业务逻辑(utils)以及版本怎么管理;

子项目独立调试、和主应用联调的方式;

发布

实现

补充:在这个 demo 中是使用 webpack 打包项目

给各个应用注册生命周期函数

补充: 在这个 demo 中子项目都是 vue 项目

安装single-spa-vue

vue add single-spa

// 或者

npm install --save single-spa-vue

改写入口文件

import vue from 'vue';

import App from './App.vue';

import router from './router';

import store from './store/base';

import singleSpaVue from 'single-spa-vue';

import elementUI from 'element-ui';

vue.use(elementUI)

vue.config.productionTip = false;

const vueLifecycles = singleSpaVue({

Vue:vue,

appOptions: {

el:'#main',

render: (h) => h(App),

router,

store

},

});

export const bootstrap = vueLifecycles.bootstrap;

export const mount = vueLifecycles.mount;

export const unmount = vueLifecycles.unmount;

抽离公共资源

配置webpack的 externals 字段使webpack在打包的时候不打包公共库如(vue, vue-router, 私有 npm 包等),如下:

{

externals:['vue',{'vue-router':'vueRouter'},{'element-ui':'elementUI'}]

}

设置项目打包格式

output: {

...

libraryTarget: 'umd',

library: xxx,

}

注册子项目

各子个项目的配置

{

name:'main-project',

base:true,

projectIndex:'http://localhost:9100',

},

{

name:'customers',

base:false,

path:'#/customers',

domID:'main',

projectIndex:'http://localhost:5100',

},

{

name:'goods',

base:false,

path:'#/goods',

domID:'main',

projectIndex:'http://localhost:9010',

}

@hydesign/grape

使用@hydesign/grape完成子项目的注册,异步加载和生命周期管理,并且子项目的框架无关,版本无关。@hydesign/grape与webpack的 externals 配合使用,能够抽离出项目中不想打包的库,并且在项目运行当使用到这个库的时候在动态加载。

import Grape from '@hydesign/grape';

new Grape(appsConf)

.setImportMap({

"vue": "https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js",

"vueRouter": "https://cdn.jsdelivr.net/npm/vue-router@3.0.7/dist/vue-router.min.js",

"elementUI":"https://cdn.jsdelivr.net/npm/element-ui@2.12.0/lib/index.js",

"Vuex":"https://cdn.jsdelivr.net/npm/vuex@3.1.1/dist/vuex.min.js",

"axios":"https://cdn.jsdelivr.net/npm/axios@0.19.0/dist/axios.min.js",

"hytools":"https://cdn.jsdelivr.net/npm/hytools@1.2.0/dist/index.js"

})

.start()

给子项目的入口js加标识

经过webpack打包之后一个项目在 index.html 中插入的 js 脚本可能不只一个,所以在为了确保@hydesign/grape能够正确的从项目访问入口中解析要入口js,给入口 js 文件加上一个自定义属性

const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin')

plugins:[

...

new ScriptExtHtmlWebpackPlugin({

custom: {

test: /app.*\.js$/,

attribute: 'entry',

value: true

}

})

]

配置跨域访问

devServer:{

...

headers: {

"Access-Control-Allow-Origin": "*",

},

},

由于子项目的资源需要在入口项目中访问,所以需要在子项目中配置跨域访问

资源的访问路径

由于子项目的资源是在入口项目(入口项目和子项目在不同的域)中访问,所以需要将子项目的 publicPath 设置为完整的路径(即:包括协议和域名),这样才能保证子项目的资源能够正确加载。output.publicPath

各个应用间进行通信

使用浏览器自定义事件来实现各个应用间的通讯

// customers

window.dispatchEvent(new CustomEvent('logout'));

// main-project

window.addEventListener('logout',handler);

注意:各个应用之间应该尽可能少的进行通信,如果两个应用之间频繁的进行通信,那么它们两个应该合并成一个

隔离css样式

使用webpack,postcss在构建阶段为业务的所有 CSS 都加上自己的作用域

postcss:{

plugins:[require('postcss-plugin-namespace')('.main-project',{ ignore: [ '*'] })]

}

独立运行

使用 cross-env 设置环境变量,在入口js文件中访问环境变量 process.env.VUE_APP_SINGLERUN 的值决定是否new 一个vue根实例

参考文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值