热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

微前端学习笔记

一、为什么要学习微前端什么是微前端微前端就是将不同的功能按照不同的维度拆分成多个子应用。通过主应用来加载这些子应用。微前端的核心在于拆,拆完后在合!为什么要使用微前端不同团

一、为什么要学习微前端


什么是微前端

在这里插入图片描述

微前端就是将不同的功能按照不同的维度拆分成多个子应用。通过主应用来加载这些子应用。

微前端的核心在于拆, 拆完后在合!


为什么要使用微前端


  • 不同团队间开发同一个应用技术栈不同怎么破?
  • 希望每个团队都可以独立开发,独立部署怎么破?
  • 项目中还需要老的应用代码怎么破?

我们是不是可以将一个应用划分成若干个子应用,将子应用打包成一个个的lib。当路径切换时加载同的子应用。这样每个子应用都是独立的,技术栈也不用做限制了!从而解决了前端协同开发问题


怎样落地微前端

在这里插入图片描述

微前端的灵感来源于,计算机上的应用,每一次用户打开一个应用,就相当于打开了一个新的页面


  • 2018年 Single-SPA诞生了, single-spa 是一个用于前端微服务化的 Javascript 前端解决方案 (本身没有处理样式隔离, js 执行隔离) 实现了路由劫持和应用加载
  • 2019年 qiankun 基于Single-SPA, 提供了更加开箱即用的 API ( single-spa + sandbox + import-html-entry ) 做到了,技术栈无关、并且接入简单(像iframe 一样简单)

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


这里先回答下大家的问题:


  • 这不是iframe吗?

    如果使用 iframe , iframe 中的子应用切换路由时用户刷新页面就尴尬了

    更多参考 Why Not Iframe

  • 应用之间怎么通信

    • 基于URL来进行数据传递,但是传递消息能力弱
    • 基于 CustomEvent 实现通信
    • 基于props主子应用间通信
    • 使用全局变量、 Redux 进行通信
  • 公共依赖

    • CDN - externals
    • webpack 联邦模块

微前端架构具备以下几个核心价值:


  • 技术栈无关

    主框架不限制接入应用的技术栈,微应用具备完全自主权

  • 独立开发、独立部署

    微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新

  • 增量升级

    在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略

  • 独立运行时

    每个微应用之间状态隔离,运行时状态不共享


二、SingleSpa 实战

single-spa官网


构建子应用

我们需要父应用加载子应用,需要暴露三个方法

1. bootstrap
2. mount
3. unmount

  1. 构建子应用

vue create single-child
npm i --save single-spa-vue

// 在子应用的 main.js 中导入依赖并进行配置
import singleSpaVue from 'single-spa-vue'const appOptions = {el: '#vue', // 挂载到父应用中的 id 为 vue 的标签中router,render: h => h(App)
}const vueLifeCycle = singleSpaVue({ // 返回single-spa 的生命周期也就是 bootstrap/mount/unmountVue,appOptions
});// single规定的协议,父应用会调用这些方法
export const bootstrap = vueLifeCycle.bootstrap;
export const mount = vueLifeCycle.mount;
export const unmount = vueLifeCycle.unmount;
// 这样做就有一个严重的问题,子应用无法启动了??

  1. 配置子应用中的打包路径

// 配置vue.config.js
module.exports = {configureWebpack: {output: {library: 'singleVue',libraryTarg: 'umd'},devServer: {port: 10000}}
};

  1. 配置子应用的路由

const router = new VueRouter({mode: 'history',base: '/vue', // 配置子应用路由的基础路径routes
})

  1. 父应用搭建

vue create single-parent
npm i --save single-spa // 注意这里是 single-spa

  1. 将子应用挂载到 id="vue" 的容器中

<div id&#61;"app"><router-link to&#61;"/vue">加载vue引用router-link><router-view/><div id&#61;"vue">div>
div>

  1. 配置父应用加载子应用

