@yumerijs/loader 1.1.1 → 1.2.2
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/dist/index.d.ts +1 -7
- package/dist/index.js +62 -101
- package/package.json +6 -8
package/dist/index.d.ts
CHANGED
|
@@ -21,13 +21,7 @@ declare class PluginLoader {
|
|
|
21
21
|
logger: Logger;
|
|
22
22
|
constructor(core?: Core, config?: Config, pluginsDir?: string);
|
|
23
23
|
setCoreAndConfig(core: Core, config: Config): void;
|
|
24
|
-
/**
|
|
25
|
-
* 从指定路径加载插件.
|
|
26
|
-
* @param pluginPath 插件路径.
|
|
27
|
-
* @param isLocalPlugin 是否是本地插件
|
|
28
|
-
* @returns 加载的插件对象.
|
|
29
|
-
* @throws 如果插件加载失败.
|
|
30
|
-
*/
|
|
31
24
|
private loadPluginFromPath;
|
|
25
|
+
private clearRequireCache;
|
|
32
26
|
}
|
|
33
27
|
export default PluginLoader;
|
package/dist/index.js
CHANGED
|
@@ -38,7 +38,7 @@ const core_1 = require("@yumerijs/core");
|
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const util_1 = require("util");
|
|
40
40
|
const child_process_1 = require("child_process");
|
|
41
|
-
const
|
|
41
|
+
const url_1 = require("url");
|
|
42
42
|
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
43
43
|
class PluginLoader {
|
|
44
44
|
pluginCache = {};
|
|
@@ -53,168 +53,129 @@ class PluginLoader {
|
|
|
53
53
|
this.config = config || null;
|
|
54
54
|
this.isDev = process.env.NODE_ENV === 'development';
|
|
55
55
|
this.pluginsDir = pluginsDir;
|
|
56
|
-
tsNode.register({
|
|
57
|
-
transpileOnly: true, // Use transpileOnly for faster compilation
|
|
58
|
-
compilerOptions: {
|
|
59
|
-
module: 'CommonJS' // Ensure CommonJS for compatibility with require
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
56
|
}
|
|
63
57
|
setCoreAndConfig(core, config) {
|
|
64
58
|
this.core = core;
|
|
65
59
|
this.config = config;
|
|
66
60
|
}
|
|
67
|
-
/**
|
|
68
|
-
* 从本地目录或 npm 包加载插件.
|
|
69
|
-
* @param pluginName 插件名称或路径.
|
|
70
|
-
* @returns 加载的插件对象.
|
|
71
|
-
* @throws 如果插件加载失败.
|
|
72
|
-
*/
|
|
73
61
|
async load(pluginName) {
|
|
74
62
|
if (this.pluginCache[pluginName] && !this.isDev) {
|
|
75
|
-
// this.logger.info(`Returning cached plugin: ${pluginName}`);
|
|
76
63
|
return this.pluginCache[pluginName];
|
|
77
64
|
}
|
|
78
|
-
// this.logger.info('test')
|
|
79
65
|
let pluginPath;
|
|
80
66
|
let isLocalPlugin = false;
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
const localPluginPath1 = path.resolve(pluginName);
|
|
67
|
+
const localPluginPath = path.resolve(process.cwd(), this.pluginsDir, pluginName);
|
|
68
|
+
const localPluginPathAlt = path.resolve(process.cwd(), pluginName);
|
|
84
69
|
if (fs.existsSync(localPluginPath)) {
|
|
85
70
|
pluginPath = localPluginPath;
|
|
86
71
|
isLocalPlugin = true;
|
|
87
72
|
}
|
|
88
|
-
else if (fs.existsSync(
|
|
89
|
-
pluginPath =
|
|
73
|
+
else if (fs.existsSync(localPluginPathAlt)) {
|
|
74
|
+
pluginPath = localPluginPathAlt;
|
|
90
75
|
isLocalPlugin = true;
|
|
91
76
|
}
|
|
92
|
-
// 2. 检查是否是绝对路径或相对路径
|
|
93
77
|
else if (path.isAbsolute(pluginName) || pluginName.startsWith('.')) {
|
|
94
78
|
pluginPath = path.resolve(pluginName);
|
|
95
79
|
isLocalPlugin = true;
|
|
96
80
|
}
|
|
97
|
-
// 3. 尝试作为 npm 包加载
|
|
98
81
|
else {
|
|
99
82
|
try {
|
|
100
|
-
|
|
101
|
-
require.resolve(pluginName); // 检查包是否已安装
|
|
102
|
-
pluginPath = pluginName;
|
|
83
|
+
pluginPath = require.resolve(pluginName);
|
|
103
84
|
}
|
|
104
85
|
catch (e) {
|
|
105
|
-
// 如果 require.resolve 失败,则抛出错误
|
|
106
86
|
if (e.code === 'MODULE_NOT_FOUND') {
|
|
107
87
|
throw new Error(`Plugin ${pluginName} not found. Please install it first.`);
|
|
108
88
|
}
|
|
109
|
-
throw e;
|
|
89
|
+
throw e;
|
|
110
90
|
}
|
|
111
91
|
}
|
|
112
92
|
try {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
93
|
+
if (isLocalPlugin) {
|
|
94
|
+
const plugin = await this.loadPluginFromPath(pluginPath, isLocalPlugin);
|
|
95
|
+
this.pluginCache[pluginName] = plugin;
|
|
96
|
+
return plugin;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
const plugin = await Promise.resolve(`${pluginName}`).then(s => __importStar(require(s)));
|
|
100
|
+
return plugin.default || plugin;
|
|
101
|
+
}
|
|
116
102
|
}
|
|
117
103
|
catch (e) {
|
|
118
104
|
this.logger.error(`Failed to load plugin from ${pluginPath}:`, e);
|
|
119
105
|
throw e;
|
|
120
106
|
}
|
|
121
|
-
// const plugin = require(pluginName);
|
|
122
|
-
// this.pluginCache[pluginName] = plugin;
|
|
123
|
-
// return plugin;
|
|
124
107
|
}
|
|
125
|
-
/**
|
|
126
|
-
* 从指定路径加载插件.
|
|
127
|
-
* @param pluginPath 插件路径.
|
|
128
|
-
* @param isLocalPlugin 是否是本地插件
|
|
129
|
-
* @returns 加载的插件对象.
|
|
130
|
-
* @throws 如果插件加载失败.
|
|
131
|
-
*/
|
|
132
108
|
async loadPluginFromPath(pluginPath, isLocalPlugin) {
|
|
133
109
|
try {
|
|
134
|
-
let jsonPath;
|
|
135
110
|
let targetPath = pluginPath;
|
|
136
111
|
if (isLocalPlugin && this.isDev) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
// 检查目标文件是否是 TypeScript 文件
|
|
145
|
-
if (targetPath.endsWith('.ts')) {
|
|
146
|
-
// 清除该文件的缓存,确保获取最新版本
|
|
147
|
-
const resolvedPath = require.resolve(targetPath);
|
|
148
|
-
if (require.cache[resolvedPath]) {
|
|
149
|
-
delete require.cache[resolvedPath];
|
|
112
|
+
const jsonPath = path.join(pluginPath, 'package.json');
|
|
113
|
+
if (fs.existsSync(jsonPath)) {
|
|
114
|
+
const jsonContent = fs.readFileSync(jsonPath, 'utf-8');
|
|
115
|
+
const pkg = JSON.parse(jsonContent);
|
|
116
|
+
if (pkg.dev) {
|
|
117
|
+
targetPath = path.join(pluginPath, pkg.dev);
|
|
150
118
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
return module;
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
// 清除该文件的缓存,确保获取最新版本
|
|
157
|
-
const resolvedPath = require.resolve(targetPath);
|
|
158
|
-
if (require.cache[resolvedPath]) {
|
|
159
|
-
delete require.cache[resolvedPath];
|
|
119
|
+
else if (pkg.main) {
|
|
120
|
+
targetPath = path.join(pluginPath, pkg.main);
|
|
160
121
|
}
|
|
161
|
-
// 使用 require 加载 js 模块
|
|
162
|
-
const module = require(targetPath);
|
|
163
|
-
return module;
|
|
164
122
|
}
|
|
165
123
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
|
|
124
|
+
if (this.isDev) {
|
|
125
|
+
// In development, use require() to leverage esbuild-register
|
|
126
|
+
// and clear cache for HMR.
|
|
127
|
+
const resolvedPath = require.resolve(targetPath);
|
|
128
|
+
// Clean up the cache for the main module and its children
|
|
129
|
+
if (require.cache[resolvedPath]) {
|
|
130
|
+
this.clearRequireCache(resolvedPath, new Set());
|
|
171
131
|
}
|
|
132
|
+
const module = require(resolvedPath);
|
|
133
|
+
return module.default || module;
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// In production, use dynamic import.
|
|
137
|
+
const url = (0, url_1.pathToFileURL)(targetPath).href;
|
|
138
|
+
const module = await Promise.resolve(`${url}`).then(s => __importStar(require(s)));
|
|
139
|
+
return module.default || module;
|
|
172
140
|
}
|
|
173
|
-
// 使用require加载
|
|
174
|
-
const pluginModule = require(targetPath);
|
|
175
|
-
return pluginModule;
|
|
176
141
|
}
|
|
177
142
|
catch (e) {
|
|
178
143
|
this.logger.error(`Error loading plugin from path ${pluginPath}:`, e);
|
|
179
144
|
throw e;
|
|
180
145
|
}
|
|
181
146
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
147
|
+
clearRequireCache(moduleId, visited) {
|
|
148
|
+
if (visited.has(moduleId)) {
|
|
149
|
+
return; // Cycle detected
|
|
150
|
+
}
|
|
151
|
+
visited.add(moduleId);
|
|
152
|
+
const module = require.cache[moduleId];
|
|
153
|
+
if (!module)
|
|
154
|
+
return;
|
|
155
|
+
// Recursively clear children's cache
|
|
156
|
+
if (module.children) {
|
|
157
|
+
for (const child of module.children) {
|
|
158
|
+
this.clearRequireCache(child.id, visited);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Delete the module from cache
|
|
162
|
+
delete require.cache[moduleId];
|
|
163
|
+
}
|
|
186
164
|
async unloadPlugin(pluginName) {
|
|
187
165
|
if (!this.pluginCache[pluginName]) {
|
|
188
166
|
return; // Plugin not loaded
|
|
189
167
|
}
|
|
190
168
|
delete this.pluginCache[pluginName];
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
// this.logger.info(`Plugin unloaded: ${pluginName}`);
|
|
199
|
-
this.core?.unregall(pluginName);
|
|
200
|
-
}
|
|
201
|
-
catch (error) {
|
|
202
|
-
this.logger.error(`Error unloading plugin ${pluginName}:`, error);
|
|
203
|
-
}
|
|
169
|
+
// With dynamic import, there's no direct equivalent of require.cache to clear.
|
|
170
|
+
// The timestamp query in dev mode handles fresh loading.
|
|
171
|
+
// For production, modules are cached intentionally.
|
|
172
|
+
this.core?.unregall(pluginName);
|
|
173
|
+
// this.logger.info(`Plugin unloaded: ${pluginName}`);
|
|
204
174
|
}
|
|
205
|
-
/**
|
|
206
|
-
* 检查插件的依赖是否满足.
|
|
207
|
-
* @param pluginPath 插件路径.
|
|
208
|
-
* @returns 如果依赖满足,则返回 true,否则返回 false.
|
|
209
|
-
*/
|
|
210
175
|
async checkPluginDependencies(pluginPath) {
|
|
211
|
-
// TODO:
|
|
176
|
+
// TODO: Implement dependency checking from package.json
|
|
212
177
|
return true;
|
|
213
178
|
}
|
|
214
|
-
/**
|
|
215
|
-
* 安装插件的依赖.
|
|
216
|
-
* @param pluginPath 插件路径.
|
|
217
|
-
*/
|
|
218
179
|
async installPluginDependencies(pluginName) {
|
|
219
180
|
try {
|
|
220
181
|
this.logger.info(`Installing dependencies for plugin: ${pluginName}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yumerijs/loader",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "Module loader for yumeri",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
"dist"
|
|
9
9
|
],
|
|
10
10
|
"scripts": {
|
|
11
|
-
"build": "tsc"
|
|
12
|
-
"prepublishOnly": "yarn build"
|
|
11
|
+
"build": "tsc"
|
|
13
12
|
},
|
|
14
13
|
"repository": {
|
|
15
14
|
"type": "git",
|
|
@@ -27,13 +26,12 @@
|
|
|
27
26
|
"homepage": "https://github.com/yumerijs/yumeri#readme",
|
|
28
27
|
"devDependencies": {
|
|
29
28
|
"@types/node": "^22.13.10",
|
|
30
|
-
"
|
|
29
|
+
"esbuild": "^0.25.9",
|
|
30
|
+
"esbuild-register": "^3.6.0",
|
|
31
31
|
"typescript": "^5.8.2"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@yumerijs/core": "^1.
|
|
35
|
-
"chokidar": "^4.0.3"
|
|
36
|
-
"semver": "^7.7.1",
|
|
37
|
-
"ts-node": "^10.9.2"
|
|
34
|
+
"@yumerijs/core": "^1.2.0",
|
|
35
|
+
"chokidar": "^4.0.3"
|
|
38
36
|
}
|
|
39
37
|
}
|