别把“模块化启动模板”当 Composer 包发布,否则扩展性会随依赖爆炸而崩塌;真正高可用的分发方式是「主干模板 + path 仓库 + 运行时加载」三件套。

直接结论:别把“模块化启动模板”当 Composer 包发布,否则扩展性会随依赖爆炸而崩塌;真正高可用的分发方式是「主干模板 + path 仓库 + 运行时加载」三件套。
为什么用 composer create-project 发布模块化模板容易翻车
很多人误以为把一个含多个 modules/ 目录的项目 push 到 GitHub、提交到 Packagist,再用 composer create-project 拉下来就叫“模块化脚手架”。实际踩坑点密集:
- 一旦某个租户模块加了私有 Git 依赖(如
"private-vendor/tenant-b": "dev-main"),create-project在 CI 环境里会卡在 SSH 凭据或 token 认证上,根本跑不完 -
post-create-project-cmd脚本只能执行一次,但模块启用/禁用是运行时行为——你没法靠一次初始化就覆盖所有租户组合 - 所有模块代码被静态拷贝进新项目,后续升级靠手动 diff 或 patch,违背“可维护即高可用”的前提
- 若模板中用了
autoload-dev加载测试类,--no-dev又会把本该保留的模块初始化逻辑也干掉
path 仓库 + require 是唯一可控的模块接入方式
真正的扩展性来自“不打包、只链接”。你在主模板的 composer.json 里这样写:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
{
"repositories": [
{
"type": "path",
"url": "./modules/order"
},
{
"type": "path",
"url": "./modules/notification"
}
],
"require": {
"app/module-order": "*",
"app/module-notification": "*"
}
}
关键点:
-
./modules/order必须是真实存在的本地目录,且其内部composer.json明确声明"autoload": { "psr-4": { "App\Modules\Order\": "src/" } } -
composer update会软链接而非拷贝代码,改模块源码立刻生效,无需重复 install - 删掉某个
modules/xxx目录后,只要从require里移除对应项并composer update,自动解耦,无残留 - CI 构建时用
composer install --no-dev --optimize-autoloader,它只会扫描repositories中已声明的 path 目录,不会误加载未启用模块
模块启用必须在运行时控制,不能靠 composer.json
租户 A 需要订单模块,租户 B 不需要——这种策略无法在 composer.json 里表达。必须放弃 “require 控制开关” 的幻想,改用运行时注册:
- 在 Laravel 中,于
AppServiceProvider::boot()里检查租户配置,条件调用$loader->addPsr4('App\Modules\Order\', base_path('modules/order/src')) - 务必加防重注册逻辑:
if (! in_array('App\Modules\Order\', $loader->getPrefixesPsr4())) { ... } - PHP-FPM worker 进程不重启,
addPsr4()就不生效——上线后记得sudo systemctl reload php8.3-fpm或触发 fpm reload - 不要用
nwidart/laravel-modules这类包做核心调度,它把模块当“内置功能”管,反而堵死按租户动态加载的路径
最后提醒一个硬伤:classmap 优化和模块化互斥
composer dump-autoload -o 会把所有 autoload 声明的路径扫成静态映射表,但它 完全不识别运行时 addPsr4() 注册的路径。这意味着:
- 你开了
--classmap-authoritative,那些租户模块类就彻底找不到——autoloader 连 fallback 查找都跳过了 - 生产环境若坚持 classmap 优化,就必须把所有可能启用的模块路径都写死进根
composer.json的autoload字段,等于放弃运行时灵活性 - 折中方案:构建时用
-o加速主干代码,但对 modules/ 目录保持 PSR-4 动态查找,靠 opcode 缓存扛住开销

