// 在父应用中导入依赖
import { registerApplication, start } from &#39;single-spa&#39;async function loadScript(url) { // 异步加载子组件中的脚本return new Promise((resolve, reject) &#61;> {let script &#61; document.createElement(&#39;script&#39;);script.src &#61; url;script.onload &#61; resolve;script.onerror &#61; reject;document.head.appendChild(script);});
}// 注册一个应用
registerApplication(&#39;myVueApp&#39;,async () &#61;> {console.log(&#39;加载模块&#39;);// 加载子应用中的脚本await loadScript(&#96;http://localhost:10000/js/chunk-vendors.js&#96;)await loadScript(&#96;http://localhost:10000/js/app.js&#96;)// 这里需要要返回 bootstrap/mount/unmountreturn window.singleVue},location &#61;> location.pathname.startsWith(&#39;/vue&#39;), // 此路径用来判断当前路由切换到 /vue 的路径下&#xff0c;需要加载我们定义的子应用{ a: 1 } // 选传&#xff0c;传给子应用 props 的参数&#xff0c;可以是对象或值
);start(); // 启动应用

  1. 配置子应用的路径

// 设置路径
if (window.singleSpaNavigate) { // 如果是父应用加载子应用&#xff0c;那会自动挂载一个属性&#xff0c;值为true__webpack_public_path__ &#61; &#39;http://localhost:10000/&#39;
}

  1. 希望子应用可以独立运行&#xff0c;在子应用中添加一个配置

if(!window.singleSpaNavigate){delete appOptions.el; // 子应用中没有#vue&#xff0c;所以需要手动删除&#xff0c;挂载到 #app 中new Vue(appOptions).$mount(&#39;#app&#39;);
}

singleSpa 缺陷


  1. 不能动态加载JS文件
  2. 样式不隔离
  3. 全局对象&#xff0c;没有JS沙箱的机制

三、qiankun 实战

qiankun官网


特点

1. 简单&#xff1a;任意 js 框架均可使用。微应用接入像使用接入一个 iframe 系统一样简单&#xff0c;但实际不是 iframe。
2. 完备&#xff1a;几乎包含所有构建微前端系统时所需要的基本能力&#xff0c;如 样式隔离、js 沙箱、预加载等。
3. 生产可用&#xff1a;已在蚂蚁内外经受过足够大量的线上系统的考验及打磨&#xff0c;健壮性值得信赖。

项目构建


  1. 主应用搭建 qiankun-base

vue create qiankun-base
npm i --save qiankun

// 配置主项目的加载 main.js
import Vue from &#39;vue&#39;
import App from &#39;./App.vue&#39;
import router from &#39;./router&#39;
import ElementUI from &#39;element-ui&#39;;
import &#39;element-ui/lib/theme-chalk/index.css&#39;;import {registerMicroApps, start} from &#39;qiankun&#39;;Vue.config.productionTip &#61; false
Vue.use(ElementUI);const apps &#61; [{name: &#39;vueApp&#39;, // 应用的名字entry: &#39;http://localhost:10000/&#39;, // 默认加载这个html&#xff0c;解析里面的js动态的执行&#xff08;子应用必须支持跨域&#xff0c;内部使用的是 fetch&#xff09;container: &#39;#vue&#39;, // 要渲染到的容器名idactiveRule: &#39;/vue&#39; // 通过哪一个路由来激活},{name: &#39;reactApp&#39;,entry: &#39;http://localhost:20000/&#39;,container: &#39;#react&#39;,activeRule: &#39;/react&#39;}
];registerMicroApps(apps); // 注册应用
start(); // 开启应用new Vue({router,render: h &#61;> h(App)
}).$mount(&#39;#app&#39;)


<template><div><el-menu :router&#61;"true" mode&#61;"horizontal"><el-menu-item index&#61;"/">首页el-menu-item><el-menu-item index&#61;"/vue">vue应用el-menu-item><el-menu-item index&#61;"/react">react应用el-menu-item>el-menu><router-view v-show&#61;"$route.name">router-view><div id&#61;"vue">div><div id&#61;"react">div>div>
template>

  1. 搭建Vue子项目

vue create qiankun-vue
// 子项目中不需要安装任何依赖&#xff0c;父组件会给window设置一些环境变量

// mian.js
import Vue from &#39;vue&#39;
import App from &#39;./App.vue&#39;
import router from &#39;./router&#39;Vue.config.productionTip &#61; false/*
new Vue({router,render: h &#61;> h(App)
}).$mount(&#39;#app&#39;)
*/

let instance &#61; null;
function render(props) {// props 组件通信instance &#61; new Vue({router,render: h &#61;> h(App)}).$mount(&#39;#app&#39;) // 这里是挂载到自己的HTML中&#xff0c;基座会拿到这个挂载后的HTML&#xff0c;将其插入进去
}if (!window.__POWERED_BY_QIANKUN__) { // 如果是独立运行&#xff0c;则手动调用渲染render();
}
if(window.__POWERED_BY_QIANKUN__){ // 如果是qiankun使用到了&#xff0c;则会动态注入路径__webpack_public_path__ &#61; window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}// 根据 qiankun 的协议需要导出 bootstrap/mount/unmount
export async function bootstrap(props) {};
export async function mount(props) {render(props);
};
export async function unmount(props) {instance.$destroy();
};

// 设置router路径
const router &#61; new VueRouter({mode: &#39;history&#39;,base: &#39;/vue&#39;,routes
})

// 配置打包 vue.config.js
module.exports &#61; {devServer: {port: 10000,headers:{&#39;Access-Control-Allow-Origin&#39;: &#39;*&#39; // 允许跨域}},configureWebpack: {output: {library: &#39;vueApp&#39;,libraryTarget: &#39;umd&#39;}}
};

  1. 搭建React项目

