micro-zoe / micro-app

A simple, efficient and powerful micro front-end framework. 一款简约、高效、功能强大的微前端框架
https://micro-zoe.github.io/micro-app/
MIT License
5.62k stars 571 forks source link

主应用和子应用同时使用antd,子应用style插入顺序问题 #1142

Open QJvic opened 7 months ago

QJvic commented 7 months ago

问题描述

问题的具体描述

issue https://github.com/micro-zoe/micro-app/issues/1071 同一问题。 经过上述issue的修复后,主应用不使用antd,子应用使用antd没有问题。 主应用、子应用同时使用antd后,子应用style插入顺序与上述issue相同,导致样式出现问题。

复现步骤

  1. 主应用使用antd
  2. 子应用使用antd

上传截图

请上传代码截图、控制台、终端等截图以帮助我们了解您的问题。

复现仓库

请提供一个精简的代码仓库,然后上传到自己的 github,以帮助我们复现您的问题。

环境信息

AmorDiamond commented 7 months ago

我也遇到相似的问题,第一次进入页面,会在加载的css类名前加上子应用name属性前缀,但是跳转进入其他页面后再返回该页面,就没有加上name属性前缀了

第一次进入页面加载的样式

image

进入其他页面再返回后设置的样式

image

在控制台能看到它是被更新成了没有name属性前缀的,导致子应用样式权重变低,样式被主应用影响。

QJvic commented 7 months ago

我也遇到相似的问题,第一次进入页面,会在加载的css类名前加上子应用name属性前缀,但是跳转进入其他页面后再返回该页面,就没有加上name属性前缀了

第一次进入页面加载的样式

image

进入其他页面再返回后设置的样式

image

在控制台能看到它是被更新成了没有name属性前缀的,导致子应用样式权重变低,样式被主应用影响。

你这个和当前issue不是同一问题,但是我也遇到了。 我通过以下方法临时解决: 在scoped_css.ts中,添加方法

export function scopedCssText(cssText: string, appName: string): string{
  if (!parser) parser = new CSSParser();

  let result: string | null = null;
  const prefix = createPrefix(appName);

  try {
    result = parser.exec(
      cssText,
      prefix,
      '',
    )
    parser.reset()
  } catch (e) {
    parser.reset()
    logError('An error occurred while parsing CSS:\n', appName, e)
  }

  return result || ''
}

在element.ts中,大概174行左右,

rawDefineProperty(microRootElement.prototype, 'innerHTML', {
    configurable: true,
    enumerable: true,
    get () {
      return rawInnerHTMLDesc.get!.call(this)
    },
    set (code: string) {
      /* --  新增代码开始 --*/
      // 针对antd的动态style进行处理
      if(isStyleElement(this) && this?.hasAttribute('data-rc-order')) {
        // antd cssinjs 会更新style节点,更新后会把css的scope去掉
        // 这里进行判断,如果要更新的内容加上scope后和原来一样,则不更新
        if(this.textContent === scopedCssText(code, appName)) return;
      }
      /* --  新增代码结束 --*/

      rawInnerHTMLDesc.set!.call(this, code)
      Array.from(this.children).forEach((child) => {
        if (isElement(child)) {
          updateElementInfo(child, appName)
        }
      })
    }
  })
QJvic commented 7 months ago

当前issue,通过以下方法临时解决。 在path.ts中,大概145行,

function invokePrototypeMethod (
  app: AppInterface,
  rawMethod: Func,
  parent: Node,
  targetChild: Node,
  passiveChild?: Node | null,
): any {
  const hijackParent = getHijackParent(parent, targetChild, app)
  if (hijackParent) {
     /* --  新增代码开始 --*/
    // 针对antd的动态style进行处理
    if(isStyleElement(targetChild) && targetChild?.hasAttribute('data-rc-order')) {
      if( passiveChild && hijackParent.contains(passiveChild)){
        return invokeRawMethod(rawMethod, hijackParent, targetChild, passiveChild)
      } else {
        return invokeRawMethod(rawMethod, hijackParent, targetChild, hijackParent.firstChild)
      }
    }
   /* --  新增代码结束 --*/
AmorDiamond commented 6 months ago

我也遇到相似的问题,第一次进入页面,会在加载的css类名前加上子应用name属性前缀,但是跳转进入其他页面后再返回该页面,就没有加上name属性前缀了 第一次进入页面加载的样式 image 进入其他页面再返回后设置的样式 image 在控制台能看到它是被更新成了没有name属性前缀的,导致子应用样式权重变低,样式被主应用影响。

你这个和当前issue不是同一问题,但是我也遇到了。 我通过以下方法临时解决: 在scoped_css.ts中,添加方法

export function scopedCssText(cssText: string, appName: string): string{
  if (!parser) parser = new CSSParser();

  let result: string | null = null;
  const prefix = createPrefix(appName);

  try {
    result = parser.exec(
      cssText,
      prefix,
      '',
    )
    parser.reset()
  } catch (e) {
    parser.reset()
    logError('An error occurred while parsing CSS:\n', appName, e)
  }

  return result || ''
}

在element.ts中,大概174行左右,

rawDefineProperty(microRootElement.prototype, 'innerHTML', {
    configurable: true,
    enumerable: true,
    get () {
      return rawInnerHTMLDesc.get!.call(this)
    },
    set (code: string) {
      /* --  新增代码开始 --*/
      // 针对antd的动态style进行处理
      if(isStyleElement(this) && this?.hasAttribute('data-rc-order')) {
        // antd cssinjs 会更新style节点,更新后会把css的scope去掉
        // 这里进行判断,如果要更新的内容加上scope后和原来一样,则不更新
        if(this.textContent === scopedCssText(code, appName)) return;
      }
      /* --  新增代码结束 --*/

      rawInnerHTMLDesc.set!.call(this, code)
      Array.from(this.children).forEach((child) => {
        if (isElement(child)) {
          updateElementInfo(child, appName)
        }
      })
    }
  })

感谢分享方案,该方法的确可以解决目前我这个问题👍👏❤️

@bailicangdu 你好,请问有计划对这个问题优化吗? 你提供的在invokePrototypeMethod方法里添加的修复代码对我这个情况无效😭

"@micro-zoe/micro-app": "1.0.0-rc.4" 子应用使用的ant-design版本信息: "antd": "4.24.15" "@ant-design/pro-components": "2.6.42"

Jennylx commented 6 months ago

我这边也遇到了这个问题(第一次进入页面,会在加载的css类名前加上子应用name属性前缀,但是跳转进入其他页面后再返回该页面,就没有加上name属性前缀了),主应用:vue2+element,子应用:vue3+element-plus。

pegmca commented 2 months ago

主应用vue3+vite+elementplus 子应用react+vite+antd 同样的问题