Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

分享你的 demo [ Share your demo ] #1777

Open
gongshun opened this issue Oct 23, 2021 · 35 comments
Open

分享你的 demo [ Share your demo ] #1777

gongshun opened this issue Oct 23, 2021 · 35 comments

Comments

@gongshun
Copy link
Collaborator

hi,大家好!尽管官方已经提供了 qiankundemo教程,但是覆盖面有限。比如说,qiankun 嵌套的使用、angular 作为主应用等,都没有可以参考的 demo。有不少的小伙伴,在不同的技术栈或者框架中使用 qiankun 时,遇到了很多棘手的问题。

如果你有写过一些不同框架/技术栈的 demo ,希望可以分享出来,帮助他人快速上手,谢谢。直接在 issue 中回复 demo 的地址并附上简介即可。

PS:如果别人的 demo 有帮助到你,可以给他点个赞或者点个 star

注意: 请不要在 issue 回复无关内容,对 demo 有疑问请去 demo 仓库提问,无关的回复将会被定期清理。


Hi all! Although the demo and tutorial of qiankun have been provided, the scenarios covered are limited. For example, there are no demos that can be referenced for the use of qiankun nesting and angular as the main application. There are many partners who have encountered many difficult problems when using qiankun in different frameworks.

If you have written demos of different frameworks/technology stacks, I hope you can share them to help others get started quickly, thanks. Reply to the demo address in the issue and attach a brief introduction.

PS: If someone else’s demo is helpful to you, you can give him a like or a star.

Note: Please do not reply to irrelevant content in the issue. If you have any questions about the demo, please go to the demo warehouse to ask questions. Irrelevant replies will be cleaned up regularly.

@gongshun gongshun pinned this issue Oct 23, 2021
@gongshun
Copy link
Collaborator Author

地址:https://github.com/gongshun/qiankun-vue-demo

介绍:主子应用都是 vue 技术栈,在常规使用的基础上实现了:tab 标签页效果、应用之间的组件共享、依赖共享、子应用是 vite 构建 的等效果(代码在不同的分支)

@gongshun
Copy link
Collaborator Author

地址:https://github.com/gongshun/qiankun-vue-element-admin

介绍:主子项目都是 vue-element-admin 创建的,路由都是 history 模式

@niexq
Copy link

niexq commented Oct 23, 2021

地址

https://github.com/niexq/react-app-qiankun-main

简介

🍔 基座

🍟 react子应用

🌮 vue子应用

@xtthaop
Copy link

xtthaop commented Oct 25, 2021

地址:https://github.com/xtthaop/vue-qiankun-demo

介绍:主子应用都是 vue 技术栈,在常规使用的基础上实现了权限管理,详细请查看这里

@hql7
Copy link

hql7 commented Oct 27, 2021

地址:https://github.com/wl-ui/wl-mfe
介绍:qiankun2.x & vue3.x 版本
地址:https://github.com/hql7/wl-micro-frontends
介绍:qiankun1.x & vue2x 版本
地址:https://github.com/hql7/wl-cli
介绍:快速创建qiankun主应用、自应用结构脚手架

@zhaoshunchen
Copy link

地址:https://github.com/zhaoshunchen/qiankun-nested-demo
介绍:qiankun2.x & vue2.x 版本
业务场景:项目 A,内部注册项目 B,项目 B也使用了 qiankun,内部注册项目 C

@8696
Copy link

8696 commented Dec 12, 2021

地址https://github.com/8696/micro-web-demo
预览http://micro.icode.link
主应用:react^17.0.2
子应用react^17.0.2、vue^3.2.40、angular^15.2.0

@GreenBoy0526
Copy link

https://github.com/GreenBoy0526/qiankun-demo
主要是解决微应用路由切换后主应用切换路由报错问题,代码参考主应用的路由配置,主应用vite+vue3,子应用vue2

router.beforeEach((to, from, next) => {
  if (!window.history.state.current) window.history.state.current = to.fullPath;
  if (!window.history.state.back) window.history.state.back = from.fullPath;
  return next();
});

@aehyok
Copy link

aehyok commented Dec 27, 2021

主应用使用vite3+vue3,子应用使用vuecli +vue3

单纯vue3 qiankun的 demo文档说明

代码仓库地址

线上预览版本 http://vue.tuokecat.com/

@haixiangyan
Copy link

haixiangyan commented Dec 29, 2021

非常简单的 Demo~
主应用:React
子应用:React, Vue 有各自路由,欢迎 fork
普通业务的 Demo: https://github.com/haixiangyan/qiankun-bigass-app
企业微信侧边栏的 qiankun 模板:https://github.com/wecom-sidebar/wecom-sidebar-qiankun-tpl

@hairgc
Copy link

hairgc commented Jan 5, 2022

Demo还没有时间整理,说一下遇到的问题以及解决方案吧
主应用: Angular10
子应用: Vue2
项目概况:主应用本身有自己的业务代码和页面,使用的是@angular/router,,hash路由,子应用会在特定路由加载使用的是registerMicroApps(为啥不用loadMicroApp?因为子应用的卸载时机不太好把握)

下面说一下遇到的问题以及解决方案吧,首先说明一下解决方案只保证对我们这个项目有效,大家只供参考

问题1:

问题描述:主应用页面使用浏览器返回功能(history.back())失效(即使还从未加载过子应用),页面url会变,但是页面不会渲染,只有下次Angular脏检查才会渲染新页面渲染(可以通过调用一下window.dispatchEvent(new Event('resize'))验证下)

浏览器:Chrome/IE11

问题定位:qiankun依赖的single-spa一开始就会拦截篡改原生的window.addEventListener,源码片段如下:

  // https://github.com/single-spa/single-spa/blob/bcea338aff9231bacf9926ffc7b70dfe83e9f6eb/src/navigation/navigation-events.js#L147
  window.addEventListener = function (eventName, fn) {
    if (typeof fn === "function") {
      if (
        routingEventsListeningTo.indexOf(eventName) >= 0 &&
        !find(capturedEventListeners[eventName], (listener) => listener === fn)
      ) {
        capturedEventListeners[eventName].push(fn);
        return;
      }
    }

    return originalAddEventListener.apply(this, arguments);
  };

而且上述代码会在Angular Zone注册各种监听事件之前执行,导致Angular Zone注册的hashchange事件会被拦截,虽然single-spa会在url改变时调用一下所有注册的回调,但是不知为何Zone并不会响应浏览器的返回事件了

解决

方案1:自己在全局注册一下hashchange事件(比如app.component.ts),然后手动触发一下Angular脏检查

fromEvent(window, 'hashchange')
    .pipe(
        takeUntil(this.complete$),
        tap(()=>{
            const evt = document.createEvent('HTMLEvents');
            evt.initEvent('resize', false, false);
            window.dispatchEvent(evt)
        })
    )

方案2:让主应用的各种注册事件在single-spa拦截window.addEventListener前执行,修改single-spa源码

