做后台系统别再只会单体架构了,微前端才是更优解

在后台系统开发领域,传统的单体架构已经无法满足现代企业的复杂需求。本文将深入探讨为什么微前端架构是后台系统的更优选择,并通过一个完整的开源项目案例,展示如何构建高性能、可扩展的微前端后台系统。

前言:单体架构的那些坑

说实话,做后台系统开发这么多年,单体架构的痛点真是深有体会:

  • 代码耦合严重:多个业务模块混杂在一起,修改一个功能可能影响到其他模块
  • 代码无法隔离:所有代码都在一个仓库中,无法进行物理隔离,权限管理困难
  • 构建速度缓慢:随着业务增长,项目体积越来越大,构建时间从几分钟到十几分钟不等
  • 技术栈锁定:整个项目被限制在单一技术栈,无法灵活选择最适合的技术方案
  • 团队协作困难:多人同时开发时,代码冲突频发,发布需要协调所有模块
  • 部署风险高:任何小改动都需要重新部署整个应用,风险巨大

这些问题的根源在于传统的单体架构模式。在单体架构中,所有的业务功能都被打包在一个巨大的代码库中,就像一个臃肿的巨人,行动迟缓且容易摔倒。

微前端:一种可行的解决方案

微前端(Micro Frontends)把前端应用拆分成多个小型、独立的部分。每个部分都能独立开发、测试、部署,最后组合成一个完整的应用。

这样做的好处很明显:

  • 独立部署:改一个模块不用重新发布整个系统
  • 团队自治:每个团队管好自己的模块就行
  • 渐进迁移:不用一次性重写,可以慢慢来
  • 故障隔离:一个模块崩了不会拖垮整个应用

一个实际案例:PbstarAdmin

为了让大家看看微前端在后台系统中怎么用,我分享一下最近做的一个项目 ------ PbstarAdmin

这个项目用到了腾讯的 wujie 微前端框架,解决了一些实际开发中的痛点。

代码隔离这块是怎么做的?

PbstarAdmin 用了一个比较实用的办法:Git子模块 + Rsbuild构建 双重隔离。

Git子模块隔离

简单说就是把代码分成两类:

  • 内部子应用 :放在主仓库的 apps/ 目录下,适合核心业务,改起来方便
  • 外部子应用:用Git子模块管理,完全独立的仓库,适合第三方模块或者需要权限控制的代码

Rsbuild构建隔离

每个子应用都有自己的构建配置:

  • 独立的构建配置和输出目录
  • 子应用之间没有依赖耦合
  • 可以独立部署和版本管理

这样做的好处是实实在在的:不同团队负责不同模块,互不干扰;出问题也容易定位。

项目特色

PbstarAdmin 这个项目主要解决了几个实际问题:

  • 微前端架构:用腾讯 wujie 框架,支持动态加载子应用
  • 模块化设计:pnpm monorepo 管理,支持内外部子应用
  • 组件复用:共享组件库,统一别名引用
  • 工程化工具:CLI 工具链简化开发流程
  • 高性能构建:基于 Rsbuild,支持多环境配置

技术选型

技术选型比较务实,都是现在主流的方案:

  • Vue 3: Composition API 开发体验不错
  • Pinia:状态管理比 Vuex 简洁
  • Element Plus:组件库成熟稳定
  • Rsbuild:基于 Rspack,构建速度很快
  • pnpm:monorepo 管理很方便
  • wujie:腾讯的微前端方案,相对成熟

架构设计

项目结构

整个项目结构比较清晰:

perl 复制代码
pbstar-admin/
├── main/                      # 主应用(基座)
├── apps/                      # 子应用目录
│   ├── app-common/            # 公共子应用模块
│   ├── system/                # 系统管理应用
│   ├── example/               # 示例应用
│   ├── equipment/             # 设备管理应用(外部子应用)
│   └── apps.json              # 子应用配置
├── components/                # 共享组件库
├── assets/                    # 共享资源
└── tools/                     # 工具模块(CLI)

