@path-ioc/pack 0.1.1 → 0.1.3

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hanlin Lian
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <div align="center">
2
2
  <h1>@path-ioc/pack</h1>
3
3
  <p><b>Mesh Registry Distribution Bundler for Path-IoC</b></p>
4
- <p>专为微前端、组件库分发与 Mesh 网格化依赖设计的物理打包与发布构建插件</p>
4
+ <p>Physical bundling and publishing plugin designed for microfrontends, component distribution, and Mesh registry architectures</p>
5
5
 
6
6
  <p>
7
7
  <a href="https://www.npmjs.com/package/@path-ioc/pack"><img src="https://img.shields.io/npm/v/@path-ioc/pack.svg" alt="NPM version"></a>
@@ -9,42 +9,46 @@
9
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
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
11
  </p>
12
+
13
+ <p>
14
+ <b>English</b> | <a href="./README.zh-CN.md">简体中文</a> | <a href="https://path-ioc.dev/api/pack">Official Docs</a>
15
+ </p>
12
16
  </div>
13
17
 
14
18
  ---
15
19
 
16
- ## 核心特性 (Features)
20
+ ## Features
17
21
 
18
- - **物理入口自动生成 (Physical Entrypoint Generation)**:
19
- 在 Vite 构建流程中,自动深度扫描 `src/modules` 下所有包含 `index.ts/tsx` 的物理子目录,并在磁盘上自动生成/更新干净的入口文件(默认 `.modular-plugin-entry.ts`)。
20
- - **Mesh 注册表与类型全导出**:
21
- 自动生成统一的模块导入别名与导出,并导出标准运行期注册表数组 `modules`:
22
+ - **Physical Entrypoint Generation**:
23
+ During Vite builds, automatically scans `src/modules` for physical directories containing `index.ts/tsx` and synthesizes clean on-disk entrypoints (default `.modular-plugin-entry.ts`).
24
+ - **Full Mesh Registry & Type Exports**:
25
+ Generates unified module import aliases and exports the canonical runtime module registry array `modules`:
22
26
  ```typescript
23
27
  export const modules = [
24
28
  { key: "/math/add", module: _Modular_Mod_0 },
25
29
  { key: "/math/isEven", module: _Modular_Mod_1 },
26
30
  ];
27
31
  ```
28
- - **静态类型映射提取 (`sharedMappings`)**:
29
- 自动填充 `sharedMappings` 与 `sharedContainerMappings` 集合,为构建跨包 SDK 或微前端网格映射提供准确的类型描述。
30
- - **物理隔离与代码混淆兼容**:
31
- 物理生成的入口文件可直接用于 npm 打包流程,完美兼容各类 AST 物理打散与防篡改混淆工具。
32
+ - **Static Type Mapping Extraction (`sharedMappings`)**:
33
+ Fills `sharedMappings` and `sharedContainerMappings` to provide accurate type descriptions for cross-package SDKs or microfrontend mesh topologies.
34
+ - **Physical Isolation & Bundler Obfuscation Compatibility**:
35
+ Generated physical entrypoint files integrate seamlessly into standard npm packaging pipelines, fully compatible with downstream AST transformers and code protection tools.
32
36
 
33
37
  ---
34
38
 
35
- ## 安装 (Installation)
39
+ ## Installation
36
40
 
37
41
  ```bash
38
42
  pnpm add -D @path-ioc/pack
39
- # 或
43
+ # or
40
44
  npm install -D @path-ioc/pack
41
45
  ```
42
46
 
43
47
  ---
44
48
 
45
- ## 快速上手 (Quick Start)
49
+ ## Quick Start
46
50
 
47
- ### Vite 配置 (`vite.config.ts`)
51
+ ### Vite Configuration (`vite.config.ts`)
48
52
 
49
53
  ```typescript
50
54
  import { defineConfig } from "vite";
@@ -57,7 +61,7 @@ export default defineConfig({
57
61
  plugins: [
58
62
  modularPackPlugin({
59
63
  modulesPath: "src/modules",
60
- // 可选:自定义生成的入口文件路径(默认存放在 node_modules/.path-ioc/.modular-plugin-entry.ts)
64
+ // Optional: Custom on-disk entrypoint path (default: node_modules/.path-ioc/.modular-plugin-entry.ts)
61
65
  entryFile: "node_modules/.path-ioc/.modular-plugin-entry.ts",
62
66
  sharedMappings,
63
67
  sharedContainerMappings,
@@ -68,18 +72,18 @@ export default defineConfig({
68
72
 
69
73
  ---
70
74
 
71
- ## 配置选项 (PackPluginOptions)
75
+ ## Configuration Options (`PackPluginOptions`)
72
76
 
73
- | 配置项 | 类型 | 默认值 | 描述 |
77
+ | Option | Type | Default | Description |
74
78
  | :--- | :--- | :--- | :--- |
75
- | **`modulesPath`** | `string` | `'src/modules'` | 模块扫描的物理根目录路径。 |
76
- | **`entryFile`** | `string` | `'node_modules/.path-ioc/.modular-plugin-entry.ts'` | 物理生成的入口文件路径。 |
77
- | **`sharedMappings`** | `string[]` | `[]` *(可选)* | 接收生成的类型映射字符串数组引用。 |
78
- | **`sharedContainerMappings`** | `string[]` | `[]` *(可选)* | 接收生成的容器类型映射字符串数组引用。 |
79
+ | **`modulesPath`** | `string` | `'src/modules'` | Root directory scanned for modular IoC entrypoints. |
80
+ | **`entryFile`** | `string` | `'node_modules/.path-ioc/.modular-plugin-entry.ts'` | Target physical path for the generated entrypoint file. |
81
+ | **`sharedMappings`** | `string[]` | `[]` *(optional)* | Reference to an array that receives generated type mapping strings. |
82
+ | **`sharedContainerMappings`** | `string[]` | `[]` *(optional)* | Reference to an array that receives generated container type mapping strings. |
79
83
 
80
84
  ---
81
85
 
82
- ## 导出的 API
86
+ ## Exported API
83
87
 
84
88
  ```typescript
85
89
  import { modularPackPlugin, type PackPluginOptions } from "@path-ioc/pack";
@@ -87,7 +91,7 @@ import { modularPackPlugin, type PackPluginOptions } from "@path-ioc/pack";
87
91
 
88
92
  ---
89
93
 
90
- ## 开源协议 (License)
94
+ ## License
91
95
 
92
96
  Released under the [MIT License](./LICENSE).
