自造微前端

起因是,我要在一个大型后台管理应用中剥离出一个管理模块,这样做的好处当然是可以单独开发和发布,但是坏处也有,比如部分全局变量污染,UI不一致,状态通信传导等。虽然市面上已经有很多微前端方案了,比如qiankun等,但是这都需要对这个大仓库应用进行大动工,对原应用造成一些负载和可能意想不到的错误,非我所愿也,所以在这里我打算自己搞个简化的方案。 原应用是react+dva,

基座应用改造

我们设计的主应用核心是;

  1. 主应用不直接打包子应用的代码,而是运行时按需加载子应用的 JS 资源。
  2. 将子应用的路由注册到主应用的路由系统中,实现无缝跳转。
  3. 通过全局变量(window)共享库,避免重复加载,也可形成单例。 我们先改造子应用路由代码,为了解决刚才说的UI和一些重要库不一致问题,我们将直接暴露库到Window中,有:
  4. antd
  5. React主库 另外状态通信的问题,我们直接使用dva去修饰取得的子应用Com,并把部分方法如connect暴露到window中。

代码如下

ini 复制代码
import React from 'react';
import {
  Alert,
  Drawer,
} from 'antd';
import { connect } from 'dva';

window.React = React;
window.CONNECT = connect;
window.Antd_ZI = {
  Drawer,
  Alert,
};

const configUrl = {
  test: 'https://zi.test.cn',
  product: 'https://zi.prod.com',
};

const env = 'product';

const mapStateToProps = (state) => {
  const currentState = state.adManage;
  const { userAuth, userInfo } = state.app;
  return { ...currentState, userAuth, userInfo };
};

const insertScript = (e, isStyle = false) => {
  return new Promise((reslove, reject) => {
    const i = isStyle ? document.createElement('link') : document.createElement('script');
    isStyle || i.setAttribute('type', 'text/javascript');
    isStyle || i.setAttribute('src', e);
    isStyle && i.setAttribute('href', e);
    isStyle && i.setAttribute('rel', 'stylesheet');
    isStyle && i.setAttribute('type', 'text/css');
    function onload() {
      if (!(this.readyState && this.readyState !== 'loaded' && this.readyState !== 'complete')) {
        i.onload = null;
        i.onreadystatechange = i.onload;
        reslove();
      }
    }
    function onerror(ee) {
      reject(ee);
    }
    i.onreadystatechange = onload;
    i.onload = onload;
    i.onerror = onerror;
    document.querySelector('head').appendChild(i);
  });
};

function ERROR() {
  return '加载静态资源失败,请稍后重试';
}

const subappRoutes = [];

const AyncComponent = async (pathname) => {
  const id = pathname;
  // 子工程资源是否加载完成
  let ayncLoaded = false;
  if (subappRoutes[id]) {
    // 如果已经加载过该子工程的模块,则不再加载,直接取缓存的routes
    ayncLoaded = true;
  } else if (window.ziPLATFORMSLOT && window.ziPLATFORMSLOT[pathname]) {
    const res = await window.ziPLATFORMSLOT[pathname]();
    subappRoutes[id] = res.default;
    ayncLoaded = true;
    // return subappRoutes[id];
  } else {
    try {
      await insertScript(`${configUrl[env]}/js/index.js?_=${new Date().getTime()}`);
      if (window.ziPLATFORMSLOT && window.ziPLATFORMSLOT[pathname]) {
        const res = await window.ziPLATFORMSLOT[pathname]();
        subappRoutes[id] = res.default;
        ayncLoaded = true;
      }
    } catch (error) {
      console.log('加载js失败', error);
    }
  }
  return ayncLoaded ? connect(mapStateToProps)(subappRoutes[id]) : ERROR;
};

export default [
  {
    name: '资源管理',
    path: 'ziMedia',
    component: () => AyncComponent('ziMedia'),
  },
  {
    name: '黑名单管理',
    path: 'ziBlack',
    component: () => AyncComponent('ziBlack'),
  },
];

子应用改造

子应用中,入口文件我们需要定义publicPath保证资源的正确引用

javascript 复制代码
const configUrl = {
  test: 'https://zi.test.cn',
  product: 'https://zi.prod.com',
};

const env = 'product';
// webpack 的魔法变量,用于指定异步加载的 JS/CSS 文件的基地址(如 `import()` 动态导入的模块)
__webpack_public_path__ = `${configUrl[env]}/js/`;

const routes = {
  version: '1.0.0',
  ziMedia: () => import('./ziMedia/index'),
  ziBlack: () => import('./ziBlack/index'),
};

export default routes;

在子应用的页面中,我们基本不需要做改造,但是在webpack的配置中,我们在base中需要:

css 复制代码
{
    ...
    output:{
        ...
          libraryExport: 'default',
          library: 'ziPLATFORMSLOT',
          libraryTarget: 'umd',
          umdNamedDefine: true,
    },
    externals: {
      'react': 'React',
      'antd': 'Antd_ZI',
      // 'react-dom':'ReactDOM'
    }
}

在prod配置中,为了保证子js能正确加载执行,我们使用InlineChunkHtmlPlugin插件,避免微前端环境下因路径问题导致运行时脚本加载失败。 至此,完成。

相关推荐
毕设源码-郭学长2 小时前
【开题答辩全过程】以 基于Web的文档管理系统的设计与实现为例,包含答辩的问题和答案
前端
Rhys..2 小时前
Playwright + JS 进行页面跳转测试
开发语言·前端·javascript
We་ct2 小时前
LeetCode 135. 分发糖果:双向约束下的最小糖果分配方案
前端·算法·leetcode·typescript
Yan.love2 小时前
【CSS-核心属性】“高频词”速查清单
前端·css
广州华水科技2 小时前
如何通过GNSS位移监测提升单北斗变形监测系统的精度与应用效果?
前端
郭优秀的笔记3 小时前
html鼠标悬浮提示功能
android·javascript·html
慧一居士3 小时前
npm install 各参数使用说明, 和使用场景说明
前端
冰暮流星3 小时前
if与switch的区分
javascript
小二·3 小时前
Python Web 开发进阶实战:神经符号系统 —— 在 Flask + Vue 中融合深度学习与知识图谱
前端·python·flask
Yan.love3 小时前
【CSS-动画与过渡】丝滑的艺术,从简单位移到贝塞尔曲线
前端·css