@yumerijs/loader 1.1.0 → 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,59 +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
- if (this.pluginCache[pluginName]) {
75
- this.logger.info(`Returning cached plugin: ${pluginName}`);
62
+ if (this.pluginCache[pluginName] && !this.isDev) {
76
63
  return this.pluginCache[pluginName];
77
64
  }
78
65
  let pluginPath;
79
66
  let isLocalPlugin = false;
80
- // 1. 检查是否是本地插件目录下的插件
81
- const localPluginPath = path.resolve(this.pluginsDir, pluginName);
82
- const localPluginPath1 = path.resolve(pluginName);
67
+ const localPluginPath = path.resolve(process.cwd(), this.pluginsDir, pluginName);
68
+ const localPluginPathAlt = path.resolve(process.cwd(), pluginName);
83
69
  if (fs.existsSync(localPluginPath)) {
84
70
  pluginPath = localPluginPath;
85
71
  isLocalPlugin = true;
86
72
  }
87
- else if (fs.existsSync(localPluginPath1)) {
88
- pluginPath = localPluginPath1;
73
+ else if (fs.existsSync(localPluginPathAlt)) {
74
+ pluginPath = localPluginPathAlt;
89
75
  isLocalPlugin = true;
90
76
  }
91
- // 2. 检查是否是绝对路径或相对路径
92
77
  else if (path.isAbsolute(pluginName) || pluginName.startsWith('.')) {
93
78
  pluginPath = path.resolve(pluginName);
94
79
  isLocalPlugin = true;
95
80
  }
96
- // 3. 尝试作为 npm 包加载
97
81
  else {
98
82
  try {
99
- // 尝试 require,如果成功,则认为是一个已安装的 npm 包
100
- require.resolve(pluginName); // 检查包是否已安装
101
- pluginPath = pluginName;
83
+ pluginPath = require.resolve(pluginName);
102
84
  }
103
85
  catch (e) {
104
- // 如果 require.resolve 失败,则抛出错误
105
86
  if (e.code === 'MODULE_NOT_FOUND') {
106
87
  throw new Error(`Plugin ${pluginName} not found. Please install it first.`);
107
88
  }
108
- throw e; // 其他类型的错误,直接抛出
89
+ throw e;
109
90
  }
110
91
  }
111
92
  try {
@@ -118,99 +99,77 @@ class PluginLoader {
118
99
  throw e;
119
100
  }
120
101
  }
121
- /**
122
- * 从指定路径加载插件.
123
- * @param pluginPath 插件路径.
124
- * @param isLocalPlugin 是否是本地插件
125
- * @returns 加载的插件对象.
126
- * @throws 如果插件加载失败.
127
- */
128
102
  async loadPluginFromPath(pluginPath, isLocalPlugin) {
129
103
  try {
130
- let jsonPath;
131
104
  let targetPath = pluginPath;
132
105
  if (isLocalPlugin && this.isDev) {
133
- // 开发模式下,加载 src 目录下的 ts 文件
134
- jsonPath = path.join(pluginPath, 'package.json');
135
- let jsoncontent = fs.readFileSync(jsonPath, 'utf-8');
136
- targetPath = path.join(pluginPath, JSON.parse(jsoncontent).dev);
137
- if (!fs.existsSync(targetPath)) {
138
- throw new Error(`devfile not found in ${pluginPath}`);
139
- }
140
- // 检查目标文件是否是 TypeScript 文件
141
- if (targetPath.endsWith('.ts')) {
142
- // 清除该文件的缓存,确保获取最新版本
143
- const resolvedPath = require.resolve(targetPath);
144
- if (require.cache[resolvedPath]) {
145
- 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);
146
112
  }
147
- // 使用 ts-node 重新编译并加载 TypeScript 模块
148
- const module = require(targetPath);
149
- return module;
150
- }
151
- else {
152
- // 清除该文件的缓存,确保获取最新版本
153
- const resolvedPath = require.resolve(targetPath);
154
- if (require.cache[resolvedPath]) {
155
- delete require.cache[resolvedPath];
113
+ else if (pkg.main) {
114
+ targetPath = path.join(pluginPath, pkg.main);
156
115
  }
157
- // 使用 require 加载 js 模块
158
- const module = require(targetPath);
159
- return module;
160
116
  }
161
117
  }
162
- else {
163
- targetPath = require.resolve(pluginPath);
164
- // 清除该文件的缓存,确保获取最新版本
165
- if (require.cache[targetPath]) {
166
- 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());
167
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;
168
134
  }
169
- // 使用require加载
170
- const pluginModule = require(targetPath);
171
- return pluginModule;
172
135
  }
173
136
  catch (e) {
174
137
  this.logger.error(`Error loading plugin from path ${pluginPath}:`, e);
175
138
  throw e;
176
139
  }
177
140
  }
178
- /**
179
- * 卸载插件
180
- * @param pluginName 插件名称
181
- */
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
+ }
182
158
  async unloadPlugin(pluginName) {
183
159
  if (!this.pluginCache[pluginName]) {
184
160
  return; // Plugin not loaded
185
161
  }
186
162
  delete this.pluginCache[pluginName];
187
- try {
188
- // 清除插件相关的所有模块缓存
189
- Object.keys(require.cache).forEach(key => {
190
- if (key.includes(pluginName)) {
191
- delete require.cache[key];
192
- }
193
- });
194
- // this.logger.info(`Plugin unloaded: ${pluginName}`);
195
- this.core?.unregall(pluginName);
196
- }
197
- catch (error) {
198
- this.logger.error(`Error unloading plugin ${pluginName}:`, error);
199
- }
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}`);
200
168
  }
201
- /**
202
- * 检查插件的依赖是否满足.
203
- * @param pluginPath 插件路径.
204
- * @returns 如果依赖满足,则返回 true,否则返回 false.
205
- */
206
169
  async checkPluginDependencies(pluginPath) {
207
- // TODO: 读取插件package.json,检查依赖是否满足
170
+ // TODO: Implement dependency checking from package.json
208
171
  return true;
209
172
  }
210
- /**
211
- * 安装插件的依赖.
212
- * @param pluginPath 插件路径.
213
- */
214
173
  async installPluginDependencies(pluginName) {
215
174
  try {
216
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.0",
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
  }