@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 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,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
- // 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 {
113
- const plugin = await this.loadPluginFromPath(pluginPath, isLocalPlugin);
114
- this.pluginCache[pluginName] = plugin;
115
- return plugin;
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
- // 开发模式下,加载 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];
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
- // 使用 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];
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
- else {
167
- targetPath = require.resolve(pluginPath);
168
- // 清除该文件的缓存,确保获取最新版本
169
- if (require.cache[targetPath]) {
170
- delete require.cache[targetPath];
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
- * @param pluginName 插件名称
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
- 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
- }
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: 读取插件package.json,检查依赖是否满足
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.1.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
- "@types/semver": "^7.5.8",
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.1.0",
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
  }