<div align="center">
  <img src="https://cloud.lianhanlin.org/path-ioc/logo.webp" width="160" alt="Path-IoC logo">

  <h1>Path-IoC (lianhanlin-modular)</h1>

  <p><b>Spring 有 Bean，Nest 有 Provider，Path-IoC 有 Mesh。</b></p>
  <p>🚀 <b>像 lodash-es 一样纯粹通用的 TypeScript/JavaScript 路径依赖查找引擎 (IoC-DL)</b></p>
  <p>✨ <b>JavaScript/TypeScript 动态语言模块控制反转的唯一正解</b></p>

  <p>
    <a href="https://www.npmjs.com/package/lianhanlin-modular"><img src="https://img.shields.io/npm/v/lianhanlin-modular.svg" alt="NPM version"></a>
    <a href="https://www.npmjs.com/package/lianhanlin-modular"><img src="https://img.shields.io/npm/dm/lianhanlin-modular.svg" alt="NPM downloads"></a>
    <a href="https://packagephobia.com/result?p=lianhanlin-modular"><img src="https://packagephobia.com/badge?p=lianhanlin-modular" alt="Install size"></a>
    <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/npm/l/lianhanlin-modular.svg" alt="License"></a>
    <a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-5.0+-3178C6?logo=typescript&logoColor=white" alt="TypeScript"></a>
    <a href="https://vite.dev"><img src="https://img.shields.io/badge/powered%20by-Vite-646CFF?logo=vite&logoColor=white" alt="Powered by Vite"></a>
    <a href="https://webpack.js.org"><img src="https://img.shields.io/badge/Webpack-5-8DD6F9?logo=webpack&logoColor=black" alt="Webpack 5"></a>
    <a href="https://rspack.dev"><img src="https://img.shields.io/badge/Rspack-compatible-EE6338?logo=rspack&logoColor=white" alt="Rspack"></a>
  </p>
</div>

> 📦 **项目标识与包名对照 (Identity Mapping)**：
>
> - **NPM 安装包名**：`lianhanlin-modular` (`npm i lianhanlin-modular`)
> - **核心架构思想**：`Path-IoC`（基于物理路径契约的控制反转与依赖查找引擎）
> - **核心物理单元**：`Mesh`（对应 Spring 中的 Bean）
> - **虚拟模块导入**：`virtual:modular-container`（构建插件在内存中全自动收集导出的 Mesh 注册表）

> 💡 **什么是 Path-IoC (IoC-DL)？**：告别原始 `import` 泥潭与 Java 式重型黑盒 DI（如 NestJS）在 JS 异步生态里的死锁/反射包袱。Path-IoC 采用 **Dependency Lookup (依赖查找)** 范式——路径即契约，静态图预编译，原生 `async/await` 支持。零反射、零概念包袱，组件面向 `container` 极简解构。