window.addEventListener = function (eventName, fn) {
    if (typeof fn === "function") {
      if (
        routingEventsListeningTo.indexOf(eventName) >= 0 &&
        !find(capturedEventListeners[eventName], (listener) => listener === fn) &&
        isStarted() // 加一个这个判断,isStarted是源码里面提供的方法,判断微服务是否启动
      ) {
        capturedEventListeners[eventName].push(fn);
        return;
      }
    }

问题2:

问题描述:子应用记载过一次之后,返回主应用的页面,Zone脏检查就出问题了,进入主应用某些页面本应该触发的某些事件就会莫名其妙的不触发,比如:某个页面使用了ng-zorro的nz-table组件,本来组件初始化就会触发的nzQueryParams并没有被触发

浏览器:IE11

问题定位:IE不支持Proxy,qiankun会使用SnapshotSandbox沙箱来隔离父子应用对于window对象的修改

if (window.Proxy) {
sandbox = useLooseSandbox ? new LegacySandbox(appName, globalContext) : new ProxySandbox(appName, globalContext);
} else {
sandbox = new SnapshotSandbox(appName);
}

当加载子应用时会为子应用创建一个沙箱,如果已创建过就会还原子应用卸载时的window快照,有兴趣可以看下源码,不难理解
active() {
// 记录当前快照
this.windowSnapshot = {} as Window;
iter(window, (prop) => {
this.windowSnapshot[prop] = window[prop];
});
// 恢复之前的变更
Object.keys(this.modifyPropsMap).forEach((p: any) => {
window[p] = this.modifyPropsMap[p];
});
this.sandboxRunning = true;
}

function iter(obj: typeof window, callbackFn: (prop: any) => void) {
// eslint-disable-next-line guard-for-in, no-restricted-syntax
for (const prop in obj) {
// patch for clearInterval for compatible reason, see #1490
if (obj.hasOwnProperty(prop) || prop === 'clearInterval') {
callbackFn(prop);
}
}
}

问题就出在这里,当进入子应用并从子应用回来,window.setInterval会被还原为进入之前的对象,然后主应用脏检查就出问题了,原因尚未可知
inactive() {
this.modifyPropsMap = {};
iter(window, (prop) => {
if (window[prop] !== this.windowSnapshot[prop]) {
// 记录变更,恢复环境
this.modifyPropsMap[prop] = window[prop];
window[prop] = this.windowSnapshot[prop];
}
});
if (process.env.NODE_ENV === 'development') {
console.info(`[qiankun:sandbox] ${this.name} origin window restore...`, Object.keys(this.modifyPropsMap));
}
this.sandboxRunning = false;
}

解决
不记录Zone快照

function iter(obj: typeof window, callbackFn: (prop: any) => void) {
  for (const prop in obj) {
    // 修改点在这里
    if ((obj.hasOwnProperty(prop) || prop === 'clearInterval') && prop !== 'setInterval') {
      callbackFn(prop);
    }
  }
}

问题3:

问题描述:Target container with #xxx not existed while xxx mounting!,第二次进入子应用偶现这个错误(快速使用浏览器返回进入子应用可复现),因为是在特定路由加载子应用,子应用挂载时,容器还不存在

浏览器:Chrome/IE

问题定位:出现这个问题不难理解,就是子应用挂载时指定的容器还未渲染在DOM中

qiankun/src/loader.ts

Lines 392 to 402 in d626baa

async () => {
const useNewContainer = remountContainer !== initialContainer;
if (useNewContainer || !appWrapperElement) {
// element will be destroyed after unmounted, we need to recreate it if it not exist
// or we try to remount into a new container
appWrapperElement = createElement(appContent, strictStyleIsolation, scopedCSS, appInstanceId);
syncAppWrapperElement2Sandbox(appWrapperElement);
}
render({ element: appWrapperElement, loading: true, container: remountContainer }, 'mounting');
},

qiankun/src/loader.ts

Lines 171 to 186 in d626baa

if (phase !== 'unmounted') {
const errorMsg = (() => {
switch (phase) {
case 'loading':
case 'mounting':
return `Target container with ${container} not existed while ${appInstanceId} ${phase}!`;
case 'mounted':
return `Target container with ${container} not existed after ${appInstanceId} ${phase}!`;
default:
return `Target container with ${container} not existed while ${appInstanceId} rendering!`;
}
})();
assertElementExist(containerElement, errorMsg);
}

qiankun/src/loader.ts

Lines 35 to 43 in d626baa

function assertElementExist(element: Element | null | undefined, msg?: string) {
if (!element) {
if (msg) {
throw new QiankunError(msg);
}
throw new QiankunError('element not existed!');
}
}

为什么会出现呢?浏览器卡一点,或者页面渲染加入了过渡动画都可能导致这个问题

解决
删除过渡动画有可能解决,但是有些过渡动画确实能够提升用户体验,直接去掉不太可取, 我采用如下方案:修改qiankun loader源码(这里也希望qiankun API能够支持获取容器的最大重试次数)

// https://github.com/umijs/qiankun/blob/d626baaa342a4ce74a3b944f4cedc40c1bf661b7/src/loader.ts#L393
async () => {
  const useNewContainer = remountContainer !== initialContainer;
  if (useNewContainer || !appWrapperElement) {
    // element will be destroyed after unmounted, we need to recreate it if it not exist
    // or we try to remount into a new container
    appWrapperElement = createElement(appContent, strictStyleIsolation, scopedCSS, appName);
    syncAppWrapperElement2Sandbox(appWrapperElement);
  }

  // 修改点:加入以下代码片段,留下充足的时间等待容器加载(每300ms重试一次,最多重试15次)
  if (!getContainer(initialContainer!)) {
    await new Promise((resolve) => {
      let count = 0;
      const timer = setInterval(() => {
        if (getContainer(initialContainer!) || count > 15) {
          clearInterval(timer);
          resolve({});
        }
        count++;
      }, 300);
    });
  }

  render({ element: appWrapperElement, loading: true, container: remountContainer }, 'mounting');
}

举一反三:其他各个阶段的Target container with #xxx not existed ,也可参考类似思路解决

修改了node_modules源码,如何让其他小伙伴也能够一起用,推荐 patch-package

@sh-winter
Copy link

sh-winter commented Feb 11, 2022

地址:https://github.com/sh-winter/vite-plugin-qiankun (demoexample 目录下)

介绍:主子应用都是由 vite 构建的,子应用使用了 vue3,支持开发环境😉

@kuaifengle
Copy link

kuaifengle commented Feb 17, 2022

参考代码地址: https://github.com/kuaifengle/qiankun-vue3-tabsPage
网页演示网址: https://kuaifengle.github.io/qiankun-vue3-tabsPage-demo

Vue3.0 + qiankun.js 实现多tab标签页的路由切换功能
主子应用都是vue3.0写的, 目前自己的公司也在用,后续会持续更新.
通过修改主应用的路由 后利用子应用的updata方法来 执行子页面$root的方法
监听用initialState的变化来执行对微页面内部的路由跳转
用keep-alive来缓存主应用和微应用的页面

@su4g
Copy link

su4g commented Mar 30, 2022

地址:https://github.com/su4g/qiankun-angular13-Base

简介:
主应用 - Angular13
子应用 - Angular13

@qq253498229
Copy link

qq253498229 commented Apr 29, 2022

地址:https://github.com/qq253498229/qiankun-ng13-docker

简介:
主应用 - Angular13
子应用 - Angular13

未使用single-spa,带Dockerfile以及docker-compose.yml


2023-04-20更新,升级到Angular15,原来的代码在ng13分支查看

@mayunbaba
Copy link

地址:https://gitee.com/github-26497262/micro-fe

简介:主要介绍三方依赖提取的方案。
vue-cli、webpack、vite 三个版本

@Aaron52077
Copy link

Aaron52077 commented Jul 27, 2022

地址:mat-react-pro演示地址

简介:支持页面缓存、页签操作

主应用:react18

子应用:react18、vue3、angular9

@xoptimal
Copy link

地址: https://github.com/xoptimal/qiankun-demo

简介

  • 主应用(基于umi4构建)
  • 微应用(基于umi3构建)
  • 微应用2(基于react-create-app构建)
  • 微应用3(react-create-app + router构建)

完成功能

挂载, 通信, 样式隔离, 错误处理

@savelifeme
Copy link

主应用使用vite3+vue3,子应用使用vuecli +vue3

单纯vue3 qiankun的 demo文档说明

代码仓库地址

线上预览版本 http://vue.tuokecat.com/

大佬,写的很细,太贴心了,

@aehyok
Copy link

aehyok commented Aug 23, 2022

@savelifeme 最好能帮到你。

@yugasun
Copy link

yugasun commented Sep 6, 2022

Micro Frontend Starter

Source code: https://github.com/yugasun/micro-frontend-starter

Feature

  • Micro Framework using qiankun 🔥
  • Monorepo using pnpm 🔥
  • Develop & build using vite 🔥
  • Support Vue.js, React.js, Svelte.js frameworks
  • Auto develop and build commands.
  • Support docker deployment.

@ghost
Copy link

ghost commented Sep 25, 2022

一个使用 qiankun 支持的微前端应用 demo

  • 主应用 vue2
  • 子应用 angularjs + vue2

启动整个项目

  • monorepo,使用 pnpm workspace 管理
  • 使用 pnpm 安装依赖
  • 执行 pnpm start 启动整个项目

端口

主应用 子应用 端口
vue2 8080(默认)
angularjs 7101
vue2 7102

源代码:

https://github.com/12redcircle/qiankun-angularjs-migrate-demo

@MAXLZ1
Copy link

MAXLZ1 commented Oct 14, 2022

地址

线上地址:https://maxlz1.github.io/micro-app-demos/qiankun-demo/vue3-main/
仓库地址:https://github.com/MAXLZ1/micro-app-demos/tree/main/packages/qiankun-demo

简介

主应用为vue3 + vite,子应用为vue2 + vue clireact18 + webpackreact18 + vite。其中react18 + webpack会作为主应用动态加载vue2 + vue cli应用或react18 + vite应用。

其中vite子应用使用vite-plugin-qiankun进行接入。

功能列表

  • 应用间通信(利用CustomEvent
  • 多个子应用共存
  • CSS隔离
  • 主子应用间跳转
  • 嵌套子应用
  • 资源预加载
  • 子应用保活
  • 接入vite子应用

@RainManGO
Copy link

地址:react演示地址

简介:主应用react18、子应用react18都支持缓存

仓库地址是什么看看一看。

@Aaron52077
Copy link

地址:react演示地址
简介:主应用react18、子应用react18都支持缓存

仓库地址是什么看看一看。

暂未开源,完善中

@wjm0913
Copy link

wjm0913 commented Nov 13, 2022

地址:react演示地址
简介:主应用react18、子应用react18都支持缓存

仓库地址是什么看看。

暂未开源,完善中
期待啊

@CurrrryChen
Copy link

nuxtjs v2作为主应用接入qiankun的demo,附接入过程中的注意事项:
nuxtjs-qiankun-demo

@athrunsun
Copy link

@CurrrryChen 请问主应用使用nuxt算是SSR吗?(其实我就是想问qiankun的主应用现在到底支不支持SSR)

@xuanxuan321
Copy link

地址:https://github.com/gongshun/qiankun-vue-demo

介绍:主子应用都是 vue 技术栈,在常规使用的基础上实现了:tab 标签页效果、应用之间的组件共享、依赖共享、子应用是 vite 构建 的等效果(代码在不同的分支)
我有两个vue应用A和B,用了qiankun这个微前端框架,A作为主应用,B作为子应用,主子应用本地启动时所在的端口号不一样,导致子应用的hmr不生效,请问该怎么处理

@wys0529
Copy link

wys0529 commented Mar 2, 2023

@PandaSususu
Copy link

地址:react演示地址
简介:主应用react18、子应用react18都支持缓存

仓库地址是什么看看一看。

暂未开源,完善中
大佬,过去一年时间了,可以考虑开源了吗?😊

@Caesar-APAX
Copy link

@PandaSususu 我实现了他的代码,不需要付费哈

@liu-collab
Copy link

@PandaSususu 我实现了他的代码,不需要付费哈

可以发个地址学习一下嘛

@razr001
Copy link

razr001 commented Aug 20, 2023

受qiankun启发,根据其原理做的可视化平台
https://github.com/drinkjs/mojito

@sansui-orz
Copy link

仓库地址: https://github.com/sansui-orz/qiankun-admin
使用qiankun 2.10.13,主应用使用webpack5 + react18,子应用1使用vite + react18, 子应用2使用vite + vue3.

支持:

  1. 模块联邦
  2. 页面tabs缓存
  3. 主应用全局状态管理
  4. 基础中后台逻辑(登录退出,基础图表等)

期待star~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests