这是我参与8月更文挑战的第7天,活动详情查看: 8月更文挑战
前言
微前端解决什么问题? 近几年前端的工程化知识开发愈演愈烈,后端解耦,前端聚合,兴起微前端的技术主要是因为SPA项目工程,得到了长足的发展,所有的微前端都是为了解决工程与工程之间的粘合问题即是 从所有收集的部分组成并返回一个无缝的HTML页面
首先先明白一个概念,什么是SPA?什么是MPA?什么是PWA?
- SPA:单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。
- MPA:多页面应用(multi page web application,MPA),绝大多数的网站都属于多页面应用 见下图:
- PWA: 是Progressive Web App的英文缩写, 翻译过来就是渐进式增强WEB应用, 是Google 在2016年提出的概念,2017年落地的web技术。目的就是在移动端利用提供的标准化框架,在网页应用中实现和原生应用相近的用户体验的渐进式网页应用。(详细看:www.jianshu.com/p/098af61bb… 见下图:
综合对比之后,我们看到
2016年, PWA在google正式落地,基于 Chromium 的浏览器 Chrome 和 Opera 已经完全支持 PWA 了
随着 iOS 11.3 的发布,iOS正式开始支持PWA
Windows Edge 支持PWA
随着越来越多的浏览器大厂,相继的对PWA做出了支持和优化,想必PWA的时代即将到来。
比较有意思的是VUE-CLI 官方早已经支持构建PWA应用了,大家可以去尝试尝试。@vue/cli-plugin-pwa
前面的都是多余的话,后面重点来了,多个SPA工程如何能够聚合在一个页面里面呢?(该话题仅限在前端的知识范畴里面讨论,不能开历史的倒车)
这个问题在前端领域一直是一个非常重要的话题
看看别人怎么说的吧!
同样的,一些复杂概念的解释如下:
-
应用微服务化,即每个前端应用一个独立的服务化前端应用,并配套一套统一的应用管理和启动机制,诸如微前端框架 Single-SPA 或者 mooa 。
-
微件化,即通过对构建系统的 hack,使不同的前端应用可以使用同一套依赖。它在应用微服务化的基本上,改进了重复加载依赖文件的问题。
-
微应用化,又可以称之为组合式集成,即通过软件工程的方式,在开发环境对单体应用进行拆分,在构建环境将应用组合在一起构建成一个应用。 即我们采用的方案是Single-SPA来完成的我们的一体化前端大项目方案落地
什么是 single-spa?
single-spa是一个在前端应用程序中将多个javascript microfrontend集合在一起的框架。使用单spa构建前端可以带来很多好处,如: -
在同一页面上使用多个框架而无需刷新页面 (React,AngularJS,Angular,Ember或您使用的任何东西)
-
独立部署您的微前端。
-
使用新框架编写代码,而无需重写现有应用程序
-
延迟加载代码可缩短初始加载时间。
正文
一、single-spa 案例
1、父级项目
1.1 配置single-spa-config.js
// singleSpa.registerApplication:这是注册子项目的方法。参数如下:
// appName: 子项目名称
// applicationOrLoadingFn: 子项目注册函数,用户需要返回 single-spa 的生命周期对象。后面我们会介绍single-spa的生命周期机制
// activityFn: 回调函数入参 location 对象,可以写自定义匹配路由加载规则。
// singleSpa.start:这是启动函数。
// single-spa-config.js
import * as singleSpa from 'single-spa'; //导入single-spa
/**
* 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);
})
};
singleSpa.registerApplication( //注册微前端服务
'singDemo',
async() => {
await runScript('http://127.0.0.1:3000/js/chunk-vendors.js');
await runScript('http://127.0.0.1:3000/js/app.js');
return window.singleVue;
},
location => (location.pathname.startsWith('/uni-ems') || location.pathname.startsWith('/landingPageWeb/uni-ems')) // 配置微前端模块前缀
);
singleSpa.start(); // 启动
1.2 router路由信息
{
name: 'uni-ems',
path: '/uni-ems',
component:() => import('@/views/portal/Portal'),// 加载器 加载模块
},
2、子项目
2.1 配置main.js
const vueOptions = {
el: '#uni-ems',
router,
store,
render: h => h(App)
}
// 判断是否为single-spa模式,如果不是,就独立渲染
if (!window.singleSpaNavigate) { // 如果不是single-spa模式
delete vueOptions.el;
new Vue(vueOptions).$mount('#app')
}
// singleSpaVue包装一个vue微前端服务对象
const vueLifecycles = singleSpaVue({
Vue,
appOptions: vueOptions
})
// 导出生命周期对象
export const bootstrap = vueLifecycles.bootstrap // 启动时
export const mount = vueLifecycles.mount // 挂载时
export const unmount = vueLifecycles.unmount // 卸载时
export default vueLifecycles
2.2 配置vue.config.js
重点配置: publicPath、 output 、devServer
publicPath: '//localhost:3000',
pluginOptions: {
"style-resources-loader": {
preProcessor: "less",
patterns: [path.resolve(__dirname, "./src/style/base.less")]
}
},
configureWebpack: {
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"windows.jQuery": "jquery"
})
],
devtool: 'none', // 不打包sourcemap
output: {
library: "singleVue", // 导出名称
libraryTarget: "window", //挂载目标
}
},
devServer: {
contentBase: './',
port: 3000, // 端口
compress: true,
}
二、微前端的进阶 qiankun
qiankun 是由蚂蚁金服推出的比较成熟的微前端框架,基于 single-spa
进行二次开发,用于将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。
1、父级项目
1.1 安装 qiankun
$ yarn add qiankun # 或者 npm i qiankun -S
1.2. 父项目 基座
<div class="main-app">
<header class="main-app-header">
<h1>QianKun</h1>
</header>
<div class="main-app-main">
<ul class="main-app-menu">
<li><a href="/vue">vue子项目</a></li>
</ul>
<main id="sub-app-container">
<div id="vue"></div>
</main>
</div>
</div>
1.3. 在主应用中注册子应用
import { registerMicroApps, setDefaultMountApp, start } from 'qiankun';
/**
* 注册子应用
*/
registerMicroApps(
[
{
name: 'vueApp',
entry: '//localhost:10000',
container: '#vue',
activeRule: '/vue',//浏览器url变化 插入到指定的container中 ,依次调用微应用的生命周期钩子
},
],
);
/**
* 设置默认进入的子应用
*/
setDefaultMountApp('/vue');
/**
* 启动应用
*/
start();
当子应用信息注册完之后,一旦浏览器的 url 发生变化,便会自动触发 qiankun 的匹配逻辑,所有 activeRule 方法返回 true
的子应用对应的 render 方法就会被调用,同时依次调用子应用暴露出的生命周期钩子
2、子项目
子应用不需要额外安装任何其他依赖即可接入 qiankun 主应用。
2.1 导出相应的生命周期钩子
子应用需要在自己的入口 js (通常就是你配置的 webpack 的 entry js) 导出 bootstrap
、 mount
、 unmount
三个生命周期钩子,以供主应用在适当的时机调用。
let router = null;
let instance = null;
function render(props = {}) {
const { container } = props;
router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? '/vue' : '/',
mode: 'history',
routes,
});
instance = new Vue({
router,
render: h => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
}
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
//子组件协议
export async function bootstrap(props){
console.log(props);
}
export async function mount(props){
render(props)//装载
}
export async function unmount(props){
console.log(props);
instance.$destroy(); //卸载
instance.$el.innerHTML = '';
instance = null;
router = null;
}
2.2 配置子应用的打包工具
除了代码中暴露出相应的生命周期钩子之外,为了让主应用能正确识别子应用暴露出来的一些信息,子应用的打包工具需要增加如下配置:
module.exports = {
configureWebpack:{
output:{
library: 'vueApp',
libraryTarget:'umd'
}
},
devServer: {
port: 10000,
headers: {
'Access-Control-Allow-Origin': '*'
}
}
};
以上就是项目中用到的微前端的解决方案,谢谢观看!