如何实现模块化加载的前端和后端代码?

2025 年 8 月 14 日
 llej

首先我定义一下我这里的模块概念:一个文件夹下的代码(也就是前端的话可能涉及多个页面以及组件等,后端同理)

其实如果只是追求打包时动态加载不同的模块是很简单的,通过环境变量约束一下打包工具即可

但我还想要有强类型支持,以及直接剪切文件夹就能新增和移除模块。

架构畅想

  1. 使用 MonoRepo 的形式进行项目管理

  2. 每个顶级模块(包)都可能包含一个后端模块和一个前端模块(也就是可以是单纯的前端模块或后端模块)

  3. 存在一个基座包,这是整个项目的核心,所有的其他包都会依赖这个

  4. 非基座包的后端模块和前端模块都能直接引用到基座包中的后端依赖和前端依赖,而不需要特别专门的配置

  5. 同一个包内的前端模块可以直接引用到后端模块的 api (强类型)以及其他包的后端模块的 api

  6. 所有包的后端模块都能直接声明需要的 context ,然后编译时能够感知到基座包是否兜底的提供了所有 context (即编译时能够报错某个 context 缺失)

    1. 为什么基座包需要兜底:因为是从基座包启动的 http server ,他是入口也是出口
  7. 可以直接剪切文件夹就能新增包和移除包,如果包之间有依赖但对应的包被移除了则编译时应该报错

如何实现?

期待各位朋友的指点(❁´◡`❁)

4707 次点击
所在节点    程序员
28 条回复
JoeJoeJoe
2025 年 8 月 14 日
可以搜一下 python 的一个 erp 框架 叫 Odoo , 跟你说的有些差异 但是他的模块化做的很好
tcper
2025 年 8 月 14 日
你说的目录是源码结构,最终打包结构和源码显然不是一回事,严重怀疑没做过真实项目才有这种设想
layxy
2025 年 8 月 14 日
前端可以通过微前端实现,后端 java 倒是可以通过插件实现
sentinelK
2025 年 8 月 14 日
所以楼主说的和 jar 、dll 的引用,以及 js 的 import 有啥区别?
楼主的意思是不想改配置?

那你直接把你项目 src 中的某个文件夹、dll 、jar 直接删了不就行了……
直接删了,IDE 直接标红,就满足了楼主说的“如果包之间有依赖但对应的包被移除了则编译时应该报错”
llej
2025 年 8 月 14 日
@tcper 因为我需要分发源码给不同的客户,我不希望他们能得到全部的模块源码,我想只给他们定制的功能需要的模块部分
wn990916
2025 年 8 月 14 日
根据不同的用户构建不同的版本呢?
llej
2025 年 8 月 14 日
@sentinelK 是的,我不想改配置,所以我需要实现,copy 一个模块的文件夹进来(包含了对应模块的前端和后端代码)然后直接就能运行项目,前端路由这块我已经实现可以这样加载了,但是后端还没搞定,主要是我想要 ts 类型严谨,否则我直接 require 也能实现
llej
2025 年 8 月 14 日
@wn990916 比如老用户之前用的老模块,那就不用管呀,接着用老的就行了
sentinelK
2025 年 8 月 14 日
@llej 那不是应该从 Git 管理的角度入手吗。每个用户是不同的 Git 分支。否则你如何做后续支持?每次支持难道你都要“手动删除文件夹”到和用户环境一致的程度吗
weixind
2025 年 8 月 14 日
前端没那么复杂,使用文件路由就可以了。

文件路由打包的时候就是先读取你的文件夹,动态生成路由文件。

node 的后端也可以用同样的方式处理,但是不一定有现成的方案。其他语言的后端不清楚。

可以搜一下哪些 router 方案支持文件路由。要自己写的话可以参考 taro 的 h5 方案。
llej
2025 年 8 月 14 日
@sentinelK 我会有一个环境变量文件的,比如 用户 a.env 的是包含了模块 a 模块 b ,那么我的脚本打包的时候就只包含这两,也有脚本一键导出只包含这两模块的源码发给他(有很多用户就是想要源码,我提供源码也可以跟他要价更高一些)

不使用 git 分支管理不同用户(因为我在实现某个用户的功能的时候可能又改善了某些通用模块,那么我不停切换分支来修改合并代码太麻烦了)
llej
2025 年 8 月 14 日
@weixind 嗯嗯,前端我已经实现了,现在就是 node 我想实现 ts 类型严谨,还没想出好办法
Ketteiron
2025 年 8 月 14 日
@llej node 实现 ts 类型严谨具体是指什么,是前端调用了不存在的接口就类型报错吗,调用对应接口拿到入参类型和返回类型?
你可以看一下 tPRC ,或者 hono 的 RPC ,虽然重构的工作量可能会很大。
hono 的 RPC 是后端导出一个或者多个路由实例类型给前端使用,客户端底层是基于 fetch 实现,前端调用这个接口就像直接调用后端接口方法一样,带来的收益是无需专门为接口类型定义一堆的类型到处混乱地引用,因为接口本身已经有类型了。
在你这个场景下,可以每个模块都导出一个路由实例,最后在基座包组装所有路由,再把类型导入到前端,最终得到包含所有接口路径、入参、返回类型的一个 http 客户端,前端只需要调用这个客户端就行,不存在的接口或者入参不对都会报错。你也可以让一部分路由只给同个顶级包下的前端模块引用,这样就实现了或许会用到的接口 public/private 修饰功能。
zhuangzhuang1988
2025 年 8 月 14 日
学习下 kibana , 就是要系统的设计才行。

举例 https://github.com/elastic/kibana/tree/main/x-pack/examples/alerting_example
flytsuki
2025 年 8 月 14 日
要不试试代码存数据库,启动项目时再编译
SorcererXW
2025 年 8 月 14 日
后端为啥要模块化加载,都部署不就好了吗,能差多少呢,对应模块没有流量也没啥开销
crysislinux
2025 年 8 月 14 日
https://nx.dev/ 看看这个呢。一个组件也可以是一个 package ,你想分多细分多细。也不用分前端还是后端,只要 package 没有平台依赖的代码就随便用。
realJamespond
2025 年 8 月 14 日
每个用户建一个 git 仓库包含对应模块 git submodules 的库
neoblackcap
2025 年 8 月 14 日
后端不就是动态加载嘛,你完全可以将模块写成独立的 dll, so 文件,然后自己写一个 loader 在程序启动的时候载入这些模块。
对应做法就是,一个程序许可证( license )可以解码出对应的权限以及模块清单,然后运行时根据这个清单去查找对应的模块并载入就可以了
yandif
2025 年 8 月 14 日
试一下 elysia.js ,https://elysiajs.com/at-glance.html
截屏 2025-08-14 13.55.12.png
这个后端框架有个 eden 功能实现了这个强类型

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1152245

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX