@path-ioc/unplugin 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -0
- package/dist/index.cjs +351 -0
- package/dist/index.d.cts +50 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +310 -0
- package/package.json +121 -0
- package/virtual.d.ts +6 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>@path-ioc/unplugin</h1>
|
|
3
|
+
<p><b>Universal Dev Plugin for Path-IoC (Virtual Container & Type Generator)</b></p>
|
|
4
|
+
<p>跨构建工具(Vite / Rolldown / Webpack / Rspack / Rollup / Esbuild)的通用虚拟模块注入与 TypeScript 类型自动推导插件</p>
|
|
5
|
+
|
|
6
|
+
<p>
|
|
7
|
+
<a href="https://www.npmjs.com/package/@path-ioc/unplugin"><img src="https://img.shields.io/npm/v/@path-ioc/unplugin.svg" alt="NPM version"></a>
|
|
8
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/npm/l/@path-ioc/unplugin.svg" alt="License"></a>
|
|
9
|
+
<a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-5.0+-3178C6?logo=typescript&logoColor=white" alt="TypeScript"></a>
|
|
10
|
+
<a href="https://vite.dev"><img src="https://img.shields.io/badge/powered%20by-Vite-646CFF?logo=vite&logoColor=white" alt="Vite"></a>
|
|
11
|
+
<a href="https://rolldown.rs"><img src="https://img.shields.io/badge/Rolldown-ready-FF6B6B?logo=rust&logoColor=white" alt="Rolldown"></a>
|
|
12
|
+
<a href="https://rspack.dev"><img src="https://img.shields.io/badge/Rspack-compatible-EE6338?logo=rspack&logoColor=white" alt="Rspack"></a>
|
|
13
|
+
<a href="https://webpack.js.org"><img src="https://img.shields.io/badge/Webpack-5-8DD6F9?logo=webpack&logoColor=black" alt="Webpack"></a>
|
|
14
|
+
</p>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
> 💡 **核心定位**:`@path-ioc/unplugin` 是 [`@path-ioc/core`](../core) 的编译期伴生驱动引擎。在真实生产工程中,两者密不可分:`unplugin` 负责在构建期自动扫描物理目录并实时生成 `.d.ts` 类型推导,`core` 负责在运行时进行极速无锁 DAG 拓扑装配。
|
|
18
|
+
> **完整的架构设计哲学、模块编写规范、依赖查找与端到端完整指南,请直接查阅:**
|
|
19
|
+
> 📖 **[`@path-ioc/core` 官方指南](../core/README.md)** 或访问官方主站 **[https://path-ioc.dev](https://path-ioc.dev)**。
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 核心职能 (Key Responsibilities)
|
|
24
|
+
|
|
25
|
+
- **全构建器原生支持 (Universal Bundler Support)**:
|
|
26
|
+
基于 `unplugin` 规范,一套逻辑原生适配 **Vite**、**Rolldown (Rust)**、**Webpack 5**、**Rspack**、**Rollup** 与 **Esbuild**。
|
|
27
|
+
- **`virtual:modular-container` 虚拟模块流式注入**:
|
|
28
|
+
构建期自动扫描 `src/modules/**/index.{ts,tsx}`,动态生成全量模块注册表。在 Vite/Rolldown/Rollup 环境下纯内存流式注入,在 Webpack/Rspack 下自动创建临时代理桥接。
|
|
29
|
+
- **TypeScript 零配置类型合成**:
|
|
30
|
+
开发时与 HMR 热更新时毫秒级生成 `ignore.modular.d.ts`,自动扩充全局 `ModularContainer` 接口,解构享 100% 准确 IDE 提示。
|
|
31
|
+
- **Git 规避自愈 (`.gitignore` 自动维护)**:
|
|
32
|
+
自动向项目 `.gitignore` 补充 `ignore.*` 规则,防止生成的临时声明污染版本控制。
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 安装 (Installation)
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pnpm add -D @path-ioc/unplugin
|
|
40
|
+
pnpm add @path-ioc/core
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 构建工具集成速查 (Bundler Quick Reference)
|
|
46
|
+
|
|
47
|
+
### 1. Vite (`vite.config.ts`)
|
|
48
|
+
```typescript
|
|
49
|
+
import { defineConfig } from "vite";
|
|
50
|
+
import { vitePlugin as pathIoc } from "@path-ioc/unplugin";
|
|
51
|
+
|
|
52
|
+
export default defineConfig({
|
|
53
|
+
plugins: [pathIoc({ modulesPath: "src/modules", typeFileOutput: "types" })],
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 2. Rolldown (`rolldown.config.ts`)
|
|
58
|
+
```typescript
|
|
59
|
+
import { defineConfig } from "rolldown";
|
|
60
|
+
import { rolldownPlugin as pathIoc } from "@path-ioc/unplugin";
|
|
61
|
+
|
|
62
|
+
export default defineConfig({
|
|
63
|
+
plugins: [pathIoc({ modulesPath: "src/modules", typeFileOutput: "types" })],
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 3. Rspack (`rspack.config.js`)
|
|
68
|
+
```javascript
|
|
69
|
+
const { rspackPlugin: pathIoc } = require("@path-ioc/unplugin");
|
|
70
|
+
|
|
71
|
+
module.exports = {
|
|
72
|
+
plugins: [pathIoc()],
|
|
73
|
+
};
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 4. Webpack 5 (`webpack.config.js`)
|
|
77
|
+
```javascript
|
|
78
|
+
const { webpackPlugin: pathIoc } = require("@path-ioc/unplugin");
|
|
79
|
+
|
|
80
|
+
module.exports = {
|
|
81
|
+
plugins: [pathIoc({ modulesPath: "src/modules" })],
|
|
82
|
+
};
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 5. Rollup (`rollup.config.js`) / Esbuild
|
|
86
|
+
```javascript
|
|
87
|
+
// Rollup
|
|
88
|
+
import { rollupPlugin as pathIoc } from "@path-ioc/unplugin";
|
|
89
|
+
// Esbuild
|
|
90
|
+
import { esbuildPlugin as pathIoc } from "@path-ioc/unplugin";
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 插件配置项 (Plugin Options)
|
|
96
|
+
|
|
97
|
+
| 配置项 | 类型 | 默认值 | 描述 |
|
|
98
|
+
| :--- | :--- | :--- | :--- |
|
|
99
|
+
| **`modulesPath`** | `string` | `'src/modules'` | 模块扫描的物理根目录路径。 |
|
|
100
|
+
| **`typeFileOutput`** | `string` | `'types'` | 自动生成的类型声明文件 `ignore.modular.d.ts` 存放相对目录。 |
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 真实应用与模块编写
|
|
105
|
+
|
|
106
|
+
关于如何编写 `main` 纯函数模块、声明依赖、在应用入口一行唤醒容器,请参阅:
|
|
107
|
+
👉 **[查看 @path-ioc/core 完整实战指南](../core/README.md)**
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 许可证 (License)
|
|
113
|
+
|
|
114
|
+
Released under the [MIT License](./LICENSE).
|
|
115
|
+
Copyright © 2026 [Path-IoC Organization](https://github.com/path-ioc) & Lian HanLin.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
PathIocPlugin: () => PathIocPlugin,
|
|
34
|
+
default: () => index_default,
|
|
35
|
+
esbuildPlugin: () => esbuildPlugin,
|
|
36
|
+
rolldownPlugin: () => rolldownPlugin,
|
|
37
|
+
rollupPlugin: () => rollupPlugin,
|
|
38
|
+
rspackPlugin: () => rspackPlugin,
|
|
39
|
+
vitePlugin: () => vitePlugin,
|
|
40
|
+
webpackPlugin: () => webpackPlugin
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(index_exports);
|
|
43
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
44
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
45
|
+
var import_unplugin = require("unplugin");
|
|
46
|
+
|
|
47
|
+
// src/generator.ts
|
|
48
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
49
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
50
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
51
|
+
var import_lodash_es = require("lodash-es");
|
|
52
|
+
var import_fast_glob = __toESM(require("fast-glob"), 1);
|
|
53
|
+
|
|
54
|
+
// src/utils.ts
|
|
55
|
+
function createTrailingRunner(asyncFn) {
|
|
56
|
+
let isRunning = false;
|
|
57
|
+
let pendingArgs = null;
|
|
58
|
+
let pendingWaiters = [];
|
|
59
|
+
const startLoop = async (initialArgs) => {
|
|
60
|
+
isRunning = true;
|
|
61
|
+
let latestResult;
|
|
62
|
+
let currentArgs = initialArgs;
|
|
63
|
+
while (true) {
|
|
64
|
+
const argsToRun = currentArgs;
|
|
65
|
+
const currentWaiters = pendingWaiters;
|
|
66
|
+
pendingArgs = null;
|
|
67
|
+
pendingWaiters = [];
|
|
68
|
+
try {
|
|
69
|
+
latestResult = await asyncFn(...argsToRun);
|
|
70
|
+
currentWaiters.forEach((w) => w.resolve(latestResult));
|
|
71
|
+
} catch (err) {
|
|
72
|
+
currentWaiters.forEach((w) => w.reject(err));
|
|
73
|
+
}
|
|
74
|
+
if (pendingArgs !== null) {
|
|
75
|
+
currentArgs = pendingArgs;
|
|
76
|
+
} else {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
isRunning = false;
|
|
81
|
+
return latestResult;
|
|
82
|
+
};
|
|
83
|
+
return (...args) => {
|
|
84
|
+
if (!isRunning) {
|
|
85
|
+
return startLoop(args);
|
|
86
|
+
}
|
|
87
|
+
pendingArgs = args;
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
pendingWaiters.push({ resolve, reject });
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/generator.ts
|
|
95
|
+
var cachedFolderSet = null;
|
|
96
|
+
function generateModuleMapContent(folders, rootDir, typeDir, modulesPathStr) {
|
|
97
|
+
if (folders.length === 0) {
|
|
98
|
+
return `// This file is generated by @path-ioc/unplugin, do not edit.
|
|
99
|
+
|
|
100
|
+
declare global {
|
|
101
|
+
interface ModuleMap {
|
|
102
|
+
[key: string]: any;
|
|
103
|
+
}
|
|
104
|
+
interface ModularContainer {
|
|
105
|
+
[key: string]: any;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export {};
|
|
110
|
+
`;
|
|
111
|
+
}
|
|
112
|
+
const dtsDir = import_node_path.default.resolve(rootDir, typeDir);
|
|
113
|
+
const modulesRoot = import_node_path.default.resolve(rootDir, modulesPathStr);
|
|
114
|
+
const moduleFolderMap = /* @__PURE__ */ new Map();
|
|
115
|
+
const shortNameFullNamesMap = /* @__PURE__ */ new Map();
|
|
116
|
+
folders.forEach((relDir) => {
|
|
117
|
+
const dirPath = import_node_path.default.resolve(rootDir, relDir);
|
|
118
|
+
let importRelPath = import_node_path.default.relative(dtsDir, dirPath).replace(/\\/g, "/");
|
|
119
|
+
if (!importRelPath.startsWith(".")) {
|
|
120
|
+
importRelPath = "./" + importRelPath;
|
|
121
|
+
}
|
|
122
|
+
const logicalPath = import_node_path.default.relative(modulesRoot, dirPath).replace(/\\/g, "/");
|
|
123
|
+
const folderName = logicalPath.split("/").pop();
|
|
124
|
+
if (!folderName) return;
|
|
125
|
+
const moduleName = folderName.charAt(0) + (0, import_lodash_es.camelCase)(folderName).slice(1);
|
|
126
|
+
const logicalDir = logicalPath.substring(0, logicalPath.lastIndexOf(folderName));
|
|
127
|
+
const moduleFullName = `/${logicalDir}${moduleName}`;
|
|
128
|
+
moduleFolderMap.set(moduleFullName, importRelPath);
|
|
129
|
+
moduleFolderMap.set(moduleName, importRelPath);
|
|
130
|
+
const fullNames = shortNameFullNamesMap.get(moduleName) || [];
|
|
131
|
+
fullNames.push(moduleFullName);
|
|
132
|
+
shortNameFullNamesMap.set(moduleName, fullNames);
|
|
133
|
+
});
|
|
134
|
+
for (const [shortName, fullNames] of shortNameFullNamesMap.entries()) {
|
|
135
|
+
if (fullNames.length > 1) {
|
|
136
|
+
moduleFolderMap.delete(shortName);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const entries = [];
|
|
140
|
+
const containerEntries = [];
|
|
141
|
+
for (const [key, relPath] of moduleFolderMap.entries()) {
|
|
142
|
+
entries.push(` "${key}": typeof import("${relPath}/index");`);
|
|
143
|
+
containerEntries.push(` "${key}": Awaited<ReturnType<typeof import("${relPath}/index")["main"]>>;`);
|
|
144
|
+
}
|
|
145
|
+
return `// This file is generated by @path-ioc/unplugin, do not edit.
|
|
146
|
+
/// <reference types="@path-ioc/unplugin/virtual" />
|
|
147
|
+
|
|
148
|
+
declare global {
|
|
149
|
+
interface ModuleMap {
|
|
150
|
+
[key: string]: any;
|
|
151
|
+
${entries.join("\n")}
|
|
152
|
+
}
|
|
153
|
+
interface ModularContainer {
|
|
154
|
+
[key: string]: any;
|
|
155
|
+
${containerEntries.join("\n")}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export {};
|
|
160
|
+
`;
|
|
161
|
+
}
|
|
162
|
+
var doGenerateTypeDefinitions = async (rootDir, typeDir, modulesPathStr) => {
|
|
163
|
+
try {
|
|
164
|
+
const modulesRoot = import_node_path.default.resolve(rootDir, modulesPathStr);
|
|
165
|
+
const dotIgnorePath = import_node_path.default.resolve(rootDir, ".gitignore");
|
|
166
|
+
try {
|
|
167
|
+
const dotIgnoreContent = await import_promises.default.readFile(dotIgnorePath, "utf-8");
|
|
168
|
+
if (!dotIgnoreContent.includes("ignore.*")) {
|
|
169
|
+
await import_promises.default.appendFile(
|
|
170
|
+
dotIgnorePath,
|
|
171
|
+
`
|
|
172
|
+
|
|
173
|
+
# @path-ioc/unplugin
|
|
174
|
+
ignore.*
|
|
175
|
+
`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
} catch (e) {
|
|
179
|
+
}
|
|
180
|
+
const dtsDir = import_node_path.default.resolve(rootDir, typeDir);
|
|
181
|
+
await import_promises.default.mkdir(dtsDir, { recursive: true });
|
|
182
|
+
const dtsPath = import_node_path.default.resolve(dtsDir, "ignore.modular.d.ts");
|
|
183
|
+
const searchPattern = import_node_path.default.posix.join(modulesRoot.replace(/\\/g, "/"), "**/index.{ts,tsx}");
|
|
184
|
+
const files = await (0, import_fast_glob.default)(searchPattern, { absolute: true });
|
|
185
|
+
const folders = files.map((f) => import_node_path.default.relative(rootDir, import_node_path.default.dirname(f)));
|
|
186
|
+
if (cachedFolderSet && cachedFolderSet.size === folders.length && import_node_fs.default.existsSync(dtsPath)) {
|
|
187
|
+
let isIdentical = true;
|
|
188
|
+
for (let i = 0; i < folders.length; i++) {
|
|
189
|
+
if (!cachedFolderSet.has(folders[i])) {
|
|
190
|
+
isIdentical = false;
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (isIdentical) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
cachedFolderSet = new Set(folders);
|
|
199
|
+
const content = generateModuleMapContent(folders, rootDir, typeDir, modulesPathStr);
|
|
200
|
+
await import_promises.default.writeFile(dtsPath, content, { flag: "w" });
|
|
201
|
+
} catch (e) {
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
var generateTypeDefinitions = createTrailingRunner(doGenerateTypeDefinitions);
|
|
205
|
+
|
|
206
|
+
// src/index.ts
|
|
207
|
+
var VIRTUAL_MODULE_ID = "virtual:modular-container";
|
|
208
|
+
var RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
|
|
209
|
+
var PathIocPlugin = (0, import_unplugin.createUnplugin)((options = {}, meta) => {
|
|
210
|
+
const { typeFileOutput = "types", modulesPath = "src/modules" } = options;
|
|
211
|
+
let projectRoot = process.cwd();
|
|
212
|
+
const isWebpackLike = meta.framework === "webpack" || meta.framework === "rspack";
|
|
213
|
+
return {
|
|
214
|
+
name: "unplugin-path-ioc",
|
|
215
|
+
enforce: "pre",
|
|
216
|
+
// Webpack / Vite 钩子获取根目录
|
|
217
|
+
vite: {
|
|
218
|
+
configResolved(config) {
|
|
219
|
+
if (config && typeof config === "object" && "root" in config && typeof config.root === "string") {
|
|
220
|
+
projectRoot = import_node_path2.default.resolve(config.root);
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
async handleHotUpdate(ctx) {
|
|
224
|
+
if (ctx && typeof ctx === "object" && "file" in ctx && typeof ctx.file === "string") {
|
|
225
|
+
const file = ctx.file;
|
|
226
|
+
if (file.endsWith(".d.ts") || file.includes("ignore.")) return;
|
|
227
|
+
const relativeModulesPath = import_node_path2.default.normalize(modulesPath);
|
|
228
|
+
if (file.includes(import_node_path2.default.join(projectRoot, relativeModulesPath))) {
|
|
229
|
+
await generateTypeDefinitions(projectRoot, typeFileOutput, modulesPath);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
webpack(compiler) {
|
|
235
|
+
projectRoot = compiler.context;
|
|
236
|
+
const cleanPath = modulesPath.replace(/\/$/, "");
|
|
237
|
+
const virtualPath = import_node_path2.default.resolve(projectRoot, "node_modules/.virtual-modular-container.js");
|
|
238
|
+
const absModulesPath = import_node_path2.default.resolve(projectRoot, cleanPath).replace(/\\/g, "/");
|
|
239
|
+
const virtualCode = `
|
|
240
|
+
import { compileModuleGraph, instantiateModuleContainer } from '@path-ioc/core';
|
|
241
|
+
|
|
242
|
+
const reqContext = require.context('${absModulesPath}', true, /\\/index\\.[jt]sx?$/);
|
|
243
|
+
export const modules = reqContext.keys().map((k) => {
|
|
244
|
+
const rawKey = k.replace(/^\\.\\//, '').replace(/\\/index\\.[jt]sx?$/, '');
|
|
245
|
+
return { key: '/' + rawKey, module: reqContext(k) };
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
let compiledGraph = null;
|
|
249
|
+
|
|
250
|
+
export async function createModularContainer(modularContainer = {}) {
|
|
251
|
+
if (!compiledGraph) {
|
|
252
|
+
compiledGraph = compileModuleGraph(modules);
|
|
253
|
+
}
|
|
254
|
+
await instantiateModuleContainer(compiledGraph, modularContainer);
|
|
255
|
+
return modularContainer;
|
|
256
|
+
}
|
|
257
|
+
`;
|
|
258
|
+
try {
|
|
259
|
+
import_node_fs2.default.mkdirSync(import_node_path2.default.dirname(virtualPath), { recursive: true });
|
|
260
|
+
import_node_fs2.default.writeFileSync(virtualPath, virtualCode, "utf-8");
|
|
261
|
+
} catch (e) {
|
|
262
|
+
}
|
|
263
|
+
if (compiler.webpack && compiler.webpack.NormalModuleReplacementPlugin) {
|
|
264
|
+
new compiler.webpack.NormalModuleReplacementPlugin(
|
|
265
|
+
/^virtual:modular-container$/,
|
|
266
|
+
virtualPath
|
|
267
|
+
).apply(compiler);
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
resolveId(id) {
|
|
271
|
+
if (id === VIRTUAL_MODULE_ID || id.includes("virtual:modular-container")) {
|
|
272
|
+
if (isWebpackLike && projectRoot) {
|
|
273
|
+
return import_node_path2.default.resolve(projectRoot, "node_modules/.virtual-modular-container.js");
|
|
274
|
+
}
|
|
275
|
+
return RESOLVED_VIRTUAL_MODULE_ID;
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
loadInclude(id) {
|
|
279
|
+
const virtualPath = import_node_path2.default.resolve(projectRoot, "node_modules/.virtual-modular-container.js");
|
|
280
|
+
return id === RESOLVED_VIRTUAL_MODULE_ID || id === virtualPath || id.endsWith(".virtual-modular-container.js") || id.includes("virtual:modular-container");
|
|
281
|
+
},
|
|
282
|
+
load(id) {
|
|
283
|
+
const virtualPath = import_node_path2.default.resolve(projectRoot, "node_modules/.virtual-modular-container.js");
|
|
284
|
+
if (id === RESOLVED_VIRTUAL_MODULE_ID || id === virtualPath || id.endsWith(".virtual-modular-container.js") || id.includes("virtual:modular-container")) {
|
|
285
|
+
const cleanPath = modulesPath.replace(/\/$/, "");
|
|
286
|
+
if (isWebpackLike) {
|
|
287
|
+
const absModulesPath = import_node_path2.default.resolve(projectRoot, cleanPath).replace(/\\/g, "/");
|
|
288
|
+
return `
|
|
289
|
+
import { compileModuleGraph, instantiateModuleContainer } from '@path-ioc/core';
|
|
290
|
+
|
|
291
|
+
const reqContext = require.context('${absModulesPath}', true, /\\/index\\.[jt]sx?$/);
|
|
292
|
+
export const modules = reqContext.keys().map((k) => {
|
|
293
|
+
const rawKey = k.replace(/^\\.\\//, '').replace(/\\/index\\.[jt]sx?$/, '');
|
|
294
|
+
return { key: '/' + rawKey, module: reqContext(k) };
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
let compiledGraph = null;
|
|
298
|
+
|
|
299
|
+
export async function createModularContainer(modularContainer = {}) {
|
|
300
|
+
if (!compiledGraph) {
|
|
301
|
+
compiledGraph = compileModuleGraph(modules);
|
|
302
|
+
}
|
|
303
|
+
await instantiateModuleContainer(compiledGraph, modularContainer);
|
|
304
|
+
return modularContainer;
|
|
305
|
+
}
|
|
306
|
+
`;
|
|
307
|
+
}
|
|
308
|
+
return `
|
|
309
|
+
import { compileModuleGraph, instantiateModuleContainer } from '@path-ioc/core';
|
|
310
|
+
|
|
311
|
+
const viteModules = import.meta.glob(['/${cleanPath}/**/index.{ts,tsx}', './${cleanPath}/**/index.{ts,tsx}'], { eager: true });
|
|
312
|
+
export const modules = Object.entries(viteModules).map(([k, iocModule]) => {
|
|
313
|
+
const rawKey = k.replace(/^(\\.\\/|\\/)+/, '').replace('${cleanPath}', '').replace(/^(\\.\\/|\\/)+/, '').replace(/\\/index\\.(ts|tsx)$/, '');
|
|
314
|
+
return { key: '/' + rawKey, module: iocModule };
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
let compiledGraph = null;
|
|
318
|
+
|
|
319
|
+
export async function createModularContainer(modularContainer = {}) {
|
|
320
|
+
if (!compiledGraph) {
|
|
321
|
+
compiledGraph = compileModuleGraph(modules);
|
|
322
|
+
}
|
|
323
|
+
await instantiateModuleContainer(compiledGraph, modularContainer);
|
|
324
|
+
return modularContainer;
|
|
325
|
+
}
|
|
326
|
+
`;
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
async buildStart() {
|
|
330
|
+
await generateTypeDefinitions(projectRoot, typeFileOutput, modulesPath);
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
});
|
|
334
|
+
var vitePlugin = PathIocPlugin.vite;
|
|
335
|
+
var webpackPlugin = PathIocPlugin.webpack;
|
|
336
|
+
var rollupPlugin = PathIocPlugin.rollup;
|
|
337
|
+
var rspackPlugin = PathIocPlugin.rspack;
|
|
338
|
+
var esbuildPlugin = PathIocPlugin.esbuild;
|
|
339
|
+
var rolldownPlugin = PathIocPlugin.rolldown;
|
|
340
|
+
var pathIoc = PathIocPlugin;
|
|
341
|
+
var index_default = pathIoc;
|
|
342
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
343
|
+
0 && (module.exports = {
|
|
344
|
+
PathIocPlugin,
|
|
345
|
+
esbuildPlugin,
|
|
346
|
+
rolldownPlugin,
|
|
347
|
+
rollupPlugin,
|
|
348
|
+
rspackPlugin,
|
|
349
|
+
vitePlugin,
|
|
350
|
+
webpackPlugin
|
|
351
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as rolldown from 'rolldown';
|
|
2
|
+
import * as esbuild from 'esbuild';
|
|
3
|
+
import * as rollup from 'rollup';
|
|
4
|
+
import * as webpack from 'webpack';
|
|
5
|
+
import * as unplugin from 'unplugin';
|
|
6
|
+
import { Plugin } from 'vite';
|
|
7
|
+
|
|
8
|
+
interface PathIocPluginOptions {
|
|
9
|
+
/**
|
|
10
|
+
* 生成的类型文件的输出目录
|
|
11
|
+
* @default 'types'
|
|
12
|
+
*/
|
|
13
|
+
typeFileOutput?: string;
|
|
14
|
+
/**
|
|
15
|
+
* 模块扫描的根目录,相对于项目根目录
|
|
16
|
+
* @default 'src/modules'
|
|
17
|
+
*/
|
|
18
|
+
modulesPath?: string;
|
|
19
|
+
}
|
|
20
|
+
declare const PathIocPlugin: unplugin.UnpluginInstance<PathIocPluginOptions | undefined, boolean>;
|
|
21
|
+
type PathIocVitePlugin = Pick<Plugin, "name" | "enforce"> & {
|
|
22
|
+
buildStart?: () => Promise<void> | void;
|
|
23
|
+
resolveId?: (source: string, importer?: string, options?: any) => Promise<string | null | undefined | false | {
|
|
24
|
+
id: string;
|
|
25
|
+
}> | string | null | undefined | false | {
|
|
26
|
+
id: string;
|
|
27
|
+
};
|
|
28
|
+
load?: (id: string, options?: any) => Promise<string | null | undefined | {
|
|
29
|
+
code: string;
|
|
30
|
+
}> | string | null | undefined | {
|
|
31
|
+
code: string;
|
|
32
|
+
};
|
|
33
|
+
transform?: (code: string, id: string) => Promise<string | null | undefined | {
|
|
34
|
+
code: string;
|
|
35
|
+
}> | string | null | undefined | {
|
|
36
|
+
code: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
type PathIocPluginType = Omit<typeof PathIocPlugin, "vite"> & {
|
|
40
|
+
vite: (options?: PathIocPluginOptions) => PathIocVitePlugin;
|
|
41
|
+
};
|
|
42
|
+
declare const vitePlugin: (options?: PathIocPluginOptions) => PathIocVitePlugin;
|
|
43
|
+
declare const webpackPlugin: (options?: PathIocPluginOptions | undefined) => webpack.WebpackPluginInstance;
|
|
44
|
+
declare const rollupPlugin: (options?: PathIocPluginOptions | undefined) => rollup.Plugin<any> | rollup.Plugin<any>[];
|
|
45
|
+
declare const rspackPlugin: (options?: PathIocPluginOptions | undefined) => unplugin.RspackPluginInstance;
|
|
46
|
+
declare const esbuildPlugin: (options?: PathIocPluginOptions | undefined) => esbuild.Plugin;
|
|
47
|
+
declare const rolldownPlugin: (options?: PathIocPluginOptions | undefined) => rolldown.Plugin<any> | rolldown.Plugin<any>[];
|
|
48
|
+
declare const pathIoc: PathIocPluginType;
|
|
49
|
+
|
|
50
|
+
export { PathIocPlugin, type PathIocPluginOptions, type PathIocPluginType, type PathIocVitePlugin, pathIoc as default, esbuildPlugin, rolldownPlugin, rollupPlugin, rspackPlugin, vitePlugin, webpackPlugin };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as rolldown from 'rolldown';
|
|
2
|
+
import * as esbuild from 'esbuild';
|
|
3
|
+
import * as rollup from 'rollup';
|
|
4
|
+
import * as webpack from 'webpack';
|
|
5
|
+
import * as unplugin from 'unplugin';
|
|
6
|
+
import { Plugin } from 'vite';
|
|
7
|
+
|
|
8
|
+
interface PathIocPluginOptions {
|
|
9
|
+
/**
|
|
10
|
+
* 生成的类型文件的输出目录
|
|
11
|
+
* @default 'types'
|
|
12
|
+
*/
|
|
13
|
+
typeFileOutput?: string;
|
|
14
|
+
/**
|
|
15
|
+
* 模块扫描的根目录,相对于项目根目录
|
|
16
|
+
* @default 'src/modules'
|
|
17
|
+
*/
|
|
18
|
+
modulesPath?: string;
|
|
19
|
+
}
|
|
20
|
+
declare const PathIocPlugin: unplugin.UnpluginInstance<PathIocPluginOptions | undefined, boolean>;
|
|
21
|
+
type PathIocVitePlugin = Pick<Plugin, "name" | "enforce"> & {
|
|
22
|
+
buildStart?: () => Promise<void> | void;
|
|
23
|
+
resolveId?: (source: string, importer?: string, options?: any) => Promise<string | null | undefined | false | {
|
|
24
|
+
id: string;
|
|
25
|
+
}> | string | null | undefined | false | {
|
|
26
|
+
id: string;
|
|
27
|
+
};
|
|
28
|
+
load?: (id: string, options?: any) => Promise<string | null | undefined | {
|
|
29
|
+
code: string;
|
|
30
|
+
}> | string | null | undefined | {
|
|
31
|
+
code: string;
|
|
32
|
+
};
|
|
33
|
+
transform?: (code: string, id: string) => Promise<string | null | undefined | {
|
|
34
|
+
code: string;
|
|
35
|
+
}> | string | null | undefined | {
|
|
36
|
+
code: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
type PathIocPluginType = Omit<typeof PathIocPlugin, "vite"> & {
|
|
40
|
+
vite: (options?: PathIocPluginOptions) => PathIocVitePlugin;
|
|
41
|
+
};
|
|
42
|
+
declare const vitePlugin: (options?: PathIocPluginOptions) => PathIocVitePlugin;
|
|
43
|
+
declare const webpackPlugin: (options?: PathIocPluginOptions | undefined) => webpack.WebpackPluginInstance;
|
|
44
|
+
declare const rollupPlugin: (options?: PathIocPluginOptions | undefined) => rollup.Plugin<any> | rollup.Plugin<any>[];
|
|
45
|
+
declare const rspackPlugin: (options?: PathIocPluginOptions | undefined) => unplugin.RspackPluginInstance;
|
|
46
|
+
declare const esbuildPlugin: (options?: PathIocPluginOptions | undefined) => esbuild.Plugin;
|
|
47
|
+
declare const rolldownPlugin: (options?: PathIocPluginOptions | undefined) => rolldown.Plugin<any> | rolldown.Plugin<any>[];
|
|
48
|
+
declare const pathIoc: PathIocPluginType;
|
|
49
|
+
|
|
50
|
+
export { PathIocPlugin, type PathIocPluginOptions, type PathIocPluginType, type PathIocVitePlugin, pathIoc as default, esbuildPlugin, rolldownPlugin, rollupPlugin, rspackPlugin, vitePlugin, webpackPlugin };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import path2 from "path";
|
|
3
|
+
import fsSync2 from "fs";
|
|
4
|
+
import { createUnplugin } from "unplugin";
|
|
5
|
+
|
|
6
|
+
// src/generator.ts
|
|
7
|
+
import path from "path";
|
|
8
|
+
import fs from "fs/promises";
|
|
9
|
+
import fsSync from "fs";
|
|
10
|
+
import { camelCase } from "lodash-es";
|
|
11
|
+
import fg from "fast-glob";
|
|
12
|
+
|
|
13
|
+
// src/utils.ts
|
|
14
|
+
function createTrailingRunner(asyncFn) {
|
|
15
|
+
let isRunning = false;
|
|
16
|
+
let pendingArgs = null;
|
|
17
|
+
let pendingWaiters = [];
|
|
18
|
+
const startLoop = async (initialArgs) => {
|
|
19
|
+
isRunning = true;
|
|
20
|
+
let latestResult;
|
|
21
|
+
let currentArgs = initialArgs;
|
|
22
|
+
while (true) {
|
|
23
|
+
const argsToRun = currentArgs;
|
|
24
|
+
const currentWaiters = pendingWaiters;
|
|
25
|
+
pendingArgs = null;
|
|
26
|
+
pendingWaiters = [];
|
|
27
|
+
try {
|
|
28
|
+
latestResult = await asyncFn(...argsToRun);
|
|
29
|
+
currentWaiters.forEach((w) => w.resolve(latestResult));
|
|
30
|
+
} catch (err) {
|
|
31
|
+
currentWaiters.forEach((w) => w.reject(err));
|
|
32
|
+
}
|
|
33
|
+
if (pendingArgs !== null) {
|
|
34
|
+
currentArgs = pendingArgs;
|
|
35
|
+
} else {
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
isRunning = false;
|
|
40
|
+
return latestResult;
|
|
41
|
+
};
|
|
42
|
+
return (...args) => {
|
|
43
|
+
if (!isRunning) {
|
|
44
|
+
return startLoop(args);
|
|
45
|
+
}
|
|
46
|
+
pendingArgs = args;
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
pendingWaiters.push({ resolve, reject });
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/generator.ts
|
|
54
|
+
var cachedFolderSet = null;
|
|
55
|
+
function generateModuleMapContent(folders, rootDir, typeDir, modulesPathStr) {
|
|
56
|
+
if (folders.length === 0) {
|
|
57
|
+
return `// This file is generated by @path-ioc/unplugin, do not edit.
|
|
58
|
+
|
|
59
|
+
declare global {
|
|
60
|
+
interface ModuleMap {
|
|
61
|
+
[key: string]: any;
|
|
62
|
+
}
|
|
63
|
+
interface ModularContainer {
|
|
64
|
+
[key: string]: any;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export {};
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
71
|
+
const dtsDir = path.resolve(rootDir, typeDir);
|
|
72
|
+
const modulesRoot = path.resolve(rootDir, modulesPathStr);
|
|
73
|
+
const moduleFolderMap = /* @__PURE__ */ new Map();
|
|
74
|
+
const shortNameFullNamesMap = /* @__PURE__ */ new Map();
|
|
75
|
+
folders.forEach((relDir) => {
|
|
76
|
+
const dirPath = path.resolve(rootDir, relDir);
|
|
77
|
+
let importRelPath = path.relative(dtsDir, dirPath).replace(/\\/g, "/");
|
|
78
|
+
if (!importRelPath.startsWith(".")) {
|
|
79
|
+
importRelPath = "./" + importRelPath;
|
|
80
|
+
}
|
|
81
|
+
const logicalPath = path.relative(modulesRoot, dirPath).replace(/\\/g, "/");
|
|
82
|
+
const folderName = logicalPath.split("/").pop();
|
|
83
|
+
if (!folderName) return;
|
|
84
|
+
const moduleName = folderName.charAt(0) + camelCase(folderName).slice(1);
|
|
85
|
+
const logicalDir = logicalPath.substring(0, logicalPath.lastIndexOf(folderName));
|
|
86
|
+
const moduleFullName = `/${logicalDir}${moduleName}`;
|
|
87
|
+
moduleFolderMap.set(moduleFullName, importRelPath);
|
|
88
|
+
moduleFolderMap.set(moduleName, importRelPath);
|
|
89
|
+
const fullNames = shortNameFullNamesMap.get(moduleName) || [];
|
|
90
|
+
fullNames.push(moduleFullName);
|
|
91
|
+
shortNameFullNamesMap.set(moduleName, fullNames);
|
|
92
|
+
});
|
|
93
|
+
for (const [shortName, fullNames] of shortNameFullNamesMap.entries()) {
|
|
94
|
+
if (fullNames.length > 1) {
|
|
95
|
+
moduleFolderMap.delete(shortName);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const entries = [];
|
|
99
|
+
const containerEntries = [];
|
|
100
|
+
for (const [key, relPath] of moduleFolderMap.entries()) {
|
|
101
|
+
entries.push(` "${key}": typeof import("${relPath}/index");`);
|
|
102
|
+
containerEntries.push(` "${key}": Awaited<ReturnType<typeof import("${relPath}/index")["main"]>>;`);
|
|
103
|
+
}
|
|
104
|
+
return `// This file is generated by @path-ioc/unplugin, do not edit.
|
|
105
|
+
/// <reference types="@path-ioc/unplugin/virtual" />
|
|
106
|
+
|
|
107
|
+
declare global {
|
|
108
|
+
interface ModuleMap {
|
|
109
|
+
[key: string]: any;
|
|
110
|
+
${entries.join("\n")}
|
|
111
|
+
}
|
|
112
|
+
interface ModularContainer {
|
|
113
|
+
[key: string]: any;
|
|
114
|
+
${containerEntries.join("\n")}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export {};
|
|
119
|
+
`;
|
|
120
|
+
}
|
|
121
|
+
var doGenerateTypeDefinitions = async (rootDir, typeDir, modulesPathStr) => {
|
|
122
|
+
try {
|
|
123
|
+
const modulesRoot = path.resolve(rootDir, modulesPathStr);
|
|
124
|
+
const dotIgnorePath = path.resolve(rootDir, ".gitignore");
|
|
125
|
+
try {
|
|
126
|
+
const dotIgnoreContent = await fs.readFile(dotIgnorePath, "utf-8");
|
|
127
|
+
if (!dotIgnoreContent.includes("ignore.*")) {
|
|
128
|
+
await fs.appendFile(
|
|
129
|
+
dotIgnorePath,
|
|
130
|
+
`
|
|
131
|
+
|
|
132
|
+
# @path-ioc/unplugin
|
|
133
|
+
ignore.*
|
|
134
|
+
`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
} catch (e) {
|
|
138
|
+
}
|
|
139
|
+
const dtsDir = path.resolve(rootDir, typeDir);
|
|
140
|
+
await fs.mkdir(dtsDir, { recursive: true });
|
|
141
|
+
const dtsPath = path.resolve(dtsDir, "ignore.modular.d.ts");
|
|
142
|
+
const searchPattern = path.posix.join(modulesRoot.replace(/\\/g, "/"), "**/index.{ts,tsx}");
|
|
143
|
+
const files = await fg(searchPattern, { absolute: true });
|
|
144
|
+
const folders = files.map((f) => path.relative(rootDir, path.dirname(f)));
|
|
145
|
+
if (cachedFolderSet && cachedFolderSet.size === folders.length && fsSync.existsSync(dtsPath)) {
|
|
146
|
+
let isIdentical = true;
|
|
147
|
+
for (let i = 0; i < folders.length; i++) {
|
|
148
|
+
if (!cachedFolderSet.has(folders[i])) {
|
|
149
|
+
isIdentical = false;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (isIdentical) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
cachedFolderSet = new Set(folders);
|
|
158
|
+
const content = generateModuleMapContent(folders, rootDir, typeDir, modulesPathStr);
|
|
159
|
+
await fs.writeFile(dtsPath, content, { flag: "w" });
|
|
160
|
+
} catch (e) {
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
var generateTypeDefinitions = createTrailingRunner(doGenerateTypeDefinitions);
|
|
164
|
+
|
|
165
|
+
// src/index.ts
|
|
166
|
+
var VIRTUAL_MODULE_ID = "virtual:modular-container";
|
|
167
|
+
var RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
|
|
168
|
+
var PathIocPlugin = createUnplugin((options = {}, meta) => {
|
|
169
|
+
const { typeFileOutput = "types", modulesPath = "src/modules" } = options;
|
|
170
|
+
let projectRoot = process.cwd();
|
|
171
|
+
const isWebpackLike = meta.framework === "webpack" || meta.framework === "rspack";
|
|
172
|
+
return {
|
|
173
|
+
name: "unplugin-path-ioc",
|
|
174
|
+
enforce: "pre",
|
|
175
|
+
// Webpack / Vite 钩子获取根目录
|
|
176
|
+
vite: {
|
|
177
|
+
configResolved(config) {
|
|
178
|
+
if (config && typeof config === "object" && "root" in config && typeof config.root === "string") {
|
|
179
|
+
projectRoot = path2.resolve(config.root);
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
async handleHotUpdate(ctx) {
|
|
183
|
+
if (ctx && typeof ctx === "object" && "file" in ctx && typeof ctx.file === "string") {
|
|
184
|
+
const file = ctx.file;
|
|
185
|
+
if (file.endsWith(".d.ts") || file.includes("ignore.")) return;
|
|
186
|
+
const relativeModulesPath = path2.normalize(modulesPath);
|
|
187
|
+
if (file.includes(path2.join(projectRoot, relativeModulesPath))) {
|
|
188
|
+
await generateTypeDefinitions(projectRoot, typeFileOutput, modulesPath);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
webpack(compiler) {
|
|
194
|
+
projectRoot = compiler.context;
|
|
195
|
+
const cleanPath = modulesPath.replace(/\/$/, "");
|
|
196
|
+
const virtualPath = path2.resolve(projectRoot, "node_modules/.virtual-modular-container.js");
|
|
197
|
+
const absModulesPath = path2.resolve(projectRoot, cleanPath).replace(/\\/g, "/");
|
|
198
|
+
const virtualCode = `
|
|
199
|
+
import { compileModuleGraph, instantiateModuleContainer } from '@path-ioc/core';
|
|
200
|
+
|
|
201
|
+
const reqContext = require.context('${absModulesPath}', true, /\\/index\\.[jt]sx?$/);
|
|
202
|
+
export const modules = reqContext.keys().map((k) => {
|
|
203
|
+
const rawKey = k.replace(/^\\.\\//, '').replace(/\\/index\\.[jt]sx?$/, '');
|
|
204
|
+
return { key: '/' + rawKey, module: reqContext(k) };
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
let compiledGraph = null;
|
|
208
|
+
|
|
209
|
+
export async function createModularContainer(modularContainer = {}) {
|
|
210
|
+
if (!compiledGraph) {
|
|
211
|
+
compiledGraph = compileModuleGraph(modules);
|
|
212
|
+
}
|
|
213
|
+
await instantiateModuleContainer(compiledGraph, modularContainer);
|
|
214
|
+
return modularContainer;
|
|
215
|
+
}
|
|
216
|
+
`;
|
|
217
|
+
try {
|
|
218
|
+
fsSync2.mkdirSync(path2.dirname(virtualPath), { recursive: true });
|
|
219
|
+
fsSync2.writeFileSync(virtualPath, virtualCode, "utf-8");
|
|
220
|
+
} catch (e) {
|
|
221
|
+
}
|
|
222
|
+
if (compiler.webpack && compiler.webpack.NormalModuleReplacementPlugin) {
|
|
223
|
+
new compiler.webpack.NormalModuleReplacementPlugin(
|
|
224
|
+
/^virtual:modular-container$/,
|
|
225
|
+
virtualPath
|
|
226
|
+
).apply(compiler);
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
resolveId(id) {
|
|
230
|
+
if (id === VIRTUAL_MODULE_ID || id.includes("virtual:modular-container")) {
|
|
231
|
+
if (isWebpackLike && projectRoot) {
|
|
232
|
+
return path2.resolve(projectRoot, "node_modules/.virtual-modular-container.js");
|
|
233
|
+
}
|
|
234
|
+
return RESOLVED_VIRTUAL_MODULE_ID;
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
loadInclude(id) {
|
|
238
|
+
const virtualPath = path2.resolve(projectRoot, "node_modules/.virtual-modular-container.js");
|
|
239
|
+
return id === RESOLVED_VIRTUAL_MODULE_ID || id === virtualPath || id.endsWith(".virtual-modular-container.js") || id.includes("virtual:modular-container");
|
|
240
|
+
},
|
|
241
|
+
load(id) {
|
|
242
|
+
const virtualPath = path2.resolve(projectRoot, "node_modules/.virtual-modular-container.js");
|
|
243
|
+
if (id === RESOLVED_VIRTUAL_MODULE_ID || id === virtualPath || id.endsWith(".virtual-modular-container.js") || id.includes("virtual:modular-container")) {
|
|
244
|
+
const cleanPath = modulesPath.replace(/\/$/, "");
|
|
245
|
+
if (isWebpackLike) {
|
|
246
|
+
const absModulesPath = path2.resolve(projectRoot, cleanPath).replace(/\\/g, "/");
|
|
247
|
+
return `
|
|
248
|
+
import { compileModuleGraph, instantiateModuleContainer } from '@path-ioc/core';
|
|
249
|
+
|
|
250
|
+
const reqContext = require.context('${absModulesPath}', true, /\\/index\\.[jt]sx?$/);
|
|
251
|
+
export const modules = reqContext.keys().map((k) => {
|
|
252
|
+
const rawKey = k.replace(/^\\.\\//, '').replace(/\\/index\\.[jt]sx?$/, '');
|
|
253
|
+
return { key: '/' + rawKey, module: reqContext(k) };
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
let compiledGraph = null;
|
|
257
|
+
|
|
258
|
+
export async function createModularContainer(modularContainer = {}) {
|
|
259
|
+
if (!compiledGraph) {
|
|
260
|
+
compiledGraph = compileModuleGraph(modules);
|
|
261
|
+
}
|
|
262
|
+
await instantiateModuleContainer(compiledGraph, modularContainer);
|
|
263
|
+
return modularContainer;
|
|
264
|
+
}
|
|
265
|
+
`;
|
|
266
|
+
}
|
|
267
|
+
return `
|
|
268
|
+
import { compileModuleGraph, instantiateModuleContainer } from '@path-ioc/core';
|
|
269
|
+
|
|
270
|
+
const viteModules = import.meta.glob(['/${cleanPath}/**/index.{ts,tsx}', './${cleanPath}/**/index.{ts,tsx}'], { eager: true });
|
|
271
|
+
export const modules = Object.entries(viteModules).map(([k, iocModule]) => {
|
|
272
|
+
const rawKey = k.replace(/^(\\.\\/|\\/)+/, '').replace('${cleanPath}', '').replace(/^(\\.\\/|\\/)+/, '').replace(/\\/index\\.(ts|tsx)$/, '');
|
|
273
|
+
return { key: '/' + rawKey, module: iocModule };
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
let compiledGraph = null;
|
|
277
|
+
|
|
278
|
+
export async function createModularContainer(modularContainer = {}) {
|
|
279
|
+
if (!compiledGraph) {
|
|
280
|
+
compiledGraph = compileModuleGraph(modules);
|
|
281
|
+
}
|
|
282
|
+
await instantiateModuleContainer(compiledGraph, modularContainer);
|
|
283
|
+
return modularContainer;
|
|
284
|
+
}
|
|
285
|
+
`;
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
async buildStart() {
|
|
289
|
+
await generateTypeDefinitions(projectRoot, typeFileOutput, modulesPath);
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
});
|
|
293
|
+
var vitePlugin = PathIocPlugin.vite;
|
|
294
|
+
var webpackPlugin = PathIocPlugin.webpack;
|
|
295
|
+
var rollupPlugin = PathIocPlugin.rollup;
|
|
296
|
+
var rspackPlugin = PathIocPlugin.rspack;
|
|
297
|
+
var esbuildPlugin = PathIocPlugin.esbuild;
|
|
298
|
+
var rolldownPlugin = PathIocPlugin.rolldown;
|
|
299
|
+
var pathIoc = PathIocPlugin;
|
|
300
|
+
var index_default = pathIoc;
|
|
301
|
+
export {
|
|
302
|
+
PathIocPlugin,
|
|
303
|
+
index_default as default,
|
|
304
|
+
esbuildPlugin,
|
|
305
|
+
rolldownPlugin,
|
|
306
|
+
rollupPlugin,
|
|
307
|
+
rspackPlugin,
|
|
308
|
+
vitePlugin,
|
|
309
|
+
webpackPlugin
|
|
310
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@path-ioc/unplugin",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Universal dev plugin for Path-IoC generating virtual modular container and TypeScript typings",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"unplugin",
|
|
7
|
+
"vite-plugin",
|
|
8
|
+
"webpack-plugin",
|
|
9
|
+
"rspack-plugin",
|
|
10
|
+
"rollup-plugin",
|
|
11
|
+
"ioc",
|
|
12
|
+
"dependency-injection",
|
|
13
|
+
"code-generation"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://path-ioc.dev",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/path-ioc/path-ioc.git",
|
|
19
|
+
"directory": "packages/unplugin"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/path-ioc/path-ioc/issues"
|
|
23
|
+
},
|
|
24
|
+
"author": "Lian HanLin",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"main": "dist/index.cjs",
|
|
27
|
+
"module": "dist/index.js",
|
|
28
|
+
"types": "dist/index.d.ts",
|
|
29
|
+
"type": "module",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"import": "./dist/index.js",
|
|
34
|
+
"require": "./dist/index.cjs"
|
|
35
|
+
},
|
|
36
|
+
"./vite": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"import": "./dist/index.js",
|
|
39
|
+
"require": "./dist/index.cjs"
|
|
40
|
+
},
|
|
41
|
+
"./webpack": {
|
|
42
|
+
"types": "./dist/index.d.ts",
|
|
43
|
+
"import": "./dist/index.js",
|
|
44
|
+
"require": "./dist/index.cjs"
|
|
45
|
+
},
|
|
46
|
+
"./rspack": {
|
|
47
|
+
"types": "./dist/index.d.ts",
|
|
48
|
+
"import": "./dist/index.js",
|
|
49
|
+
"require": "./dist/index.cjs"
|
|
50
|
+
},
|
|
51
|
+
"./rollup": {
|
|
52
|
+
"types": "./dist/index.d.ts",
|
|
53
|
+
"import": "./dist/index.js",
|
|
54
|
+
"require": "./dist/index.cjs"
|
|
55
|
+
},
|
|
56
|
+
"./esbuild": {
|
|
57
|
+
"types": "./dist/index.d.ts",
|
|
58
|
+
"import": "./dist/index.js",
|
|
59
|
+
"require": "./dist/index.cjs"
|
|
60
|
+
},
|
|
61
|
+
"./rolldown": {
|
|
62
|
+
"types": "./dist/index.d.ts",
|
|
63
|
+
"import": "./dist/index.js",
|
|
64
|
+
"require": "./dist/index.cjs"
|
|
65
|
+
},
|
|
66
|
+
"./virtual": {
|
|
67
|
+
"types": "./virtual.d.ts"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"files": [
|
|
71
|
+
"dist",
|
|
72
|
+
"virtual.d.ts"
|
|
73
|
+
],
|
|
74
|
+
"publishConfig": {
|
|
75
|
+
"access": "public"
|
|
76
|
+
},
|
|
77
|
+
"dependencies": {
|
|
78
|
+
"fast-glob": "^3.3.2",
|
|
79
|
+
"lodash-es": "^4.17.21",
|
|
80
|
+
"unplugin": "^3.3.0",
|
|
81
|
+
"webpack-virtual-modules": "^0.6.2"
|
|
82
|
+
},
|
|
83
|
+
"peerDependencies": {
|
|
84
|
+
"vite": "*",
|
|
85
|
+
"webpack": "*",
|
|
86
|
+
"esbuild": "*",
|
|
87
|
+
"rollup": "*",
|
|
88
|
+
"rspack": "*",
|
|
89
|
+
"rolldown": "*"
|
|
90
|
+
},
|
|
91
|
+
"peerDependenciesMeta": {
|
|
92
|
+
"vite": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"webpack": {
|
|
96
|
+
"optional": true
|
|
97
|
+
},
|
|
98
|
+
"esbuild": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
101
|
+
"rollup": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"rspack": {
|
|
105
|
+
"optional": true
|
|
106
|
+
},
|
|
107
|
+
"rolldown": {
|
|
108
|
+
"optional": true
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"devDependencies": {
|
|
112
|
+
"@types/node": "^20.0.0",
|
|
113
|
+
"tsup": "^8.0.0",
|
|
114
|
+
"typescript": "^5.4.5",
|
|
115
|
+
"vite": "^8.2.2"
|
|
116
|
+
},
|
|
117
|
+
"scripts": {
|
|
118
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
119
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch"
|
|
120
|
+
}
|
|
121
|
+
}
|