93
- Copyright © 2026 [Path-IoC Organization](https://github.com/path-ioc) & Lian HanLin.
97
+ Copyright © 2026-present [Path-IoC Organization](https://github.com/path-ioc) & Lian HanLin.
@@ -0,0 +1,97 @@
1
+ <div align="center">
2
+ <h1>@path-ioc/pack</h1>
3
+ <p><b>Mesh Registry Distribution Bundler for Path-IoC</b></p>
4
+ <p>专为微前端、组件库分发与 Mesh 网格化依赖设计的物理打包与发布构建插件</p>
5
+
6
+ <p>
7
+ <a href="https://www.npmjs.com/package/@path-ioc/pack"><img src="https://img.shields.io/npm/v/@path-ioc/pack.svg" alt="NPM version"></a>
8
+ <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/npm/l/@path-ioc/pack.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
+ </p>
12
+
13
+ <p>
14
+ <a href="./README.md">English</a> | <b>简体中文</b> | <a href="https://path-ioc.dev/zh/api/pack">官方文档</a>
15
+ </p>
16
+ </div>
17
+
18
+ ---
19
+
20
+ ## 核心特性 (Features)
21
+
22
+ - **物理入口自动生成 (Physical Entrypoint Generation)**:
23
+ 在 Vite 构建流程中,自动深度扫描 `src/modules` 下所有包含 `index.ts/tsx` 的物理子目录,并在磁盘上自动生成/更新干净的入口文件(默认 `.modular-plugin-entry.ts`)。
24
+ - **Mesh 注册表与类型全导出**:
25
+ 自动生成统一的模块导入别名与导出,并导出标准运行期注册表数组 `modules`:
26
+ ```typescript
27
+ export const modules = [
28
+ { key: "/math/add", module: _Modular_Mod_0 },
29
+ { key: "/math/isEven", module: _Modular_Mod_1 },
30
+ ];
31
+ ```
32
+ - **静态类型映射提取 (`sharedMappings`)**:
33
+ 自动填充 `sharedMappings` 与 `sharedContainerMappings` 集合,为构建跨包 SDK 或微前端网格映射提供准确的类型描述。
34
+ - **物理隔离与代码混淆兼容**:
35
+ 物理生成的入口文件可直接用于 npm 打包流程,完美兼容各类 AST 物理打散与防篡改混淆工具。
36
+
37
+ ---
38
+
39
+ ## 安装 (Installation)
40
+
41
+ ```bash
42
+ pnpm add -D @path-ioc/pack
43
+ # 或
44
+ npm install -D @path-ioc/pack
45
+ ```
46
+
47
+ ---
48
+
49
+ ## 快速上手 (Quick Start)
50
+
51
+ ### Vite 配置 (`vite.config.ts`)
52
+
53
+ ```typescript
54
+ import { defineConfig } from "vite";
55
+ import { modularPackPlugin } from "@path-ioc/pack";
56
+
57
+ const sharedMappings: string[] = [];
58
+ const sharedContainerMappings: string[] = [];
59
+
60
+ export default defineConfig({
61
+ plugins: [
62
+ modularPackPlugin({
63
+ modulesPath: "src/modules",
64
+ // 可选:自定义生成的入口文件路径(默认存放在 node_modules/.path-ioc/.modular-plugin-entry.ts)
65
+ entryFile: "node_modules/.path-ioc/.modular-plugin-entry.ts",
66
+ sharedMappings,
67
+ sharedContainerMappings,
68
+ }),
69
+ ],
70
+ });
71
+ ```
72
+
73
+ ---
74
+
75
+ ## 配置选项 (PackPluginOptions)
76
+
77
+ | 配置项 | 类型 | 默认值 | 描述 |
78
+ | :--- | :--- | :--- | :--- |
79
+ | **`modulesPath`** | `string` | `'src/modules'` | 模块扫描的物理根目录路径。 |
80
+ | **`entryFile`** | `string` | `'node_modules/.path-ioc/.modular-plugin-entry.ts'` | 物理生成的入口文件路径。 |
81
+ | **`sharedMappings`** | `string[]` | `[]` *(可选)* | 接收生成的类型映射字符串数组引用。 |
82
+ | **`sharedContainerMappings`** | `string[]` | `[]` *(可选)* | 接收生成的容器类型映射字符串数组引用。 |
83
+
84
+ ---
85
+
86
+ ## 导出的 API
87
+
88
+ ```typescript
89
+ import { modularPackPlugin, type PackPluginOptions } from "@path-ioc/pack";
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 开源协议 (License)
95
+
96
+ Released under the [MIT License](./LICENSE).
97
+ Copyright © 2026 [Path-IoC Organization](https://github.com/path-ioc) & Lian HanLin.
package/dist/index.cjs CHANGED
@@ -35,21 +35,31 @@ __export(index_exports, {
35
35
  module.exports = __toCommonJS(index_exports);
36
36
  var import_node_path = __toESM(require("path"), 1);
37
37
  var import_promises = __toESM(require("fs/promises"), 1);
38
+ var import_node_fs = __toESM(require("fs"), 1);
39
+ var import_node_child_process = require("child_process");
40
+ var import_node_util = require("util");
38
41
  var import_lodash_es = require("lodash-es");
42
+ var import_javascript_obfuscator = __toESM(require("javascript-obfuscator"), 1);
43
+ var execAsync = (0, import_node_util.promisify)(import_node_child_process.exec);
39
44
  function modularPackPlugin({
40
45
  modulesPath = "src/modules",
41
46
  entryFile = "node_modules/.path-ioc/.modular-plugin-entry.ts",
47
+ outDir = "dist-plugin",
42
48
  sharedMappings = [],
43
49
  sharedContainerMappings = []
44
50
  } = {}) {
45
51
  let projectRoot;
52
+ let entryFilePath;
53
+ let outputFullPath;
54
+ let savedEntryLines = [];
46
55
  return {
47
56
  name: "vite-plugin-modular-pack",
48
57
  enforce: "pre",
49
58
  async config(config) {
50
59
  projectRoot = import_node_path.default.resolve(config.root || process.cwd());
60
+ outputFullPath = import_node_path.default.resolve(projectRoot, outDir);
51
61
  const modulesRoot = import_node_path.default.resolve(projectRoot, modulesPath);
52
- const entryFilePath = import_node_path.default.resolve(projectRoot, entryFile);
62
+ entryFilePath = import_node_path.default.resolve(projectRoot, entryFile);
53
63
  const entryFileDir = import_node_path.default.dirname(entryFilePath);
54
64
  await import_promises.default.mkdir(entryFileDir, { recursive: true });
55
65
  const absoluteFolders = await searchIndexTsFiles(modulesRoot);
@@ -108,8 +118,156 @@ function modularPackPlugin({
108
118
  entryLines.push(runtimeModulesArray.join(",\n"));
109
119
  entryLines.push(`];
110
120
  `);
121
+ savedEntryLines = [...entryLines];
111
122
  await import_promises.default.writeFile(entryFilePath, entryLines.join("\n"), "utf-8");
112
123
  console.log(`\x1B[32m[ModularPack] Generated physical entry file: ${entryFile}\x1B[0m`);
124
+ if (!config.build) config.build = {};
125
+ config.build.outDir = outDir;
126
+ config.build.emptyOutDir = true;
127
+ config.build.lib = {
128
+ entry: entryFilePath,
129
+ formats: ["es"],
130
+ fileName: () => "index.js"
131
+ };
132
+ if (!config.build.rollupOptions) config.build.rollupOptions = {};
133
+ if (config.build.rollupOptions.input) {
134
+ delete config.build.rollupOptions.input;
135
+ }
136
+ let pkg = {};
137
+ try {
138
+ const pkgPath = import_node_path.default.resolve(projectRoot, "package.json");
139
+ pkg = JSON.parse(import_node_fs.default.readFileSync(pkgPath, "utf-8"));
140
+ } catch {
141
+ }
142
+ const externalDeps = [
143
+ ...Object.keys(pkg.dependencies || {}),
144
+ ...Object.keys(pkg.peerDependencies || {})
145
+ ];
146
+ const existingExternal = config.build.rollupOptions.external;
147
+ config.build.rollupOptions.external = (source, importer, isResolved) => {
148
+ if (source.includes("?worker")) return false;
149
+ const isExternalDep = externalDeps.includes(source) || externalDeps.some((dep) => source.startsWith(`${dep}/`));
150
+ if (isExternalDep) return true;
151
+ if (existingExternal) {
152
+ if (Array.isArray(existingExternal)) {
153
+ if (existingExternal.includes(source)) return true;
154
+ } else if (typeof existingExternal === "function") {
155
+ if (existingExternal(source, importer, isResolved)) return true;
156
+ } else if (existingExternal instanceof RegExp) {
157
+ if (existingExternal.test(source)) return true;
158
+ }
159
+ }
160
+ return false;
161
+ };
162
+ if (!config.build.rollupOptions.output) {
163
+ config.build.rollupOptions.output = {};
164
+ }
165
+ if (Array.isArray(config.build.rollupOptions.output)) {
166
+ config.build.rollupOptions.output.forEach((out) => {
167
+ out.entryFileNames = "index.js";
168
+ });
169
+ } else {
170
+ config.build.rollupOptions.output.entryFileNames = "index.js";
171
+ }
172
+ },
173
+ async closeBundle() {
174
+ try {
175
+ await import_promises.default.access(outputFullPath);
176
+ } catch {
177
+ return;
178
+ }
179
+ try {
180
+ const dtsPath = import_node_path.default.resolve(outputFullPath, "index.d.ts");
181
+ const dtsContent = [
182
+ `/// <reference types="@path-ioc/unplugin/virtual" />`,
183
+ ...savedEntryLines.filter((l) => !l.startsWith("//")),
184
+ `declare global {`,
185
+ ` interface ModuleMap {`,
186
+ ...sharedMappings,
187
+ ` }`,
188
+ ``,
189
+ ` interface ModularContainer {`,
190
+ ...sharedContainerMappings,
191
+ ` }`,
192
+ `}`,
193
+ ``,
194
+ `export {};`,
195
+ ``
196
+ ].join("\n");
197
+ await import_promises.default.writeFile(dtsPath, dtsContent, "utf-8");
198
+ console.log(`\x1B[32m[ModularPack] Generated declarations: ${import_node_path.default.relative(projectRoot, dtsPath)}\x1B[0m`);
199
+ } catch (err) {
200
+ console.warn("[ModularPack] Failed to generate index.d.ts:", err);
201
+ }
202
+ if (process.env.MODULAR_OBFUSCATE !== "false") {
203
+ try {
204
+ const jsFiles = await searchJsFiles(outputFullPath);
205
+ for (const file of jsFiles) {
206
+ let content = await import_promises.default.readFile(file, "utf-8");
207
+ content = content.replace(/process\.env\.NODE_ENV/g, "GLOBAL_VITE_PROCESS_ENV_NODE_ENV");
208
+ content = content.replace(/import\.meta\.env\.MODE/g, "GLOBAL_VITE_IMPORT_META_ENV_MODE");
209
+ const obfuscationResult = import_javascript_obfuscator.default.obfuscate(content, {
210
+ compact: true,
211
+ controlFlowFlattening: false,
212
+ deadCodeInjection: false,
213
+ identifierNamesGenerator: "hexadecimal",
214
+ renameGlobals: false,
215
+ selfDefending: false,
216
+ stringArray: true,
217
+ stringArrayEncoding: ["base64"],
218
+ transformObjectKeys: true,
219
+ unicodeEscapeSequence: false,
220
+ reservedStrings: ["\\.\\./assets/.*\\.js$", "\\./assets/.*\\.js$"]
221
+ });
222
+ let obfuscatedCode = obfuscationResult.getObfuscatedCode();
223
+ obfuscatedCode = obfuscatedCode.replace(/GLOBAL_VITE_PROCESS_ENV_NODE_ENV/g, "process.env.NODE_ENV");
224
+ obfuscatedCode = obfuscatedCode.replace(/GLOBAL_VITE_IMPORT_META_ENV_MODE/g, "import.meta.env.MODE");
225
+ await import_promises.default.writeFile(file, obfuscatedCode, "utf-8");
226
+ }
227
+ if (jsFiles.length > 0) {
228
+ console.log(`\x1B[32m[ModularPack] Obfuscated output JS files successfully!\x1B[0m`);
229
+ }
230
+ } catch (err) {
231
+ console.error("[ModularPack] Error during JS obfuscation:", err);
232
+ }
233
+ }
234
+ let pkg = {};
235
+ try {
236
+ const pkgPath = import_node_path.default.resolve(projectRoot, "package.json");
237
+ pkg = JSON.parse(await import_promises.default.readFile(pkgPath, "utf-8"));
238
+ } catch {
239
+ }
240
+ const mergedPeerDeps = {
241
+ ...pkg.dependencies || {},
242
+ ...pkg.peerDependencies || {}
243
+ };
244
+ const deliveryPkg = {
245
+ name: pkg.name || "modular-plugin",
246
+ version: pkg.version || "0.0.1",
247
+ type: "module",
248
+ main: "./index.js",
249
+ module: "./index.js",
250
+ types: "./index.d.ts",
251
+ files: ["index.js", "index.d.ts", "assets", "src"],
252
+ peerDependencies: mergedPeerDeps
253
+ };
254
+ try {
255
+ await import_promises.default.writeFile(
256
+ import_node_path.default.resolve(outputFullPath, "package.json"),
257
+ JSON.stringify(deliveryPkg, null, 2),
258
+ "utf-8"
259
+ );
260
+ } catch (err) {
261
+ console.warn("[ModularPack] Failed to generate delivery package.json:", err);
262
+ }
263
+ try {
264
+ await execAsync("npm pack", { cwd: outputFullPath });
265
+ console.log(`
266
+ \x1B[32m[ModularPack] Successfully built and packed vendor package! (Version: ${deliveryPkg.version})\x1B[0m
267
+ `);
268
+ } catch (err) {
269
+ console.warn(`[ModularPack] Failed to execute 'npm pack' in "${outDir}":`, err);
270
+ }
113
271
  }
114
272
  };
115
273
  }
@@ -141,6 +299,22 @@ var searchIndexTsFiles = async (rootPath) => {
141
299
  }
142
300
  return result;
143
301
  };
302
+ var searchJsFiles = async (dirPath) => {
303
+ const result = [];
304
+ try {
305
+ const entries = await import_promises.default.readdir(dirPath, { withFileTypes: true });
306
+ for (const entry of entries) {
307
+ const fullPath = import_node_path.default.join(dirPath, entry.name);
308
+ if (entry.isDirectory()) {
309
+ result.push(...await searchJsFiles(fullPath));
310
+ } else if (/\.(js|cjs|mjs)$/.test(entry.name) && !entry.name.includes("worker")) {
311
+ result.push(fullPath);
312
+ }
313
+ }
314
+ } catch {
315
+ }
316
+ return result;
317
+ };
144
318
  // Annotate the CommonJS export names for ESM import in node:
145
319
  0 && (module.exports = {
146
320
  modularPackPlugin
package/dist/index.d.cts CHANGED
@@ -1,12 +1,30 @@
1
1
  import { Plugin } from 'vite';
2
2
 
3
3
  interface PackPluginOptions {
4
+ /**
5
+ * Root directory to scan for modules containing index.ts or index.tsx.
6
+ * @default "src/modules"
7
+ */
4
8
  modulesPath?: string;
9
+ /**
10
+ * Destination path for the physical entry file.
11
+ * @default "node_modules/.path-ioc/.modular-plugin-entry.ts"
12
+ */
5
13
  entryFile?: string;
14
+ /**
15
+ * Output directory for the packaged library bundle.
16
+ * @default "dist-plugin"
17
+ */
18
+ outDir?: string;
19
+ /**
20
+ * Shared type mappings array reference (optional).
21
+ */
6
22
  sharedMappings?: string[];
23
+ /**
24
+ * Shared container type mappings array reference (optional).
25
+ */
7
26
  sharedContainerMappings?: string[];
8
27
  }
9
- type ModularPackPlugin = Pick<Plugin, "name" | "enforce" | "config">;
10
- declare function modularPackPlugin({ modulesPath, entryFile, sharedMappings, sharedContainerMappings, }?: PackPluginOptions): ModularPackPlugin;
28
+ declare function modularPackPlugin({ modulesPath, entryFile, outDir, sharedMappings, sharedContainerMappings, }?: PackPluginOptions): Plugin;
11
29
 
12
- export { type ModularPackPlugin, type PackPluginOptions, modularPackPlugin };
30
+ export { type PackPluginOptions, modularPackPlugin };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,30 @@
1
1
  import { Plugin } from 'vite';
2
2
 
3
3
  interface PackPluginOptions {
4
+ /**
5
+ * Root directory to scan for modules containing index.ts or index.tsx.
6
+ * @default "src/modules"
7
+ */
4
8
  modulesPath?: string;
9
+ /**
10
+ * Destination path for the physical entry file.
11
+ * @default "node_modules/.path-ioc/.modular-plugin-entry.ts"
12
+ */
5
13
  entryFile?: string;
14
+ /**
15
+ * Output directory for the packaged library bundle.
16
+ * @default "dist-plugin"
17
+ */
18
+ outDir?: string;
19
+ /**
20
+ * Shared type mappings array reference (optional).
21
+ */
6
22
  sharedMappings?: string[];
23
+ /**
24
+ * Shared container type mappings array reference (optional).
25
+ */
7
26
  sharedContainerMappings?: string[];
8
27
  }
9
- type ModularPackPlugin = Pick<Plugin, "name" | "enforce" | "config">;
10
- declare function modularPackPlugin({ modulesPath, entryFile, sharedMappings, sharedContainerMappings, }?: PackPluginOptions): ModularPackPlugin;
28
+ declare function modularPackPlugin({ modulesPath, entryFile, outDir, sharedMappings, sharedContainerMappings, }?: PackPluginOptions): Plugin;
11
29
 
12
- export { type ModularPackPlugin, type PackPluginOptions, modularPackPlugin };
30
+ export { type PackPluginOptions, modularPackPlugin };
package/dist/index.js CHANGED
@@ -1,21 +1,31 @@
1
1
  // src/index.ts
2
2
  import path from "path";
3
3
  import fs from "fs/promises";
4
+ import fsSync from "fs";
5
+ import { exec } from "child_process";
6
+ import { promisify } from "util";
4
7
  import { camelCase } from "lodash-es";
8
+ import JavaScriptObfuscator from "javascript-obfuscator";
9
+ var execAsync = promisify(exec);
5
10
  function modularPackPlugin({
6
11
  modulesPath = "src/modules",
7
12
  entryFile = "node_modules/.path-ioc/.modular-plugin-entry.ts",
13
+ outDir = "dist-plugin",
8
14
  sharedMappings = [],
9
15
  sharedContainerMappings = []
10
16
  } = {}) {
11
17
  let projectRoot;
18
+ let entryFilePath;
19
+ let outputFullPath;
20
+ let savedEntryLines = [];
12
21
  return {
13
22
  name: "vite-plugin-modular-pack",
14
23
  enforce: "pre",
15
24
  async config(config) {
16
25
  projectRoot = path.resolve(config.root || process.cwd());
26
+ outputFullPath = path.resolve(projectRoot, outDir);
17
27
  const modulesRoot = path.resolve(projectRoot, modulesPath);
18
- const entryFilePath = path.resolve(projectRoot, entryFile);
28
+ entryFilePath = path.resolve(projectRoot, entryFile);
19
29
  const entryFileDir = path.dirname(entryFilePath);
20
30
  await fs.mkdir(entryFileDir, { recursive: true });
21
31
  const absoluteFolders = await searchIndexTsFiles(modulesRoot);
@@ -74,8 +84,156 @@ function modularPackPlugin({
74
84
  entryLines.push(runtimeModulesArray.join(",\n"));
75
85
  entryLines.push(`];
76
86
  `);
87
+ savedEntryLines = [...entryLines];
77
88
  await fs.writeFile(entryFilePath, entryLines.join("\n"), "utf-8");
78
89
  console.log(`\x1B[32m[ModularPack] Generated physical entry file: ${entryFile}\x1B[0m`);
90
+ if (!config.build) config.build = {};
91
+ config.build.outDir = outDir;
92
+ config.build.emptyOutDir = true;
93
+ config.build.lib = {
94
+ entry: entryFilePath,
95
+ formats: ["es"],
96
+ fileName: () => "index.js"
97
+ };
98
+ if (!config.build.rollupOptions) config.build.rollupOptions = {};
99
+ if (config.build.rollupOptions.input) {
100
+ delete config.build.rollupOptions.input;
101
+ }
102
+ let pkg = {};
103
+ try {
104
+ const pkgPath = path.resolve(projectRoot, "package.json");
105
+ pkg = JSON.parse(fsSync.readFileSync(pkgPath, "utf-8"));
106
+ } catch {
107
+ }
108
+ const externalDeps = [
109
+ ...Object.keys(pkg.dependencies || {}),
110
+ ...Object.keys(pkg.peerDependencies || {})
111
+ ];
112
+ const existingExternal = config.build.rollupOptions.external;
113
+ config.build.rollupOptions.external = (source, importer, isResolved) => {
114
+ if (source.includes("?worker")) return false;
115
+ const isExternalDep = externalDeps.includes(source) || externalDeps.some((dep) => source.startsWith(`${dep}/`));
116
+ if (isExternalDep) return true;
117
+ if (existingExternal) {
118
+ if (Array.isArray(existingExternal)) {
119
+ if (existingExternal.includes(source)) return true;
120
+ } else if (typeof existingExternal === "function") {
121
+ if (existingExternal(source, importer, isResolved)) return true;
122
+ } else if (existingExternal instanceof RegExp) {
123
+ if (existingExternal.test(source)) return true;
124
+ }
125
+ }
126
+ return false;
127
+ };
128
+ if (!config.build.rollupOptions.output) {
129
+ config.build.rollupOptions.output = {};
130
+ }
131
+ if (Array.isArray(config.build.rollupOptions.output)) {
132
+ config.build.rollupOptions.output.forEach((out) => {
133
+ out.entryFileNames = "index.js";
134
+ });
135
+ } else {
136
+ config.build.rollupOptions.output.entryFileNames = "index.js";
137
+ }
138
+ },
139
+ async closeBundle() {
140
+ try {
141
+ await fs.access(outputFullPath);
142
+ } catch {
143
+ return;
144
+ }
145
+ try {
146
+ const dtsPath = path.resolve(outputFullPath, "index.d.ts");
147
+ const dtsContent = [
148
+ `/// <reference types="@path-ioc/unplugin/virtual" />`,
149
+ ...savedEntryLines.filter((l) => !l.startsWith("//")),
150
+ `declare global {`,
151
+ ` interface ModuleMap {`,
152
+ ...sharedMappings,
153
+ ` }`,
154
+ ``,
155
+ ` interface ModularContainer {`,
156
+ ...sharedContainerMappings,
157
+ ` }`,
158
+ `}`,
159
+ ``,
160
+ `export {};`,
161
+ ``
162
+ ].join("\n");
163
+ await fs.writeFile(dtsPath, dtsContent, "utf-8");
164
+ console.log(`\x1B[32m[ModularPack] Generated declarations: ${path.relative(projectRoot, dtsPath)}\x1B[0m`);
165
+ } catch (err) {
166
+ console.warn("[ModularPack] Failed to generate index.d.ts:", err);
167
+ }
168
+ if (process.env.MODULAR_OBFUSCATE !== "false") {
169
+ try {
170
+ const jsFiles = await searchJsFiles(outputFullPath);
171
+ for (const file of jsFiles) {
172
+ let content = await fs.readFile(file, "utf-8");
173
+ content = content.replace(/process\.env\.NODE_ENV/g, "GLOBAL_VITE_PROCESS_ENV_NODE_ENV");
174
+ content = content.replace(/import\.meta\.env\.MODE/g, "GLOBAL_VITE_IMPORT_META_ENV_MODE");
175
+ const obfuscationResult = JavaScriptObfuscator.obfuscate(content, {
176
+ compact: true,
177
+ controlFlowFlattening: false,
178
+ deadCodeInjection: false,
179
+ identifierNamesGenerator: "hexadecimal",
180
+ renameGlobals: false,
181
+ selfDefending: false,
182
+ stringArray: true,
183
+ stringArrayEncoding: ["base64"],
184
+ transformObjectKeys: true,
185
+ unicodeEscapeSequence: false,
186
+ reservedStrings: ["\\.\\./assets/.*\\.js$", "\\./assets/.*\\.js$"]
187
+ });
188
+ let obfuscatedCode = obfuscationResult.getObfuscatedCode();
189
+ obfuscatedCode = obfuscatedCode.replace(/GLOBAL_VITE_PROCESS_ENV_NODE_ENV/g, "process.env.NODE_ENV");
190
+ obfuscatedCode = obfuscatedCode.replace(/GLOBAL_VITE_IMPORT_META_ENV_MODE/g, "import.meta.env.MODE");
191
+ await fs.writeFile(file, obfuscatedCode, "utf-8");
192
+ }
193
+ if (jsFiles.length > 0) {
194
+ console.log(`\x1B[32m[ModularPack] Obfuscated output JS files successfully!\x1B[0m`);
195
+ }
196
+ } catch (err) {
197
+ console.error("[ModularPack] Error during JS obfuscation:", err);
198
+ }
199
+ }
200
+ let pkg = {};
201
+ try {
202
+ const pkgPath = path.resolve(projectRoot, "package.json");
203
+ pkg = JSON.parse(await fs.readFile(pkgPath, "utf-8"));
204
+ } catch {
205
+ }
206
+ const mergedPeerDeps = {
207
+ ...pkg.dependencies || {},
208
+ ...pkg.peerDependencies || {}
209
+ };
210
+ const deliveryPkg = {
211
+ name: pkg.name || "modular-plugin",
212
+ version: pkg.version || "0.0.1",
213
+ type: "module",
214
+ main: "./index.js",
215
+ module: "./index.js",
216
+ types: "./index.d.ts",
217
+ files: ["index.js", "index.d.ts", "assets", "src"],
218
+ peerDependencies: mergedPeerDeps
219
+ };
220
+ try {
221
+ await fs.writeFile(
222
+ path.resolve(outputFullPath, "package.json"),
223
+ JSON.stringify(deliveryPkg, null, 2),
224
+ "utf-8"
225
+ );
226
+ } catch (err) {
227
+ console.warn("[ModularPack] Failed to generate delivery package.json:", err);
228
+ }
229
+ try {
230
+ await execAsync("npm pack", { cwd: outputFullPath });
231
+ console.log(`
232
+ \x1B[32m[ModularPack] Successfully built and packed vendor package! (Version: ${deliveryPkg.version})\x1B[0m
233
+ `);
234
+ } catch (err) {
235
+ console.warn(`[ModularPack] Failed to execute 'npm pack' in "${outDir}":`, err);
236
+ }
79
237
  }
80
238
  };
81
239
  }
@@ -107,6 +265,22 @@ var searchIndexTsFiles = async (rootPath) => {
107
265
  }
108
266
  return result;
109
267
  };
268
+ var searchJsFiles = async (dirPath) => {
269
+ const result = [];
270
+ try {
271
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
272
+ for (const entry of entries) {
273
+ const fullPath = path.join(dirPath, entry.name);
274
+ if (entry.isDirectory()) {
275
+ result.push(...await searchJsFiles(fullPath));
276
+ } else if (/\.(js|cjs|mjs)$/.test(entry.name) && !entry.name.includes("worker")) {
277
+ result.push(fullPath);
278
+ }
279
+ }
280
+ } catch {
281
+ }
282
+ return result;
283
+ };
110
284
  export {
111
285
  modularPackPlugin
112
286
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@path-ioc/pack",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Mesh registry distribution bundler & obfuscator for Path-IoC",
5
5
  "keywords": [
6
6
  "ioc",
@@ -50,11 +50,11 @@
50
50
  }
51
51
  },
52
52
  "devDependencies": {
53
+ "@path-ioc/unplugin": "0.1.3",
53
54
  "@types/node": "^20.0.0",
54
- "vite": "^8.2.2",
55
55
  "tsup": "^8.0.0",
56
56
  "typescript": "^5.4.5",
57
- "@path-ioc/unplugin": "0.1.1"
57
+ "vite": "^8.2.2"
58
58
  },
59
59
  "scripts": {
60
60
  "build": "tsup src/index.ts --format cjs,esm --dts",