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

通过 reload(appName) 或者 unmountApp(appName) 之后再 renderApp 子应用挂载失败 #1338

Closed
bolawen opened this issue Aug 21, 2024 · 3 comments
Labels
common common question

Comments

@bolawen
Copy link

bolawen commented Aug 21, 2024

问题描述

在 "@micro-zoe/micro-app": "1.0.0-rc.6" 版本中, 主应用为 Vite + React , 一个子应用为 Vite + React, 一个子应用为 Vite + Vue3.0。需求是, vue 子应用通过 display: none 隐藏即可,但是 react 子应用想着重新渲染一下,这时候通过 reload(appName) 或者 unmountApp(appName) 之后再 renderApp React 都不大行,辛苦帮忙看看是什么情况呢?

具体复现步骤:

GitHub Demo 地址:https://github.com/bolawen/practice/tree/master/microApp
Demo 复现步骤:

  1. 启动 main - vite-react 主应用
  2. 启动 micro - vite-react 子应用
  3. 启动 micro - vite-vue3 子应用

浏览器访问 主应用,点击微应用列表,点击 vue 子应用,此时可以正常渲染 vue 子应用, 点击 react 子应用, 可以正常渲染 react 子应用,在点击 vue 子应用,然后再点击 react 子应用, 此时, react 子应用挂载失败, 可以看到 react 子应用的入口文件都不会执行

代码如下:

import "./MicroAppList.css";
import microApp from "@micro-zoe/micro-app";
import { useState, useEffect } from "react";
import { useNavigate, useLocation } from "react-router-dom";

const microApps = [
  {
    title: "Vue 子应用",
    name: "vite-vue-micro-app",
    url: "http://localhost:4008/",
  },
  {
    isReload: true,
    title: "React 子应用",
    name: "vite-react-micro-app",
    url: "http://localhost:4007/",
  },
];

function MicroAppList() {
  const navigate = useNavigate();
  const location = useLocation();
  const [activedTab, setActivedTab] = useState<string>("");
  const [tabs, setTabs] = useState<{ label: string; value: string }[]>([]);

  const normalizeMicroAppContainer = (name: string) => {
    return name + "__micro-app";
  };

  const renderMicroApp = (app: { url: string; name: string }) => {
    microApp.renderApp({
      url: app.url,
      destory: true,
      name: app.name,
      "disable-sandbox": true,
      container: `#${normalizeMicroAppContainer(app.name)}`,
    });
  };

  const handleActiveApp = async (name: string) => {
    const elName = normalizeMicroAppContainer(name);
    const el = document.getElementById(elName);

    if (!el) {
      return;
    }

    const allActiveApps = microApp.getActiveApps();
    const app = microApps.find((app) => app.name === name);
    const isHasAppOfTabs = tabs.find((tab) => tab.value === name);

    if (!app) {
      microApp.unmountAllApps();
      return;
    }

    if (isHasAppOfTabs && !app.isReload && allActiveApps.includes(name)) {
      return;
    }

    if (app.isReload) {
      await microApp.unmountApp(name);
      if (el) {
        el.innerHTML = "";
      }
    }

    renderMicroApp(app);
  };

  const handlePathChange = () => {
    const path = location.pathname.split("/").pop();
    const needActiveApp = microApps.find((app) => app.name === path);
    const isHasAppOfTabs = tabs.find((tab) => tab.value === path);

    if (needActiveApp) {
      if (!isHasAppOfTabs) {
        setTabs([
          ...tabs,
          {
            label: needActiveApp.title,
            value: needActiveApp.name,
          },
        ]);
      }

      setActivedTab(needActiveApp.name);
      return;
    }

    const defaultTab = microApps[0];
    setTabs([
      {
        label: defaultTab.title,
        value: defaultTab.name,
      },
    ]);
    handleActiveApp(defaultTab.name);
  };

  const onTabClick = (tab: { label: string; value: string }) => {
    navigate(`/micro-app-list/${tab.value}`);
  };

  const onMenuClick = (name: string) => {
    navigate(`/micro-app-list/${name}`);
  };

  useEffect(() => {
    handlePathChange();
  }, [location.pathname]);

  useEffect(() => {
    handleActiveApp(activedTab);
  }, [activedTab, tabs]);

  return (
    <div className="micro-app-list">
      <div className="menu">
        {microApps.map((app, index) => (
          <div className="menu-item" key={index}>
            <button onClick={() => onMenuClick(app.name)}>{app.title}</button>
          </div>
        ))}
      </div>
      <div className="content">
        <div className="tabs">
          {tabs.map((tab, index) => (
            <div
              key={index}
              className={`tab ${
                activedTab === tab.value ? "tab__active" : "tab__inactive"
              }`}
              onClick={() => onTabClick(tab)}
            >
              <div className="tab-item">{tab.label}</div>
            </div>
          ))}
        </div>
        <div className="micro-view-list">
          {tabs.map((tab, index) => {
            const app = microApps.find((app) => app.name === tab.value);

            if (!app) {
              return null;
            }

            return (
              <div
                key={index}
                className={`micro-view-item ${
                  activedTab === app.name
                    ? "micro-view-item__active"
                    : "micro-view-item__inactive"
                }`}
                id={normalizeMicroAppContainer(app.name)}
              ></div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

export default MicroAppList;

问题如下:

image

React 子应用 main.js 入口都不会重新执行,不知道为什么?

@bailicangdu
Copy link
Member

沙箱关闭导致的冲突,切换为iframe沙箱即可
image

@bailicangdu bailicangdu added the common common question label Aug 21, 2024
@bolawen
Copy link
Author

bolawen commented Aug 27, 2024

可是在 iframe: true 的情况下,子应用中的 (window as any).microEventCenterForCommonApp 是 undefined ? 这是为什么呢?

@bailicangdu
Copy link
Member

可是在 iframe: true 的情况下,子应用中的 (window as any).microEventCenterForCommonApp 是 undefined ? 这是为什么呢?

这个代码microEventCenterForCommonApp 是给关闭沙箱时用的,iframe沙箱正常使用数据通信就行

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

No branches or pull requests

2 participants