微应用配置

apps/apps.json 中配置各个微应用的信息:

json 复制代码
[
  {
    "key": "system",
    "devPort": 8801,
    "proUrl": "http://pbstar-admin-system.pbstar.cn/"
  },
  {
    "key": "example",
    "devPort": 8802,
    "proUrl": "http://pbstar-admin-example.pbstar.cn/"
  },
  {
    "key": "equipment",
    "devPort": 8803,
    "proUrl": "http://pbstar-admin-equipment.pbstar.cn/"
  }
]

主应用核心代码

主应用负责整体布局、导航菜单管理和微应用加载:

javascript 复制代码
// main/src/stores/apps.js
export const useAppsStore = defineStore("apps", () => {
  const myApps = ref([]); // 存储用户的应用
  const appId = ref(0); // 存储当前激活的应用

  const setApps = (apps) => {
    myApps.value = apps.map((item) => {
      return {
        id: item.id,
        key: item.key,
        name: item.name,
        icon: item.icon,
        group: item.group,
        navs: [],
        navsTree: [],
      };
    });
  };

  const setAppId = async ({ id, key }) => {
    let aId = 0;
    if (id) {
      aId = id;
    } else if (key) {
      const app = myApps.value.find((item) => item.key === key);
      if (app) aId = app.id;
    }
    if (aId) {
      const navRes = await request.get({
        url: "/main/getMyNavListByAppId",
        data: { appId: aId },
      });
      if (navRes.code !== 200) {
        ElMessage.error("获取应用导航失败!请稍后重试");
        return false;
      }
      setAppNavs(aId, navRes.data);
    }
    appId.value = aId;
    return true;
  };

  return {
    appId,
    setApps,
    setAppId,
    getApp,
    getApps,
    hasAppNav,
  };
});

导航菜单管理

javascript 复制代码
// main/src/components/layout/layout.js
export function useNavMenu() {
  const router = useRouter();
  const route = useRoute();
  const appsStore = useAppsStore();

  const activeIndex = ref("1");
  const list = ref([]);
  const listTree = ref([]);

  const updateNavData = () => {
    if (appsStore.appId) {
      const app = appsStore.getApp();
      if (!app) return;
      list.value = app.navs;
      listTree.value = app.navsTree;
    } else {
      list.value = [
        {
          id: 1,
          name: "首页",
          url: "/admin/pHome",
          icon: "el-icon-house",
        },
      ];
      listTree.value = list.value;
    }
  };

  const selectNav = (val) => {
    activeIndex.value = val;
    const url = list.value.find((item) => item.id.toString() === val)?.url;
    if (url) {
      router.push(url);
    }
  };

  return {
    listTree,
    activeIndex,
    selectNav,
    updateNavData,
    updateActiveIndex,
  };
}

构建配置

使用 Rsbuild 进行高性能构建配置:

javascript 复制代码
// rsbuild.config.mjs
export default defineConfig({
  plugins: [pluginVue(), pluginSass(), distZipPlugin()],
  output: { legalComments: "none" },
  resolve: {
    alias: {
      "@Pcomponents": "./components",
      "@Passets": "./assets",
    },
  },
  server: {
    proxy: {
      "/api": {
        target: import.meta.env.PUBLIC_API_BASE_URL,
        pathRewrite: { "^/api": "" },
        changeOrigin: true,
      },
    },
  },
  environments: {
    main: mainConfig,
    ...Object.fromEntries(apps.map((app) => [app.key, createAppConfig(app)])),
  },
});

CLI 工具开发

提供完整的 CLI 工具链,简化开发流程:

javascript 复制代码
// tools/cli/dev.mjs
const list = ["main", ...apps.map((item) => item.key)];