npx create-react-app qiankun-react
npm i --save-dev react-app-rewired

// 入口配置 /src/index.js
import React from &#39;react&#39;;
import ReactDOM from &#39;react-dom&#39;;
import &#39;./index.css&#39;;
import App from &#39;./App&#39;;function render(){ReactDOM.render(<React.StrictMode><App /></React.StrictMode>,document.getElementById(&#39;root&#39;));
}
if(!window.__POWERED_BY_QIANKUN__){render();
}
export async function bootstrap(){}
export async function mount() {render()
}
export async function unmount(){ReactDOM.unmountComponentAtNode( document.getElementById(&#39;root&#39;));
}

// 配置启动 config-overrides.js
module.exports &#61; {webpack:(config)&#61;>{config.output.library &#61; &#39;reactApp&#39;;config.output.libraryTarget &#61; &#39;umd&#39;;config.output.publicPath &#61; &#39;http://localhost:20000/&#39;;return config;},devServer:(configFunction)&#61;>{return function (proxy,allowedHost){const config &#61; configFunction(proxy,allowedHost);config.headers &#61; {"Access-Control-Allow-Origin":&#39;*&#39;}return config}}
}

添加react环境变量 .envPORT&#61;20000
WDS_SOCKET_PORT&#61;20000

// 配置react路由
import { BrowserRouter, Route, Link } from "react-router-dom"
const BASE_NAME &#61; window.__POWERED_BY_QIANKUN__ ? "/react" : "";
function App() {return (<BrowserRouter basename&#61;{BASE_NAME}><Link to&#61;"/">首页</Link><Link to&#61;"/about">关于</Link><Route path&#61;"/" exact render&#61;{() &#61;> <h1>hello home</h1>}></Route><Route path&#61;"/about" render&#61;{() &#61;> <h1>hello about</h1>}></Route></BrowserRouter>);
}

推荐阅读
  • 本文详细介绍了在 Vue.js 前端框架中集成 vue-i18n 插件以实现多语言支持的方法。通过具体的配置步骤和示例代码,帮助开发者快速掌握如何在项目中实现国际化功能,提升用户体验。同时,文章还探讨了常见的多语言切换问题及解决方案,为开发人员提供了实用的参考。 ... [详细]
  • DAO(Data Access Object)模式是一种用于抽象和封装所有对数据库或其他持久化机制访问的方法,它通过提供一个统一的接口来隐藏底层数据访问的复杂性。 ... [详细]
  • 在深入研究 React 项目的过程中,特别是在探索 react-router 源码时,我发现了其中蕴含的中间件概念。这激发了我对中间件的进一步思考与整理。本文将详细探讨 Redux 中间件的原理及其在实际项目中的应用,帮助读者更好地理解和使用这一强大工具。通过具体示例和代码解析,我们将揭示中间件如何提升应用的状态管理和异步操作处理能力。 ... [详细]
  • 本文深入解析了Spring Cloud路由网关Zuul的核心功能及其典型应用场景。通过对方志朋老师教材的学习和实践,详细探讨了Zuul在微服务架构中的重要作用,包括请求路由、过滤器链管理以及服务动态扩展等关键特性。同时,结合实际案例,展示了Zuul在高并发和复杂业务场景下的应用优势,为读者提供了全面的技术参考。 ... [详细]
  • 深入解析 Vue 中的 Axios 请求库
    本文深入探讨了 Vue 中的 Axios 请求库,详细解析了其核心功能与使用方法。Axios 是一个基于 Promise 的 HTTP 客户端,支持浏览器和 Node.js 环境。文章首先介绍了 Axios 的基本概念,随后通过具体示例展示了如何在 Vue 项目中集成和使用 Axios 进行数据请求。无论你是初学者还是有经验的开发者,本文都能为你解决 Vue.js 相关问题提供有价值的参考。 ... [详细]
  • 深入探索Node.js新框架:Nest.js第六篇
    在本文中,我们将深入探讨Node.js的新框架Nest.js,并通过一个完整的示例来展示其强大功能。我们将使用多个装饰器创建一个基本控制器,该控制器提供了多种方法来访问和操作内部数据,涵盖了常见的CRUD操作。此外,我们还将详细介绍Nest.js的核心概念和最佳实践,帮助读者更好地理解和应用这一现代框架。 ... [详细]
  • IOS Run loop详解
    为什么80%的码农都做不了架构师?转自http:blog.csdn.netztp800201articledetails9240913感谢作者分享Objecti ... [详细]
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • 秒建一个后台管理系统?用这5个开源免费的Java项目就够了
    秒建一个后台管理系统?用这5个开源免费的Java项目就够了 ... [详细]
  • Vue应用预渲染技术详解与实践 ... [详细]
  • 在 Vue.js 中实现网络请求的方法与最佳实践包括使用 `vue-resource` 插件。首先,通过命令 `npm install vue-resource --save` 安装该插件,确保添加 `--save` 参数以将依赖项记录到 `package.json` 文件中。此外,推荐使用 `axios` 作为替代方案,因为它提供了更强大的功能和更好的性能。在项目中引入并配置 `axios`,可以实现更高效、灵活的网络请求管理。 ... [详细]
  • 本文探讨了使用Python进行微服务架构设计的合理性和适用性。首先,介绍了微服务的基本概念及其在现代软件开发中的重要性。接着,通过具体的业务场景,详细分析了Python在微服务架构设计中的优势和挑战。文章还讨论了在实际应用中可能遇到的问题,并提出了相应的解决方案。希望本文能够为从事Python微服务开发的技术人员提供有价值的参考和指导。 ... [详细]
  • TypeScript 实战分享:Google 工程师深度解析 TypeScript 开发经验与心得
    TypeScript 实战分享:Google 工程师深度解析 TypeScript 开发经验与心得 ... [详细]
  • 如果程序使用Go语言编写并涉及单向或双向TLS认证,可能会遭受CPU拒绝服务攻击(DoS)。本文深入分析了CVE-2018-16875漏洞,探讨其成因、影响及防范措施,为开发者提供全面的安全指导。 ... [详细]
  • 本文推荐了六款高效的Java Web应用开发工具,并详细介绍了它们的实用功能。其中,分布式敏捷开发系统架构“zheng”项目,基于Spring、Spring MVC和MyBatis技术栈,提供了完整的分布式敏捷开发解决方案,支持快速构建高性能的企业级应用。此外,该工具还集成了多种中间件和服务,进一步提升了开发效率和系统的可维护性。 ... [详细]
author-avatar
dtd3795290
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有