@yumerijs/loader 1.1.1 → 1.2.0

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 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 tsNode = __importStar(require("ts-node"));
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,60 +53,40 @@ 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
- // 1. 检查是否是本地插件目录下的插件
82
- const localPluginPath = path.resolve(this.pluginsDir, pluginName);
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(localPluginPath1)) {
89
- pluginPath = localPluginPath1;
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
- // 尝试 require,如果成功,则认为是一个已安装的 npm 包
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 {
@@ -118,103 +98,78 @@ class PluginLoader {
118
98
  this.logger.error(`Failed to load plugin from ${pluginPath}:`, e);
119
99
  throw e;
120
100
  }
121
- // const plugin = require(pluginName);
122
- // this.pluginCache[pluginName] = plugin;
123
- // return plugin;
124
101
  }
125
- /**
126
- * 从指定路径加载插件.
127
- * @param pluginPath 插件路径.
128
- * @param isLocalPlugin 是否是本地插件
129
- * @returns 加载的插件对象.
130
- * @throws 如果插件加载失败.
131
- */
132
102
  async loadPluginFromPath(pluginPath, isLocalPlugin) {
133
103
  try {
134
- let jsonPath;
135
104
  let targetPath = pluginPath;
136
105
  if (isLocalPlugin && this.isDev) {
137
- // 开发模式下,加载 src 目录下的 ts 文件
138
- jsonPath = path.join(pluginPath, 'package.json');
139
- let jsoncontent = fs.readFileSync(jsonPath, 'utf-8');
140
- targetPath = path.join(pluginPath, JSON.parse(jsoncontent).dev);
141
- if (!fs.existsSync(targetPath)) {
142
- throw new Error(`devfile not found in ${pluginPath}`);
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];
106
+ const jsonPath = path.join(pluginPath, 'package.json');
107
+ if (fs.existsSync(jsonPath)) {
108
+ const jsonContent = fs.readFileSync(jsonPath, 'utf-8');
109
+ const pkg = JSON.parse(jsonContent);
110
+ if (pkg.dev) {
111
+ targetPath = path.join(pluginPath, pkg.dev);
150
112
  }
151
- // 使用 ts-node 重新编译并加载 TypeScript 模块
152
- const module = require(targetPath);
153
- return module;
154
- }
155
- else {
156
- // 清除该文件的缓存,确保获取最新版本
157
- const resolvedPath = require.resolve(targetPath);
158
- if (require.cache[resolvedPath]) {
159
- delete require.cache[resolvedPath];
113
+ else if (pkg.main) {
114
+ targetPath = path.join(pluginPath, pkg.main);
160
115
  }
161
- // 使用 require 加载 js 模块
162
- const module = require(targetPath);
163
- return module;
164
116
  }
165
117
  }
166
- else {
167
- targetPath = require.resolve(pluginPath);
168
- // 清除该文件的缓存,确保获取最新版本
169
- if (require.cache[targetPath]) {
170
- delete require.cache[targetPath];
118
+ if (this.isDev) {
119
+ // In development, use require() to leverage esbuild-register
120
+ // and clear cache for HMR.
121
+ const resolvedPath = require.resolve(targetPath);
122
+ // Clean up the cache for the main module and its children
123
+ if (require.cache[resolvedPath]) {
124
+ this.clearRequireCache(resolvedPath, new Set());
171
125
  }
126
+ const module = require(resolvedPath);
127
+ return module.default || module;
128
+ }
129
+ else {
130
+ // In production, use dynamic import.
131
+ const url = (0, url_1.pathToFileURL)(targetPath).href;
132
+ const module = await Promise.resolve(`${url}`).then(s => __importStar(require(s)));
133
+ return module.default || module;
172
134
  }
173
- // 使用require加载
174
- const pluginModule = require(targetPath);
175
- return pluginModule;
176
135
  }
177
136
  catch (e) {
178
137
  this.logger.error(`Error loading plugin from path ${pluginPath}:`, e);
179
138
  throw e;
180
139
  }
181
140
  }
182
- /**
183
- * 卸载插件
184
- * @param pluginName 插件名称
185
- */
141
+ clearRequireCache(moduleId, visited) {
142
+ if (visited.has(moduleId)) {
143
+ return; // Cycle detected
144
+ }
145
+ visited.add(moduleId);
146
+ const module = require.cache[moduleId];
147
+ if (!module)
148
+ return;
149
+ // Recursively clear children's cache
150
+ if (module.children) {
151
+ for (const child of module.children) {
152
+ this.clearRequireCache(child.id, visited);
153
+ }
154
+ }
155
+ // Delete the module from cache
156
+ delete require.cache[moduleId];
157
+ }
186
158
  async unloadPlugin(pluginName) {
187
159
  if (!this.pluginCache[pluginName]) {
188
160
  return; // Plugin not loaded
189
161
  }
190
162
  delete this.pluginCache[pluginName];
191
- try {
192
- // 清除插件相关的所有模块缓存
193
- Object.keys(require.cache).forEach(key => {
194
- if (key.includes(pluginName)) {
195
- delete require.cache[key];
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
- }
163
+ // With dynamic import, there's no direct equivalent of require.cache to clear.
164
+ // The timestamp query in dev mode handles fresh loading.
165
+ // For production, modules are cached intentionally.
166
+ this.core?.unregall(pluginName);
167
+ // this.logger.info(`Plugin unloaded: ${pluginName}`);
204
168
  }
205
- /**
206
- * 检查插件的依赖是否满足.
207
- * @param pluginPath 插件路径.
208
- * @returns 如果依赖满足,则返回 true,否则返回 false.
209
- */
210
169
  async checkPluginDependencies(pluginPath) {
211
- // TODO: 读取插件package.json,检查依赖是否满足
170
+ // TODO: Implement dependency checking from package.json
212
171
  return true;
213
172
  }
214
- /**
215
- * 安装插件的依赖.
216
- * @param pluginPath 插件路径.
217
- */
218
173
  async installPluginDependencies(pluginName) {
219
174
  try {
220
175
  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.1.1",
3
+ "version": "1.2.0",
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",
@@ -28,12 +27,13 @@
28
27
  "devDependencies": {
29
28
  "@types/node": "^22.13.10",
30
29
  "@types/semver": "^7.5.8",
30
+ "esbuild": "^0.25.9",
31
+ "esbuild-register": "^3.6.0",
31
32
  "typescript": "^5.8.2"
32
33
  },
33
34
  "dependencies": {
34
- "@yumerijs/core": "^1.1.0",
35
+ "@yumerijs/core": "^1.2.0",
35
36
  "chokidar": "^4.0.3",
36
- "semver": "^7.7.1",
37
- "ts-node": "^10.9.2"
37
+ "semver": "^7.7.1"
38
38
  }
39
39
  }