program
  .version("1.0.0")
  .description("启动应用模块")
  .action(async () => {
    try {
      const answers = await inquirer.prompt([
        {
          type: "list",
          name: "appKey",
          message: "请选择要启动的应用模块:",
          choices: list,
        },
      ]);
      const { appKey } = answers;
      // 构建启动命令
      let command = "";
      if (appKey === "main") {
        command = "rsbuild dev --environment main --port 8800 --open";
      } else {
        const app = apps.find((item) => item.key === appKey);
        command = `rsbuild dev --environment ${appKey} --port ${app.devPort}`;
      }
      execSync(command, { stdio: "inherit", cwd: "../" });
    } catch (err) {
      console.error(chalk.red("Error:"), err);
      process.exit(1);
    }
  });

代码隔离的终极解决方案

传统方案的局限性

之前用过一些微前端方案,发现隔离做得并不好:

  • 代码都在一起:所有子应用代码混在一个仓库,权限控制很麻烦
  • 依赖经常冲突:这个子应用要Vue3,那个要Vue2,构建时各种问题
  • 构建互相影响:一个子应用构建失败了,整个项目都跑不起来
  • 版本管理混乱:没法单独给某个业务模块打版本标签

PbstarAdmin的双重隔离机制

PbstarAdmin 用了 Git子模块 + Rsbuild构建 的双重隔离,算是把代码隔离做到了物理层面。

1. Git子模块隔离

bash 复制代码
# .gitmodules 配置,其实就是普通的git子模块
[submodule "apps/equipment"]
	path = apps/equipment
	url = https://github.com/pbstar/pbstar-admin-quipment.git

内部子应用(in类型)

  • 代码放在主仓库里,适合核心业务
  • 团队协作方便,代码复用容易
  • 构建起来也快

外部子应用(out类型)

  • 用Git子模块管理,完全独立的仓库
  • 适合业务团队或者需要保密的模块
  • 版本控制完全独立

2. Rsbuild构建隔离

javascript 复制代码
// rsbuild.config.mjs - 给每个子应用单独的配置
const createAppConfig = (app) => {
  const basePath = `./apps/${app.key}`;
  return {
    source: {
      entry: { index: `${basePath}/src/main.js` },
    },
    output: {
      distPath: { root: `./build/dist/${app.key}` },
    },
    resolve: {
      alias: {
        "@": basePath + "/src",
      },
    },
    plugins: [
      checkUniqueKeyPlugin({
        checkPath: `${basePath}/src`,
        checkKeys: ["btnkey"],
      }),
    ],
  };
};

子应用创建流程

javascript 复制代码
// tools/cli/create.mjs - 智能创建子应用
const answers = await inquirer.prompt([
  {
    type: "list",
    name: "appType",
    message: "子应用类型:",
    choices: ["in", "out"],
  },
  {
    type: "input",
    name: "appKey",
    message: "子应用Key:",
    validate: (input) => {
      if (!/^[a-z0-9-]+$/.test(input)) {
        return "子应用Key只能包含小写字母、数字和连字符";
      }
      return true;
    },
  },
]);

// 外部子应用就加个git子模块
if (appType === "out" && gitUrl) {
  execSync(`git submodule add ${gitUrl} apps/${appKey}`, {
    cwd: path.join(__dirname, "../../"),
    stdio: "inherit",
  });
}

代码隔离的实际效果

用了双重隔离后,确实比传统单体架构方便不少:

权限管理

  • 仓库级别权限:外部子应用可以单独设置Git权限
  • 代码审查隔离:每个子应用可以有自己的Code Review流程
  • 敏感代码保护:核心业务代码可以放在内部子应用中

依赖管理

javascript 复制代码
// 每个子应用可以有自己的依赖,不会冲突
{
  "name": "system-subapp",
  "dependencies": {
    "vue": "^3.5.18",
    "element-plus": "^2.10.7",
    // 子应用特定的依赖
    "echarts": "^5.4.0"
  }
}

// 另一个子应用可以用不同版本
{
  "name": "equipment-subapp",
  "dependencies": {
    "vue": "^3.5.18",
    "element-plus": "^2.8.0",
    "echarts": "^4.9.0"  // 版本不一样,但不会冲突
  }
}

独立部署

bash 复制代码
# 用ptools构建指定子应用(推荐)
pnpm run build
# 选择要构建的子应用,比如equipment

Ptools:CLI工具链

PbstarAdmin 还有个特色是 Ptools - 一套CLI工具链,把复杂的构建流程都封装起来了。

Ptools的核心命令

bash 复制代码
# 启动开发环境 - 会让你选择子应用
pnpm run dev

# 构建指定子应用 - 交互式选择
pnpm run build

# 创建新的子应用 - 引导式创建
pnpm run create

# 添加依赖包 - 精确到具体工程
pnpm run add

# 移除依赖包 - 清理依赖
pnpm run remove

为什么用Ptools而不是直接敲命令

直接敲命令的问题

bash 复制代码
# 要记住复杂的命令和参数
rsbuild build --environment equipment --port 8803

# 容易敲错,还得手动指定端口和环境
rsbuild dev --environment system --port 8801

Ptools的交互方式

javascript 复制代码
// tools/cli/build.mjs - 构建命令其实就是帮你选一下
const list = ["main", ...apps.map((item) => item.key)];

program
  .version("1.0.0")
  .description("构建应用模块")
  .action(async () => {
    const answers = await inquirer.prompt([
      {
        type: "list",
        name: "appKey",
        message: "请选择要构建的应用模块:",
        choices: list, // 自动读取所有可用模块
      },
    ]);
    const { appKey } = answers;
    // 自动构建正确的环境和配置
    const command = `rsbuild build --environment ${appKey}`;
    execSync(command, { stdio: "inherit", cwd: "../" });
  });

Ptools的好处

  1. 不用记配置:开发者不用了解底层的Rsbuild配置
  2. 不会选错:自动发现可用的子应用,避免手打错误
  3. 统一入口:所有操作都通过统一的CLI,比较好记
  4. 减少出错:内置参数验证和错误处理
  5. 流程统一:确保团队成员用相同的流程

依赖管理

javascript 复制代码
// tools/cli/add.mjs - 添加依赖包
const answers = await inquirer.prompt([
  {
    type: "list",
    name: "appKey",
    message: "请选择要添加依赖包的工程:",
    choices: [
      "全局工程",
      "assets",
      "components",
      "tools",
      "main",
      ...apps.map((item) => item.key),
    ],
  },
  {
    type: "input",
    name: "packageName",
    message: "请输入要添加的依赖包名称:",
  },
  {
    type: "list",
    name: "packageType",
    message: "请选择要添加的依赖包类型:",
    choices: ["dependencies", "devDependencies"],
  },
]);

通过Ptools,PbstarAdmin把从创建到构建的流程都标准化了。

故障隔离

javascript 复制代码
// 子应用A构建出错了,不会影响子应用B
const appConfigs = {
  system: createAppConfig({ key: "system" }), // ✅ 正常构建
  equipment: createAppConfig({ key: "equipment" }), // ❌ 构建失败
  example: createAppConfig({ key: "example" }), // ✅ 不受影响
};

实际使用效果

开发体验

  • 独立开发:每个团队可以独立开发自己的微应用,互不干扰
  • 构建速度:单个微应用构建比整个项目快很多
  • 热更新:修改一个微应用不会影响其他应用,热更新很快

部署运维

  • 独立部署:每个微应用可以独立部署,降低风险
  • 灰度发布:支持微应用级别的灰度发布
  • 故障隔离:单个微应用出错不会影响整个系统

团队协作

  • 团队自治:每个团队负责自己的微应用,职责清晰
  • 技术选型自由:不同团队可以选择最适合的技术栈
  • 并行开发:多个团队可以并行开发,提高效率

快速开始

想要体验这个微前端后台系统?只需要简单的几步:

bash 复制代码
# 克隆项目
git clone https://github.com/pbstar/pbstar-admin.git

# 进入项目目录
cd pbstar-admin

# 克隆外部子应用仓库(可选)
git submodule update --init

# 安装依赖
pnpm install

# 使用Ptools启动开发环境(推荐方式)
pnpm run dev
# 交互式选择要启动的子应用

# 使用Ptools构建项目
pnpm run build
# 选择要构建的子应用

# 创建新的子应用
pnpm run create

# 添加依赖包
pnpm run add

# 移除依赖包
pnpm run remove

Ptools使用示例

bash 复制代码
# 开发环境 - 交互式选择子应用
$ pnpm run dev
? 请选择要启动的应用模块: (Use arrow keys)
❯ main
  system
  example
  equipment

# 构建指定子应用
$ pnpm run build
? 请选择要构建的应用模块: (Use arrow keys)
❯ main
  system
  example
  equipment

# 添加依赖包到指定工程
$ pnpm run add
? 请选择要添加依赖包的工程: (Use arrow keys)
❯ 全局工程
  assets
  components
  tools
  main
  system
  example
  equipment
? 请输入要添加的依赖包名称: axios
? 请选择要添加的依赖包类型: (Use arrow keys)
❯ dependencies
  devDependencies

总结

单体架构就像一搜巨大的航空母舰,虽然功能强大,但转向困难,维护成本高。而微前端架构就像一支现代化的舰队,每艘舰艇都有自己的使命,既能独立作战,又能协同配合。

通过 PbstarAdmin 的实践,我发现微前端在后台系统中的优势确实很明显:

  • 开发效率:构建速度快了很多,热更新基本是秒级
  • 部署运维:可以独立部署,不用每次都全量发布
  • 团队协作:各团队负责自己的模块,冲突少了很多
  • 系统稳定性:一个模块出问题不会拖垮整个系统

当然,微前端也有它的复杂性,比如通信机制、状态同步等问题。但总的来说,对于大型后台系统,微前端是一个值得考虑的方向。

如果你也在做后台系统,建议可以试试看微前端的思路,或许能解决你当前遇到的一些痛点。

相关资料

项目地址和文档都整理在这里了,有兴趣的可以看看:


💡 这里是初辰,一个有理想的切图仔!

🎉 如果本文对你有帮助,别忘了点赞、收藏、评论哦!

给项目点个Star,支持开源精神,让更多人发现这个优秀的微前端解决方案!

相关推荐
风止何安啊2 小时前
React 入门秘籍:像搭积木一样写网页,JSX 让开发爽到飞起!
前端·react.js·前端框架
whyfail2 小时前
React原理(暴力版)
前端·react.js
shoa_top2 小时前
一文带你掌握 JSONP:从 Script 标签到手写实现
前端·面试
Crazy_Urus2 小时前
深入解析 React 史上最严重的 RCE 漏洞 CVE-2025-55182
前端·安全·react.js
八荒启_交互动画2 小时前
【基础篇007】GeoGebra工具系列_多边形(Polygon)
前端·javascript
清风扶我腰_直上青天三万里2 小时前
vue框架无痛开发浏览器插件,好用!!本人使用脚手架开发了一款浏览器tab主页加收藏网址弹窗,以后可以自己开发需要的插件了!!
前端
知其然亦知其所以然2 小时前
小米的奇幻编程之旅:当 JavaScript 语法变成了一座魔法城
前端·javascript·面试
webkubor2 小时前
一次 H5 表单事故:100vh 在 Android 上到底坑在哪
前端·javascript·vue.js
是一碗螺丝粉2 小时前
突破小程序5层限制:如何用“逻辑物理分离”思维实现无限跳转
前端·架构