微前端 从 0到 1搭建
微前端
Single-SPA
❝微服务是面向服务架构(SOA)的一种变体,把应用程序设计成一系列松耦合的细粒度服务,并通过轻量级的通信协议组织起来具体地,将应用构建成一组小型服务。这些服务都能够独立部署、独立扩展,每个服务都具有稳固的模块边界,甚至允许使用不同的编程语言来编写不同服务,也可以由不同的团队来管理
❞
官网:
2018年 Single-SPA诞生了, single-spa是一个用于前端微服务化的JavaScript前端解决方案 (本身没有处理样式隔离、js执行隔离) 实现了路由劫持和应用加载;
Alibaba -
springboot
- sofaboot
Single-SPA 搞了个入口 --> qiankun
2019年 qiankun基于Single-SPA, 提供了更加开箱即用的 API (single-spa + sandbox + import-html-entry),它 做到了技术栈无关,并且接入简单(有多简单呢,像iframe一样简单)。
总结:子应用可以独立构建,运行时动态加载,主子应用完全解耦,并且技术栈无关,靠的是协议接入(这里提前强调一下:子应用必须导出 bootstrap、mount、unmount三个方法)。
micro front ends single spot
应用量庞大,
实现上,关键问题在于:
多个 Bundle 如何集成?
子应用之间怎样隔离影响?
公共资源如何复用?
子应用间怎样通信?
如何测试?
当然,这种架构模式并非百益而无一害,一些问题也随之而来:
导致依赖项冗余,增加用户的流量负担
团队自治程度的增加,可能会破坏协作
「.....」
简单来讲,微前端的理念类似于微服务:
❝In short, micro frontends are all about slicing up big and scary things into smaller, more manageable pieces, and then being explicit about the dependencies between them.
❞
将庞大的整体拆成可控的小块,并明确它们之间的依赖关系。关键优势在于:
代码库更小,更内聚、可维护性更高松耦合、自治的团队可扩展性更好「渐进地升级、更新甚至重写部分前端功能成为了可能」「微前端」
微前端就是将不同的功能按照不同的维度拆分成多个子应用。通过主应用来加载这些子应用。
微前端的核心在于「拆」, 拆完后再「合」!
今天来一块聊聊微前端 技术
首先创建一个vue子应用,并通过single-spa-vue来导出必要的生命周期:
vuecreatespa-vuenpminstallsingle-spa-vue
importsingleSpaVuefrom"single-spa-vue";constappOptions={el:"#vue",router,render:h=>h(App)}//在非子应用中正常挂载应用if(!window.singleSpaNavigate){deleteappOptions.el;newVue(appOptions).$mount("#app");}constvueLifeCycle=singleSpaVue({Vue,appOptions});//子应用必须导出以下生命周期:bootstrap、mount、unmountexportconstbootstrap=vueLifeCycle.bootstrap;exportconstmount=vueLifeCycle.mount;exportconstunmount=vueLifeCycle.unmount;exportdefaultvueLifeCycle;
constrouter=newVueRouter({mode:"history",base:"/vue",//改变路径配置routes})
配置库打包
//vue.config.jsmodule.exports={configureWebpack:{output:{library:"singleVue",libraryTarget:"umd"},devServer:{port:10000}}}
主应用搭建
❝将子应用挂载到id="vue"标签中
❞
importVuefrom"vue"importAppfrom"./App.vue"importrouterfrom"./router"importElementUIfrom"element-ui";import"element-ui/lib/theme-chalk/index.css";Vue.use(ElementUI);constloadScript=async(url)=>{awaitnewPromise((resolve,reject)=>{constscript=document.createElement("script");script.src=url;script.onload=resolve;script.onerror=reject;document.head.appendChild(script)});}import{registerApplication,start}from"single-spa";registerApplication("singleVue",async()=>{//这里通过协议来加载指定文件awaitloadScript("http://localhost:10000/js/chunk-vendors.js");awaitloadScript("http://localhost:10000/js/app.js");returnwindow.singleVue},location=>location.pathname.startsWith("/vue"))start();newVue({router,render:h=>h(App)}).$mount("#app")动态设置子应用
if(window.singleSpaNavigate){__webpack_public_path__="http://localhost:10000/"}前置条件
npminstall-gyarn
yarninit安装 官方 React
Create React App是FaceBook的React团队官方出的一个构建React单页面应用的脚手架工具。它本身集成了Webpack,并配置了一系列内置的loader和默认的npm的脚本,可以很轻松的实现零配置就可以快速开发React的应用。
# 全局安装npm install -g create-react-app# 构建一个my-app的项目npx create-react-app my-appcd my-app# 启动编译当前的React项目,并自动打开 http://localhost:3000/npm start
构建 React项目
npm
npminitreact-appmy-app
Yarn
#yarncreateisavailableinYarn0.25+yarncreatereact-appmy-app使用 qiankun 微前端构建
官方文档: https://qiankun.umijs.org/zh
❝首先我们需要创建 3个 前端应用, 微前端 ,就是 代表 一个小型应用的独立部署,独立交互,需要 应用之间进行通信,这里我们使用qiankun来完成 微前端 应用
❞
创建 3 个 react app
yarncreatereact-appqiankun-base--templatetypescript
yarncreatereact-appqiankun-micro-app1--templatetypescript
yarncreatereact-appqiankun-micro-app2--templatetypescriptapp2app1基座
在 react app 应用中 安装 qiankun 依赖
$yarnaddqiankun#ornpmiqiankun-S
分别创建 .env 文件来指定 项目 运行的端口号
PORT=3010PORT=3011PORT=3012
在主应用中index.tsx 注册子应用
import React from "react";import ReactDOM from "react-dom";import "./index.css";import App from "./App";import reportWebVitals from "./reportWebVitals";import { registerMicroApps, start } from "qiankun";registerMicroApps([ { name: "react app one", // app name registered entry: "//localhost:3011", container: "#micro-app2", activeRule: "/micro-app2", props:{ nickname: "全栈小刘", age:19 } }, { name: "react app two", // app name registered entry: "//localhost:3012", container: "#micro-app1", activeRule: "/micro-app1", props:{ nickname: "全栈小刘", age:18 } },]);start();ReactDOM.render(, document.getElementById("root"));// If you want to start measuring performance in your app, pass a function// to log results (for example: reportWebVitals(console.log))// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitalsreportWebVitals();
❝name 应用名称entry 端口号container 挂载容器activeRule 激活的规则props: 父子属性之间传参注:子应用加载进来 ,需要有主应用进行挂载,现在我们已经将 子应用注册在 了 主应用当中
❞
api文档: https://qiankun.umijs.org/zh/api
在 App.tsx 中创建挂载点import React from "react";import logo from "./logo.svg";import "./App.css";function App() { return ( );}export default App;
在「所有」应用中 添加 public-path.js 用于 加载静态 资源
if(window.__POWERED_BY_QIANKUN__){__webpack_public_path__=window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;}
在子应用中 添加 webpack 重写项
添加yarnaddreact-app-rewired-D「设置 子应用」启动,在 scripts
"scripts":{"start":"react-app-rewiredstart","build":"react-scriptsbuild","test":"react-scriptstest","eject":"react-scriptseject"},
在webpack 中 进行 overrides 重写,重写的 目的是 允许跨域
config-overrides.jsconst{name}=require("./package");module.exports={webpack:(config)=>{config.output.library=`${name}-[name]`;config.output.libraryTarget="umd";//config.output.jsonpFunction=`webpackJsonp_${name}`;config.output.globalObject="window";returnconfig;},devServer:(_)=>{constconfig=_;config.headers={"Access-Control-Allow-Origin":"*",};config.historyApiFallback=true;config.hot=false;config.watchContentBase=false;config.liveReload=false;returnconfig;},};
在不同的子应用当中 去加载 tsx 生命周期
app1 、app2 、 index.tsx
import React from "react";import ReactDOM from "react-dom";import "./index.css";import App from "./App";import reportWebVitals from "./reportWebVitals";export async function bootstrap() { console.log("[react] react app bootstraped");}// @ts-ignoreexport async function mount(props) { console.log(props) ReactDOM.render(, props.container ? props.container.querySelector("#root") : document.getElementById("root"));}// @ts-ignoreexport async function update(props){ console.log("update props",props)}// @ts-ignoreexport async function unmount(props) { ReactDOM.unmountComponentAtNode( props.container ? props.container.querySelector("#root") : document.getElementById("root"));}// @ts-ignoreif (!window.__POWERED_BY_QIANKUN__) { ReactDOM.render( ,document.getElementById("root"))}// If you want to start measuring performance in your app, pass a function// to log results (for example: reportWebVitals(console.log))// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitalsreportWebVitals();
在 index.tsx 引入 public-path.js 解决静态资源
import "./public-path.js"
在 主 应用 添加 访问
import React from "react";import logo from "./logo.svg";import "./App.css";function App() { return ( );}export default App;在 主 应用 index.tsx 中 传递 数据
props:{ nickname: "全栈小刘", age:19 }在 子应用 周期中进行打印
export async function mount(props) { console.log(props) ReactDOM.render(, props.container ? props.container.querySelector("#root") : document.getElementById("root"));}
import { initGlobalState, MicroAppStateActions } from "qiankun";const state ={ nickname: "全栈小刘"}// 初始化const actions: MicroAppStateActions = initGlobalState(state);actions.onGlobalStateChange((state,prev)=>{ console.log(state,prev)})// 2秒钟后 改变setTimeout(()=>{ actions.setGlobalState({...state,age:19})},2000)在子应用中 监听改变
export async function mount(props) { console.log(props) // @ts-ignore props.onGlobalStateChange((state,prev)=>{ console.log(state,prev) setTimeout(()=>{ props.setGlobalState({ ...state, age:20 }); },2000) }) // @ts-ignore ReactDOM.render(安装 NPM SCRIPT 插件 ,分别 启动 运行, props.container ? props.container.querySelector("#root") : document.getElementById("root"));}
❝安装最新的脚手架通用 vue3
❞
npminstall-g@vue/cli创建 项目 es6 js 模块
vuecreateqiankun-vue-micro-app3添加typescript ,转换 ts -Yyes
vueaddtypescript依次加入 public-path.js
/*eslint-disable*/if(window.__POWERED_BY_QIANKUN__){__webpack_public_path__=window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;}安装 qiankun
yarnaddqiankun
参考qiankun官网的示例main.js ,完成生命周期的钩子函数
base 中 进行注册 index.tsx
vue-config.js 设置启动端口
vue-config.js
/*eslint-disable*/const{name}=require("./package");module.exports={devServer:{port:3013,headers:{"Access-Control-Allow-Origin":"*",}},configureWebpack:{output:{library:`${name}-[name]`,libraryTarget:"umd"}}};微前端项目 实战
https://github.com/a1029563229/micro-front-template
相关阅读
-
世界热推荐:今晚7:00直播丨下一个突破...
今晚19:00,Cocos视频号直播马上点击【预约】啦↓↓↓在运营了三年... -
NFT周刊|Magic Eden宣布支持Polygon网...
Block-986在NFT这样的市场,每周都会有相当多项目起起伏伏。在过去... -
环球今亮点!头条观察 | DeFi的兴衰与...
在比特币得到机构关注之后,许多财务专家预测世界将因为加密货币的... -
重新审视合作,体育Crypto的可靠关系才能双赢
Block-987即使在体育Crypto领域,人们的目光仍然集中在FTX上。随着... -
简讯:前端单元测试,更进一步
前端测试@2022如果从2014年Jest的第一个版本发布开始计算,前端开发... -
焦点热讯:刘强东这波操作秀
近日,刘强东发布京东全员信,信中提到:自2023年1月1日起,逐步为...