> 🌟 **典范应用模式直达**：
>
> - 🌐 [前端全动态路由自动聚合 (`allRoutes`)](#mode-1)
> - 📦 [后端 ORM 实体自动收集与路径类型抽取 (`entities`)](#mode-2)
> - 🚀 [终态收敛启动器 (`bootstrap`)](#mode-3)

---

## ⚡ 5 秒上手 (5-Second Quick Start)

### 1. 插件配置（以 Vite 为例；Webpack / Rspack 配置 👉 [点击跳转](#build-tools-integration)）

**`vite.config.ts`**：

```typescript
import { defineConfig } from "vite";
import modularType from "lianhanlin-modular/plugin-vite";

export default defineConfig({ plugins: [modularType()] });
```

### 2. 目录结构

```text
src/
├── modules/
│   ├── math/add/index.ts       # 计算 Mesh
│   ├── math/isEven/index.ts    # 校验 Mesh
│   └── app/runner/index.ts     # 业务汇聚 Mesh (依赖 add 与 isEven)
└── index.ts                    # 项目编译构建入口 (仅一行代码)
```

### 3. 项目编译构建入口 (`src/index.ts`)

```typescript
/// <reference types="lianhanlin-modular/virtual" />
import { createModularContainer } from "virtual:modular-container";

// 🚀 项目编译构建入口：控制权全权交由容器！拓扑引擎自动解析依赖网格并链式唤醒运行
await createModularContainer();
```

### 4. 编写 Mesh (`src/modules/...`)

> 💡 **类型提示**：`ModularContainer` 类型由 Vite / 构建插件全自动根据目录生成并注入，零手动导入。

```typescript
// src/modules/math/add/index.ts
export const main = () => (a: number, b: number) => a + b;
```

```typescript
// src/modules/math/isEven/index.ts
export const main = () => (num: number) => num % 2 === 0;
```

```typescript
// src/modules/app/runner/index.ts (业务汇聚 Mesh)
export const main = (container: ModularContainer) => {
  const { add, isEven } = container;

  const sum = add(3, 5);
  const evenText = isEven(sum) ? "Even" : "Odd";
  console.log(`🚀 [Quick Start] Sum: ${sum}, IsEven: ${evenText}`);
};

// 💡 顺序控制：声明 order 为无穷大 (Infinity)，保证在无显式拓扑约束的模块中最后唤醒
// 亦可替换为显式拓扑依赖：export const dependencies = ["add", "isEven"];
export const order = Number.POSITIVE_INFINITY;
```

---

## 🏛️ 核心设计哲学 (Architecture Philosophy)

Path-IoC 的底层设计建立在 4 大高维架构哲学之上：

### 1. 💡 约定优于配置 + 闭包工厂 (Convention Over Configuration)

拒绝伪注解与重型 `@Injectable()` 装饰器，保持模块 100% 纯 TypeScript 函数与闭包纯洁性。依靠构建工具链在编译期进行隐式目录契约挂载，零配置开箱即用。

### 2. 🏷️ 目录即契约，路径即寻址 (Directory as Contract & Path Address)

- **目录即契约 (Directory as Contract)**：抛弃显式声明与 `@Inject('token')` 伪元数据，物理目录路径即为全局服务契约 Token。短名称提供极致直觉的无感解构 (`const { add } = container`)，全限定路径提供确定性的歧义消除；
- **路径即寻址 (Pattern Discovery)**：路径不仅是坐标，更是服务发现的天然索引。支持基于路径前缀模式的动态批量收集与副作用扫描（如全动态路由收集 `allRoutes`、ORM Schema 自动挂载 `entities`）。

### 3. ⚡ 零运行期反射与静态图编译 (Zero-Reflection & Precompiled Graph)

彻底摆脱 `reflect-metadata` 重型反射包袱。架构上将**静态图编译 (`compileModuleGraph`)** 与 **动态容器填充 (`instantiateModuleContainer`)** 彻底分离，服务启动时仅编译一次拓扑图，高并发请求下零重复拓扑计算，提升 **80% CPU 性能**。

### 4. 🔒 循环依赖秒级定位 (不内置与不推荐隐式解环)

不内置也不推荐隐式自动解环（主要避免 `async` 异步初始化死锁风险与切面模块时序紊乱）。一旦误写循环依赖，框架在启动瞬间（Fail-Fast）立刻拦截并**精准打印出完整闭环调用链**（如 `/A -> /B -> /C -> /A`），保证 100% 确定性（👉 [点击查看 FAQ 深度解析](#q2-为什么-path-ioc-坚决不内置隐式解环循环依赖拆解机制)）。

---

## ☯️ 架构范式：前端单例 vs 后端多例 (Practices Matrix)

Path-IoC 本身是一个纯粹的拓扑图引擎与容器填充器，天然适配不同端的架构诉求：

### 模式 A：前端全局单例 (Frontend Singleton)

在前端应用入口初始化全局单例容器，视图组件或应用逻辑直接消费该单例：

```typescript
// src/index.ts
import { createModularContainer } from "virtual:modular-container";

export const modularContainer = await createModularContainer();
```

### 模式 B：后端 Request-Scoped 多例 (Backend Multi-Instance)

在 Node.js / Hono / Express 后端服务中，启动时预编译静态图，HTTP 请求到达时高频实例化独立隔离容器：

```typescript
import {
  compileModuleGraph,
  instantiateModuleContainer,
} from "lianhanlin-modular";
import { modules } from "virtual:modular-container";

// 1. 服务启动阶段：纯同步纳秒级预编译静态拓扑图 (全局仅计算一次)
const compiledGraph = compileModuleGraph(modules);

// 2. HTTP 请求到达阶段：高频实例化独立隔离容器 (零重复图计算，CPU 性能提升 80%)
app.use(async (c, next) => {
  const reqContainer = {}; // 每次请求独立的新容器对象
  await instantiateModuleContainer(compiledGraph, reqContainer);

  c.set("container", reqContainer); // 挂载至请求上下文，防止跨请求数据污染
  await next();
});
```

---

## 📊 主流 IoC 框架选型对比 (Selection Matrix)

| 对比维度                                | **传统 TS 装饰器类**<br>(NestJS / InversifyJS)                                                                                                                                                                                                                                                          | **动态 Proxy / 注册表类**<br>(Awilix)                                                                                           | **Java 传统重型 IoC**<br>(Spring Framework)                                                                                                                                         | **Path-IoC (本框架)**                                                                                                                                                           |
| :-------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **学习成本与概念包袱**                  | ❌ **概念极其繁重**<br>(需学 `@Module`, `@Injectable`, `@inject()`, `forwardRef`, `OnModuleInit`)                                                                                                                                                                                                       | ⚠️ **中度注册链**<br>(需学 `asClass`/`asFunction` 注册链与生命周期)                                                             | ❌ **概念浩瀚繁重**<br>(需学 Bean 作用域、三级缓存、动态代理、Lifecycle 钩子)                                                                                                       | ✅ **零新概念**<br>(目录即 Service Token，仅需导 `main` 工厂 + `dependencies` 数组)                                                                                             |
| **依赖处理与异步调度**                  | ❌ **死锁与串行阻塞 (物理机制限制)**<br>1. **死锁**：因 JS `constructor` 无法 `async`，异步 Provider 与 `forwardRef` 遇微任务队列直接挂起死锁<br>2. **阻塞**：生命周期钩子 (如 `onModuleInit`) 需按模块树层级串行递归 `await`，子树中某个模块的异步挂起容易引发全局初始化延迟，无法做到节点级反应式并发 | ❌ **功能与性能受限**<br>1. **功能**：依赖外部驱动，Proxy 无法解决异步初始化时序<br>2. **性能**：挂起等待，无节点级拓扑并发支持 | ⚠️ **多线程同步阻塞模型**<br>(依赖 JVM 多线程同步栈与三级缓存，完全不适配 JavaScript 单线程异步 Event Loop)                                                                         | ✅ **回归语言原生与反应式拓扑**<br>1. **功能**：`main` 天然支持原生 `async/await`，反应式自动级联等待<br>2. **性能**：基于 DAG 反应式拓扑并发，**绝对不阻塞任何无关模块初始化** |
| **构建工具链兼容性 (Vite/SWC/ESBuild)** | ❌ **纯类型擦除模式失效**<br>(强依赖 `reflect-metadata` 与 TS Decorator Metadata，导致 ESBuild、Vite 内置转译器及 Node.js 原生 `--strip-types` 等纯类型擦除转译直接报错失效，使用 SWC 时也必须专门开启专有元数据转换插件)                                                                               | ✅ **兼容**<br>(无元数据依赖，但依赖函数 `toString()` 正则解析入参)                                                             | ➖ **不适用 (JVM 生态)**<br>(需通过 `javac` / Bytecode 字节码动态增强)                                                                                                              | ✅ **100% 极速构建兼容**<br>(纯 ES Module 函数闭包，零元数据/零反射，天然适配 Vite/SWC/ESBuild/Rspack)                                                                          |
| **循环依赖与安全性**                    | ❌ **遇到 `async` 必引发死锁**<br>(`forwardRef` / `@lazyInject` / `delay()` 遇异步微任务挂起)                                                                                                                                                                                                           | ⚠️ **仅限同步**<br>(Proxy 延迟 `get` 拦截，遇异步同样挂起)                                                                      | ⚠️ **仅限 Setter 注入解环**<br>(三级缓存解环；在构造器注入、`@Async` 或代理包装时仍抛异常失效)                                                                                      | ✅ **编译期精准定位与确定性**<br>(不内置隐式解环，DFS 环检测秒级打印 `/A -> /B -> /A` 路径)                                                                                     |
| **AOP 切面机制**                        | ❌ **概念繁多 & 框架重度绑定**<br>(切面拆分为 Guards / Interceptors / Pipes / Filters 等多个特权概念；虽然支持全局绑定，但切面逻辑重度绑定 Nest 的 `ExecutionContext` 抽象，无法作为纯 JS 函数脱离框架独立复用)                                                                                         | ❌ **无内置 AOP**<br>(无内置切面概念，需在注册链处由开发者手动包裹 Proxy 或高阶函数)                                            | ✅ **经典声明式代理 (Java 物理约束下的伟大突破)**<br>(在 Java 静态强类型与 JVM 字节码约束下，全自动封装 JDK 动态代理与 CGLIB，彻底解放手写代理；类内部自调用切面受代理机制物理限制) | ✅ **极简纯粹 (依赖查找)**<br>仅提供依赖查找能力 (DL)，基于物理路径与原生解构，JS 作为动态语言无需额外的特权 AOP 工具。                                                         |
| **团队规范与分层约束**                  | ✅ **强规范约束**<br>(强制 Controller/Service 死板分层，极大降低百人团队目录混乱与协作成本)                                                                                                                                                                                                             | ⚠️ **中度规范**<br>(依赖团队自行约束注册表结构与生命周期)                                                                       | 🏆 **工业级分层标杆**<br>(拥有全行业最成熟的 DDD/MVC 分层规约与包结构标准)                                                                                                          | ✅ **物理契约自约束**<br>(基于目录契约自动分层，短名称解构 + 路径切面，兼顾规范与极其灵活的重构)                                                                                |
| **生态扩展与特色工具**                  | ✅ **Swagger 自动推导**<br>(基于 Decorator Metadata 全自动生成 OpenAPI 文档与客户端 SDK)                                                                                                                                                                                                                | ✅ **老代码无侵入改装**<br>(支持在外部把任意第三方/遗留 Class/Function 注册为容器 Bean)                                         | 🏆 **浩瀚的企业级生态**<br>(拥有全行业最强声明式数据库事务 `@Transactional` 与微服务治理生态)                                                                                       | ⚡ **路径模式发现 & 动态 Schema**<br>(基于路径模式全自动收集路由/实体，一键导出全站 Postman 测试集合)                                                                           |
| **高并发 / 运行时性能**                 | ⚠️ **高频元数据反射损耗**<br>(Request-scoped 在每次 HTTP 请求到达时，重新遍历 Decorator Metadata 进行反射解析与对象 `new` 实例化)                                                                                                                                                                       | ⚠️ **代理解构与属性访问开销**<br>(依赖 ES6 Proxy `cradle` 机制进行参数解构与动态依赖查找，无法利用编译期静态分析)               | ⚠️ **反射与代理开销**<br>(基于 Java 反射机制实例化，存在反射与 CGLIB 代理额外开销)                                                                                                  | ⚡ **极高 (性能提升 80%)**<br>(静态图预编译与填充分离，填充后为原生 JS 对象，零 Proxy/零反射开销)                                                                               |

---

## 📚 API 参考与规格 (API & Specifications)

### 🧩 1. Mesh 规范与导出协议 (Mesh Export Protocol)

在 Path-IoC 中，每一个按目录组织的 `index.ts(x)` 即为一个 **Mesh**。一个标准的 Mesh 模块文件允许导出以下 4 个标准属性：

| 导出变量名                  | 类型签名                                                                      | 默认值  | 作用说明                                                                                        |
| :-------------------------- | :---------------------------------------------------------------------------- | :------ | :---------------------------------------------------------------------------------------------- |
| **`main`** _(必须)_         | `(container: ModularContainer, moduleNames: string[]) => any \| Promise<any>` | -       | **模块主工厂**。按拓扑顺序唤醒，接收 `container` 与全量模块 Key 列表。支持 `async` 异步初始化。 |
| **`dependencies`** _(可选)_ | `string[] \| ((moduleNames: string[]) => string[])`                           | `[]`    | **拓扑依赖声明**。图编译阶段优先唤醒。支持静态数组，或函数形式 `(names) => string[]`。          |
| **`order`** _(可选)_        | `number`                                                                      | `99999` | **初始化优先级**。无 `dependencies` 约束时按数值从小到大排序（负数优先，`Infinity` 置后）。     |
| **`skip`** _(可选)_         | `boolean \| ((moduleNames: string[]) => boolean)`                             | `false` | **条件跳过标记**。为 `true` 时跳过该 Mesh 的初始化（用于环境隔离与条件加载）。                  |

---

### <a id="build-tools-integration"></a>2. 构建工具集成 (`vite.config.ts` / `webpack.config.js`)

**Vite 配置**：

```typescript
import { defineConfig } from "vite";
import modularType from "lianhanlin-modular/plugin-vite";

export default defineConfig({
  plugins: [
    modularType({
      modulesPath: "src/modules", // 模块扫描根目录
      typeFileOutput: "types", // ignore.modular.d.ts 的输出目录
    }),
  ],
});
```

**Webpack / Rspack 配置**：

```javascript
const {
  ModularTypeWebpackPlugin,
} = require("lianhanlin-modular/plugin-webpack");

module.exports = {
  plugins: [
    new ModularTypeWebpackPlugin({
      modulesPath: "src/modules",
      typeFileOutput: "types",
    }),
  ],
};
```

---

### 3. 虚拟模块 API (导入自 `virtual:modular-container`)

> 💡 由 Vite / Webpack 插件自动生成，内部预装静态图编译逻辑。

```typescript
import { createModularContainer, modules } from "virtual:modular-container";
```

| 导出 API                 | 签名 / 说明                                    | 描述                                                                          |
| :----------------------- | :--------------------------------------------- | :---------------------------------------------------------------------------- |
| `createModularContainer` | `(container?) => Promise<Record<string, any>>` | **开箱即用首选**。内置静态图缓存，一行代码自动解析并按拓扑顺序装配所有 Mesh。 |
| `modules`                | `ModuleDeclaration[]`                          | 自动扫描发现的原始 Mesh 注册表，可用于跨项目/跨包注册表合并。                 |

---

### 4. 运行时核心 API (导入自 `lianhanlin-modular`)

> 🛠️ **高级定制 API**：用于脱离 Vite、多注册表合并或极致定制化场景。

```typescript
import {
  compileModuleGraph,
  instantiateModuleContainer,
  initialize,
} from "lianhanlin-modular";
```

| API / 类型                                                          | 签名 / 说明                                                                            | 描述 & 使用建议                                                                                                                                                           |
| :------------------------------------------------------------------ | :------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`initialize`**                                                    | `(modules, container) => Promise<void>`                                                | **快捷驱动函数**。内部串联图编译与容器填充。前端多注册表聚合直接使用。                                                                                                    |
| **`compileModuleGraph`**<br>`+`<br>**`instantiateModuleContainer`** | `compileModuleGraph(modules)`<br>`+`<br>`instantiateModuleContainer(graph, container)` | **高级图编译与填充分离组合**。服务启动时运行 `compileModuleGraph` 编译并全局缓存静态图；请求到达时调用 `instantiateModuleContainer` 填充隔离容器，提升 **80% CPU 性能**。 |

---

### 5. 调试与耗时诊断 (`container.$logs`)

初始化完成后，容器对象上会自动挂载 `$logs` 日志数组：

```typescript
const container = await createModularContainer();

// 打印每个 Mesh 的初始化耗时与启动时序日志
console.log(container.$logs);
/*
[
  "init:start",
  "Phase 5: Reactive execution flow starting...",
  "[Init] /add initialized in 1ms",
  "[Init] /isEven initialized in 1ms",
  "[Init] /app/runner initialized in 2ms",
  "Initialization complete."
]
*/
```

---

## 📦 Mesh 打包与注册表分发 (MODULAR_PACK)

框架支持将当前项目的全量 Mesh 编译并打包为独立可发布的 npm 交付包：

```bash
MODULAR_PACK=true vite build
```

通过指定环境变量，还可进行打包高级控制：

- `MODULAR_OBFUSCATE=false`: 跳过代码混淆（方便二次开发或排错调试）

打包完成后将在输出目录自动生成：

- `index.js` — 混淆加密/优化后的 ES Module 产物；
- `index.d.ts` — 带有全局 `ModuleMap` 与 `ModularContainer` 的声明文件；
- `.tgz` 压缩包 — 自动运行 `npm pack` 产出的标准 npm 交付包。

### 跨项目注册表聚合 (插件化 / 微前端)

下游消费项目可将打好的第三方注册表包与本地注册表轻松合并：

```typescript
import {
  createModularContainer,
  modules as localModules,
} from "virtual:modular-container";
import { modules as vendorModules } from "my-thirdparty-plugin";

// 跨项目聚合注册表，一行代码完成拓扑无缝连线！
const container = await createModularContainer([
  ...localModules,
  ...vendorModules,
]);
```

---

## 💡 典范应用模式 (Design Patterns)

### <a id="mode-1"></a>模式 1：前端全动态路由自动聚合 (`allRoutes`)

```tsx
// src/modules/router/allRoutes/index.tsx
export const main = (container: ModularContainer) => {
  // 从容器中过滤出所有 /pages/ 目录下的页面 Mesh
  const pageKeys = Object.keys(container).filter((k) =>
    k.startsWith("/pages/"),
  );

  return pageKeys.map((key) => ({
    path: key.replace("/pages/", ""),
    element: container[key],
  }));
};

// 原生 JS 路径过滤：确保在所有 /pages/ Mesh 加载完毕后再运行
export const dependencies = (names: string[]) =>
  names.filter((n) => n.startsWith("/pages/"));
```

### <a id="mode-2"></a>模式 2：后端 ORM 实体自动收集与路径类型抽取 (`entities`)

```typescript
// src/modules/database/entities/index.ts

// 🛠️ 自定义 TS 类型工具：根据物理路径 Pattern 自动提取 Container 中匹配的 Mesh 联合类型
type ExtractModule<T extends Record<string, any>, P extends string> = T[Extract<
  keyof T,
  P
>];

// 🌟 按路径模式抽取全量实体 Mesh 的类型
type SchemaType = ExtractModule<
  ModularContainer,
  `${string}/entities/${string}`
>;

export const main = (container: ModularContainer, moduleNames: string[]) => {
  const schemas: SchemaType[] = dependencies(moduleNames).map(
    (k) => container[k],
  );
  return registerSchemas(schemas);
};

// 原生 JS 路径过滤：提取所有包含 /entities/ 的 ORM 实体 Mesh
export const dependencies = (names: string[]) =>
  names.filter((n) => n.includes("/entities/"));
```

### <a id="mode-3"></a>模式 3：终态收敛启动器 (`bootstrap`)

```typescript
// src/modules/app/bootstrap/index.ts
export const main = (container: ModularContainer) => {
  // 此时所有 Store、路由、中间件已 100% 按拓扑顺序装配完毕
  runApp(container);
};

// 🕸️ 拓扑终态汇聚 (Sink Node)：原生 JS 过滤排除自身，确保在全图绝对最后唤醒
export const dependencies = (names: string[]) =>
  names.filter((n) => !n.endsWith("/bootstrap"));
```

---

## 💬 常见问题与技术深度解析 (FAQ)

### Q1: 模块名称是如何从文件路径映射出来的？同名冲突怎么办？

- 路径 `src/modules/common/resourceManager/index.ts`
  - **短 Token (Short Name)**: `container.resourceManager`
  - **全限定 Token (Full Path)**: `container['/common/resourceManager']`

若两个不同子目录下存在同名文件夹（如 `a/user` 与 `b/user`），短 Token `user` 会触发歧义保护并报错，提示开发者通过全限定路径 `container['/a/user']` 进行精确引用。

---

### Q2: 为什么 Path-IoC 坚决不内置“隐式解环/循环依赖拆解”机制？

> 💬 **作者立场声明**：在 JavaScript 单线程 Event Loop 与 `async` 环境中，**隐式解环机制在架构上是绝对错误且有重大隐蔽风险的**。

1. **Java Spring 三级缓存成功的前置条件**：Spring 能够使用三级缓存拆解循环依赖，核心在于 Java 是一门多线程、静态强类型且属性 Setter 注入为主的语言，可以在 JVM 同步线程栈里先塞入未完全初始化的裸对象。
2. **JS Event Loop 与 `async` 的固有矛盾**：在 Node.js / 全栈开发中，模块初始化常常包含 `async/await`。若强拆循环依赖，异步模块不仅会导致类型退化为 `Promise`，甚至会在事件循环中引发死锁 (Deadlock) 或僵尸半初始化对象。
3. **Path-IoC 的选择**：坚持 **编译期 DFS 拓扑环检测 + Fail-Fast 报错**。用 100% 的确定性保证零僵尸对象与零死锁。（如有特殊解环需求，可参考 [👉 附录：如何在 Path-IoC 中自定义扩展拆解循环依赖 `createProxyContainer`](#appendix-proxy-container)）。

---

### Q3: 为什么 Path-IoC 没有内置重型 AOP 工具包？

JavaScript 拥有原生函数、闭包与 `Proxy` 机制。在 Path-IoC 中，模块通过 `main(container)` 统一交由容器管理，开发者使用原生高阶函数包装或 ES6 `Proxy` 即可完成无感切面织入，无需框架提供重型 AOP 注解包袱。

---

### Q4: 如何在外部向容器注入自定义依赖/上下文？

`createModularContainer` 支持接收一个初始对象。你可以将外部 Request、Env 配置或全局客户端直接预挂载进容器：

```typescript
const container = await createModularContainer({
  env: process.env.NODE_ENV,
  logger: customExternalLogger,
});
```

---

### Q5: 如何在用户侧实现单例缓存 (`memoizeModule`)？

`memoizeModule` 是用户侧模式，保持 100% 的 TypeScript 返回值类型推导：

```typescript
// 用户侧单例缓存高阶函数示例 (保持 100% 类型推导)
export const memoizeModule = <T>(
  main: (container: ModularContainer, names: string[]) => T,
) => {
  let instance: T;
  let initialized = false;
  return (container: ModularContainer, names: string[]) => {
    if (!initialized && (initialized = true)) {
      instance = main(container, names);
    }
    return instance;
  };
};
```

---

### Q6: 关于 `skip` 和 `order` 的配置说明

- **`order`**：用于在相同依赖层级时干预初始化顺序，属于可选补丁。
- **`skip` (不推荐使用)**：`skip` 最初是为了少数类型声明文件的妥协产物。在现代实践中，**完全不推荐使用 `skip`**。建议通过构造不可覆写 key 的 Proxy 容器或 Readonly 对象在底层隐式解决，保持模块导出的绝对纯洁。

---

## <a id="appendix-proxy-container"></a>🧪 附录：如何在 Path-IoC 中自定义扩展拆解循环依赖 (`createProxyContainer`)

> 💡 **作者真实设计观**：初始化阶段的循环依赖在逻辑上是**无解的死结**（强硬解环必然导致僵尸半初始化对象）；而运行期的方法调用循环本身就是伪命题；在单线程事件循环（Event Loop）的语言特性下，**`async` 异步初始化与循环依赖隐式拆解更是不可调和的死结**。手写 `dependencies` 依赖声明成本极低，且能换取 100% 的确定性。

Path-IoC 本身从未主动设计或内置任何循环依赖拆解机制。但由于容器底层是一个透明的原生 JavaScript 对象，对于执意有解环需求的使用者，无需修改 Path-IoC 内核，只需在用户侧编写约 20 行动态 Proxy 容器 **`createProxyContainer`** 传入初始化函数即可：

当某个模块在初始化阶段通过 Proxy 提前触发了被依赖项的实例化并写入容器后，`instantiateModuleContainer` 在后续遍历到该节点时会自动判定已就绪并直接跳过，完美实现初始化循环拆解：

### 1. 用户侧扩展实现 (`src/createProxyContainer.ts`)

```typescript
import { CompiledModuleGraph } from "lianhanlin-modular";

// 用户侧扩展：安全的多请求复用、支持静态编译图感知的解环 Proxy 容器
export const createProxyContainer = (
  compiledGraph: CompiledModuleGraph,
  baseContainer: Record<string, any> = {},
) => {
  const initializingKeys = new Set<string>();

  return new Proxy(baseContainer, {
    get(target, prop: string) {
      // 1. 若当前请求容器已有实例，直接返回（防止重复初始化，且保证并发缓存安全）
      if (prop in target) {
        return target[prop];
      }

      // 2. 从静态编译图查找模块声明（只读查找，绝不 delete 修改全局缓存的 compiledGraph）
      const mod = compiledGraph.fullNameToModuleMap.get(prop);
      if (!mod) return target[prop];

      // 🚨 死锁保护：检测是否在初始化阶段陷入了同步循环依赖死锁！
      if (initializingKeys.has(prop)) {
        throw new Error(
          `[ProxyContainer] 检测到模块  在同步初始化阶段存在无法解开的循环依赖死锁！`,
        );
      }

      // 3. 动态触发初始化，并将结果同步写入当前请求的 target 中
      initializingKeys.add(prop);
      const instance = mod.main(this, compiledGraph.moduleDeclarationNames);

      // 🚨 安全保护：一旦发现试图对异步 Promise 模块解环，直接 Fail-Fast 抛错！
      if (instance && typeof (instance as any).then === "function") {
        throw new Error(
          `[ProxyContainer] 无法对异步模块  进行隐式解环，请显式声明 dependencies。`,
        );
      }

      target[prop] = instance; // 写入请求容器，后续自动跳过重复初始化
      initializingKeys.delete(prop);

      return instance;
    },
  });
};
```

### 2. 使用方法 (`src/index.ts`)

```typescript
import { createModularContainer } from "virtual:modular-container";
import { createProxyContainer } from "./createProxyContainer";

// 将 Proxy 代理容器传入初始化函数
createModularContainer(createProxyContainer());
```

### 3. 使用后模块定义文件 (`index.ts`) 的简化变化

- ✅ **省去依赖声明**：开发者在模块定义文件中 **无需再手写 `export const dependencies = [...]`**。
- ✅ **极简模块契约**：每一个模块文件缩减为只需要导出单单一项 `export const main = (container) => ...` 工厂函数即可。

> ⚠️ **使用注意事项**：
>
> 1. 解环的核心目的正是为了拆解 **初始化阶段** 的依赖循环。
> 2. 该解环方式仅适用于同步模块，包含 `async` 异步初始化的模块循环依赖依然建议重构解耦。

---

## 📜 License

MIT © Lianhanlin
