@yumerijs/loader 2.0.0 → 2.0.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 +41 -16
- package/dist/index.js +255 -91
- package/package.json +9 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,27 +1,52 @@
|
|
|
1
|
-
import { Core, Config, Logger, Context } from '@yumerijs/core';
|
|
1
|
+
import { Core, Config, Logger, Context, PluginStatus } from '@yumerijs/core';
|
|
2
2
|
interface Plugin {
|
|
3
3
|
apply: (ctx: Context, config: Config) => Promise<void>;
|
|
4
4
|
disable: (ctx: Context) => Promise<void>;
|
|
5
5
|
depend: Array<string>;
|
|
6
6
|
provide: Array<string>;
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
load(pluginName: string): Promise<Plugin>;
|
|
10
|
-
unloadPlugin(pluginName: string): Promise<void>;
|
|
11
|
-
checkPluginDependencies(pluginPath: string): Promise<boolean>;
|
|
12
|
-
installPluginDependencies(pluginName: string): Promise<void>;
|
|
13
|
-
logger: Logger;
|
|
14
|
-
}
|
|
15
|
-
declare class PluginLoader {
|
|
16
|
-
private pluginCache;
|
|
17
|
-
private core;
|
|
18
|
-
private config;
|
|
19
|
-
private isDev;
|
|
8
|
+
export declare class PluginLoader {
|
|
20
9
|
private pluginsDir;
|
|
10
|
+
core: Core;
|
|
11
|
+
config: any;
|
|
21
12
|
logger: Logger;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
plugins: {
|
|
14
|
+
[name: string]: Plugin & {
|
|
15
|
+
depend?: string[];
|
|
16
|
+
provide?: string[];
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
pluginStatus: Record<string, PluginStatus>;
|
|
20
|
+
private pluginWatchers;
|
|
21
|
+
private pluginModules;
|
|
22
|
+
private configPath;
|
|
23
|
+
private pluginContexts;
|
|
24
|
+
private isDev;
|
|
25
|
+
constructor(core?: Core, pluginsDir?: string);
|
|
26
|
+
/**
|
|
27
|
+
* Reloads the config file from disk into memory and emits a 'config-reloaded' event.
|
|
28
|
+
* This does NOT reload any plugins.
|
|
29
|
+
*/
|
|
30
|
+
reloadConfigFile(): Promise<void>;
|
|
31
|
+
getCore(): Core;
|
|
32
|
+
getContext(pluginName: string): Context;
|
|
33
|
+
unregall(pluginName: string): void;
|
|
34
|
+
loadConfig(configPath: string): Promise<void>;
|
|
35
|
+
getPluginConfig(pluginName: string): Promise<Config>;
|
|
36
|
+
loadPlugins(): Promise<void>;
|
|
37
|
+
loadSinglePlugin(pluginName: string, triggerPendingCheck?: boolean, onlypending?: boolean): Promise<boolean>;
|
|
38
|
+
private _loadPendingPlugins;
|
|
39
|
+
unloadPlugin(pluginNameToUnload: string, ispending?: boolean): Promise<void>;
|
|
40
|
+
private _unloadSinglePlugin;
|
|
41
|
+
/**
|
|
42
|
+
* Reloads a single plugin's code by clearing the require cache and then reloading it.
|
|
43
|
+
* @param pluginName The name of the plugin to reload.
|
|
44
|
+
*/
|
|
45
|
+
reloadPlugin(pluginName: string): Promise<void>;
|
|
46
|
+
private watchPlugin;
|
|
47
|
+
loadModule(pluginName: string): Promise<Plugin>;
|
|
25
48
|
private clearRequireCache;
|
|
49
|
+
checkPluginDependencies(pluginPath: string): Promise<boolean>;
|
|
50
|
+
installPluginDependencies(pluginName: string): Promise<void>;
|
|
26
51
|
}
|
|
27
52
|
export default PluginLoader;
|
package/dist/index.js
CHANGED
|
@@ -33,147 +33,310 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.PluginLoader = void 0;
|
|
36
37
|
const path = __importStar(require("path"));
|
|
37
38
|
const core_1 = require("@yumerijs/core");
|
|
38
39
|
const fs = __importStar(require("fs"));
|
|
39
40
|
const util_1 = require("util");
|
|
40
41
|
const child_process_1 = require("child_process");
|
|
41
|
-
const
|
|
42
|
+
const yaml = __importStar(require("js-yaml"));
|
|
43
|
+
const chokidar = __importStar(require("chokidar"));
|
|
42
44
|
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
43
45
|
class PluginLoader {
|
|
44
|
-
|
|
45
|
-
core
|
|
46
|
+
pluginsDir;
|
|
47
|
+
core;
|
|
46
48
|
config = null;
|
|
47
|
-
isDev = false;
|
|
48
|
-
pluginsDir = 'plugins'; // Default plugins directory
|
|
49
49
|
logger = new core_1.Logger('loader');
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
plugins = {};
|
|
51
|
+
pluginStatus = {};
|
|
52
|
+
pluginWatchers = {};
|
|
53
|
+
pluginModules = {};
|
|
54
|
+
configPath = '';
|
|
55
|
+
pluginContexts = {};
|
|
56
|
+
isDev = false;
|
|
57
|
+
constructor(core, pluginsDir = 'plugins') {
|
|
55
58
|
this.pluginsDir = pluginsDir;
|
|
59
|
+
this.core = core || new core_1.Core(this, undefined, false);
|
|
60
|
+
this.core.uuid = Math.random().toString(36).substring(2);
|
|
61
|
+
this.logger.info(`[DIAG] Loader created/received Core instance with UUID: ${this.core.uuid}`);
|
|
62
|
+
this.isDev = process.env.NODE_ENV === 'development';
|
|
63
|
+
core_1.Logger.setCore(this.core);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Reloads the config file from disk into memory and emits a 'config-reloaded' event.
|
|
67
|
+
* This does NOT reload any plugins.
|
|
68
|
+
*/
|
|
69
|
+
async reloadConfigFile() {
|
|
70
|
+
this.logger.info('Reloading config file...');
|
|
71
|
+
try {
|
|
72
|
+
const doc = yaml.load(fs.readFileSync(this.configPath, 'utf8'));
|
|
73
|
+
this.config = doc;
|
|
74
|
+
this.core.coreConfig = this.config.core || {};
|
|
75
|
+
this.core.emit('config-reloaded', this.config);
|
|
76
|
+
this.logger.info('Config file reloaded.');
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
this.logger.error('Failed to reload config file:', e);
|
|
80
|
+
}
|
|
56
81
|
}
|
|
57
|
-
|
|
58
|
-
this.core
|
|
59
|
-
this.config = config;
|
|
82
|
+
getCore() {
|
|
83
|
+
return this.core;
|
|
60
84
|
}
|
|
61
|
-
|
|
62
|
-
if (this.
|
|
63
|
-
|
|
85
|
+
getContext(pluginName) {
|
|
86
|
+
if (!this.pluginContexts[pluginName]) {
|
|
87
|
+
this.pluginContexts[pluginName] = new core_1.Context(this.core, pluginName);
|
|
64
88
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
if (
|
|
70
|
-
|
|
71
|
-
|
|
89
|
+
return this.pluginContexts[pluginName];
|
|
90
|
+
}
|
|
91
|
+
unregall(pluginName) {
|
|
92
|
+
const ctx = this.pluginContexts[pluginName];
|
|
93
|
+
if (ctx) {
|
|
94
|
+
ctx.dispose();
|
|
95
|
+
delete this.pluginContexts[pluginName];
|
|
72
96
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
97
|
+
}
|
|
98
|
+
async loadConfig(configPath) {
|
|
99
|
+
try {
|
|
100
|
+
this.configPath = configPath;
|
|
101
|
+
const doc = yaml.load(fs.readFileSync(configPath, 'utf8'));
|
|
102
|
+
this.config = doc;
|
|
103
|
+
this.logger.info('Config loaded.');
|
|
104
|
+
this.core.coreConfig = this.config.core || {};
|
|
105
|
+
this.core.i18n = new (require('@yumerijs/core').I18n)(this.core.coreConfig.lang || ['zh', 'en']);
|
|
76
106
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
107
|
+
catch (e) {
|
|
108
|
+
this.logger.error('Failed to load config:', e);
|
|
109
|
+
throw e;
|
|
80
110
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
111
|
+
}
|
|
112
|
+
async getPluginConfig(pluginName) {
|
|
113
|
+
const actualPluginName = pluginName.startsWith('~') ? pluginName.substring(1) : pluginName;
|
|
114
|
+
if (!this.config.plugins[actualPluginName]) {
|
|
115
|
+
return new core_1.Config(actualPluginName);
|
|
116
|
+
}
|
|
117
|
+
return new core_1.Config(actualPluginName, this.config.plugins[actualPluginName]);
|
|
118
|
+
}
|
|
119
|
+
async loadPlugins() {
|
|
120
|
+
if (!this.config || typeof this.config.plugins !== 'object' || this.config.plugins === null) {
|
|
121
|
+
this.logger.info('No plugins configuration found. No plugins to load.');
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const allPluginNames = Object.keys(this.config.plugins);
|
|
125
|
+
this.pluginStatus = {}; // Reset status
|
|
126
|
+
for (const name of allPluginNames) {
|
|
127
|
+
if (name.startsWith('~')) {
|
|
128
|
+
const actualName = name.substring(1);
|
|
129
|
+
this.pluginStatus[actualName] = "disabled" /* PluginStatus.DISABLED */;
|
|
84
130
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
throw new Error(`Plugin ${pluginName} not found. Please install it first.`);
|
|
88
|
-
}
|
|
89
|
-
throw e;
|
|
131
|
+
else {
|
|
132
|
+
this.pluginStatus[name] = "pending" /* PluginStatus.PENDING */;
|
|
90
133
|
}
|
|
91
134
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
135
|
+
const enabledPlugins = allPluginNames.filter(name => !name.startsWith('~'));
|
|
136
|
+
const currentlyLoaded = Object.keys(this.plugins);
|
|
137
|
+
for (const loadedName of currentlyLoaded) {
|
|
138
|
+
if (!enabledPlugins.includes(loadedName)) {
|
|
139
|
+
await this.unloadPlugin(loadedName);
|
|
97
140
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
141
|
+
}
|
|
142
|
+
if (enabledPlugins.length === 0) {
|
|
143
|
+
this.logger.info('No enabled plugins found in configuration.');
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
let loadedInLastPass = true;
|
|
147
|
+
while (loadedInLastPass) {
|
|
148
|
+
loadedInLastPass = false;
|
|
149
|
+
for (const pluginName of enabledPlugins) {
|
|
150
|
+
if (this.pluginStatus[pluginName] === "enabled" /* PluginStatus.ENABLED */) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const success = await this.loadSinglePlugin(pluginName, false);
|
|
154
|
+
if (success) {
|
|
155
|
+
loadedInLastPass = true;
|
|
156
|
+
}
|
|
101
157
|
}
|
|
102
158
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
159
|
+
await this._loadPendingPlugins();
|
|
160
|
+
const pendingPlugins = Object.keys(this.pluginStatus).filter(p => this.pluginStatus[p] === "pending" /* PluginStatus.PENDING */);
|
|
161
|
+
if (pendingPlugins.length > 0) {
|
|
162
|
+
// this.logger.warn('Some plugins could not be loaded due to unresolved dependencies:', pendingPlugins);
|
|
106
163
|
}
|
|
107
164
|
}
|
|
108
|
-
async
|
|
165
|
+
async loadSinglePlugin(pluginName, triggerPendingCheck = true, onlypending = false) {
|
|
166
|
+
if (!this.pluginStatus[pluginName]) {
|
|
167
|
+
this.pluginStatus[pluginName] = "pending" /* PluginStatus.PENDING */;
|
|
168
|
+
}
|
|
169
|
+
if (this.pluginStatus[pluginName] !== "pending" /* PluginStatus.PENDING */ && onlypending) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
109
172
|
try {
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
173
|
+
const pluginInstance = await this.loadModule(pluginName);
|
|
174
|
+
if (!pluginInstance) {
|
|
175
|
+
throw new Error('Plugin loader returned no instance.');
|
|
176
|
+
}
|
|
177
|
+
const deps = pluginInstance.depend || [];
|
|
178
|
+
const unmetDependencies = deps.filter(dep => !this.core.components[dep]);
|
|
179
|
+
if (unmetDependencies.length > 0) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
this.plugins[pluginName] = pluginInstance;
|
|
183
|
+
const pluginConfig = await this.getPluginConfig(pluginName);
|
|
184
|
+
const context = this.getContext(pluginName);
|
|
185
|
+
await this.core.plugin(pluginInstance, context, pluginConfig);
|
|
186
|
+
this.pluginStatus[pluginName] = "enabled" /* PluginStatus.ENABLED */;
|
|
187
|
+
if (triggerPendingCheck) {
|
|
188
|
+
await this._loadPendingPlugins();
|
|
189
|
+
}
|
|
190
|
+
if (this.isDev) {
|
|
191
|
+
let pluginPathToWatch = null;
|
|
192
|
+
try {
|
|
193
|
+
const pkgJsonPath = require.resolve(`${pluginName}/package.json`);
|
|
194
|
+
pluginPathToWatch = path.dirname(pkgJsonPath);
|
|
195
|
+
}
|
|
196
|
+
catch (e) {
|
|
197
|
+
const localPluginPath = path.resolve(process.cwd(), pluginName);
|
|
198
|
+
const localPluginPathInPlugins = path.resolve(process.cwd(), 'plugins', pluginName);
|
|
199
|
+
if (fs.existsSync(localPluginPath)) {
|
|
200
|
+
pluginPathToWatch = localPluginPath;
|
|
118
201
|
}
|
|
119
|
-
else if (
|
|
120
|
-
|
|
202
|
+
else if (fs.existsSync(localPluginPathInPlugins)) {
|
|
203
|
+
pluginPathToWatch = localPluginPathInPlugins;
|
|
121
204
|
}
|
|
122
205
|
}
|
|
206
|
+
if (pluginPathToWatch) {
|
|
207
|
+
this.watchPlugin(pluginName, pluginPathToWatch);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
this.logger.warn(`Could not resolve path for plugin ${pluginName} to watch for changes.`);
|
|
211
|
+
}
|
|
123
212
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
this.logger.error(`Failed to load plugin "${pluginName}":`, err);
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async _loadPendingPlugins() {
|
|
221
|
+
const pendingPlugins = Object.keys(this.pluginStatus).filter(p => this.pluginStatus[p] === "pending" /* PluginStatus.PENDING */);
|
|
222
|
+
if (pendingPlugins.length === 0)
|
|
223
|
+
return;
|
|
224
|
+
for (const pluginName of pendingPlugins) {
|
|
225
|
+
await this.loadSinglePlugin(pluginName, false);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async unloadPlugin(pluginNameToUnload, ispending = false) {
|
|
229
|
+
const dependents = [];
|
|
230
|
+
const pluginsToCheck = [pluginNameToUnload];
|
|
231
|
+
while (pluginsToCheck.length > 0) {
|
|
232
|
+
const currentPluginName = pluginsToCheck.shift();
|
|
233
|
+
const provided = this.plugins[currentPluginName]?.provide || [];
|
|
234
|
+
if (provided.length === 0)
|
|
235
|
+
continue;
|
|
236
|
+
for (const pluginName in this.plugins) {
|
|
237
|
+
if (dependents.includes(pluginName) || pluginName === pluginNameToUnload)
|
|
238
|
+
continue;
|
|
239
|
+
const deps = this.plugins[pluginName].depend || [];
|
|
240
|
+
if (provided.some(p => deps.includes(p))) {
|
|
241
|
+
if (!dependents.includes(pluginName)) {
|
|
242
|
+
dependents.push(pluginName);
|
|
243
|
+
pluginsToCheck.push(pluginName);
|
|
244
|
+
}
|
|
131
245
|
}
|
|
132
|
-
const module = require(resolvedPath);
|
|
133
|
-
return module.default || module;
|
|
134
246
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
247
|
+
}
|
|
248
|
+
for (const dependentName of dependents) {
|
|
249
|
+
await this.unloadPlugin(dependentName, true);
|
|
250
|
+
}
|
|
251
|
+
await this._unloadSinglePlugin(pluginNameToUnload, ispending);
|
|
252
|
+
}
|
|
253
|
+
async _unloadSinglePlugin(pluginName, ispending = false) {
|
|
254
|
+
if (this.pluginStatus[pluginName] !== "enabled" /* PluginStatus.ENABLED */) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
this.logger.info(`Unloading plugin "${pluginName}"...`);
|
|
258
|
+
try {
|
|
259
|
+
const plugin = this.plugins[pluginName];
|
|
260
|
+
if (plugin && plugin.disable)
|
|
261
|
+
await plugin.disable(this.getContext(pluginName));
|
|
262
|
+
this.unregall(pluginName);
|
|
263
|
+
delete this.plugins[pluginName];
|
|
264
|
+
delete this.pluginModules[pluginName];
|
|
265
|
+
this.pluginStatus[pluginName] = ispending ? "pending" /* PluginStatus.PENDING */ : "disabled" /* PluginStatus.DISABLED */;
|
|
266
|
+
if (this.pluginWatchers[pluginName]) {
|
|
267
|
+
this.pluginWatchers[pluginName].close();
|
|
268
|
+
delete this.pluginWatchers[pluginName];
|
|
140
269
|
}
|
|
270
|
+
this.core.emit('plugin-unloaded', pluginName);
|
|
141
271
|
}
|
|
142
|
-
catch (
|
|
143
|
-
this.logger.error(`
|
|
144
|
-
throw e;
|
|
272
|
+
catch (error) {
|
|
273
|
+
this.logger.error(`Failed to unload plugin "${pluginName}":`, error);
|
|
145
274
|
}
|
|
146
275
|
}
|
|
276
|
+
/**
|
|
277
|
+
* Reloads a single plugin's code by clearing the require cache and then reloading it.
|
|
278
|
+
* @param pluginName The name of the plugin to reload.
|
|
279
|
+
*/
|
|
280
|
+
async reloadPlugin(pluginName) {
|
|
281
|
+
this.logger.info(`Reloading plugin code for "${pluginName}"...`);
|
|
282
|
+
this.clearRequireCache(pluginName, new Set());
|
|
283
|
+
await this.unloadPlugin(pluginName);
|
|
284
|
+
const success = await this.loadSinglePlugin(pluginName);
|
|
285
|
+
if (success) {
|
|
286
|
+
this.core.emit('plugin-reloaded', pluginName);
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
this.logger.error(`Failed to reload plugin "${pluginName}". It may have unmet dependencies.`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
watchPlugin(pluginName, pluginPath) {
|
|
293
|
+
if (this.pluginWatchers[pluginName]) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const logger = new core_1.Logger('hmr');
|
|
297
|
+
const watcher = chokidar.watch(pluginPath, {
|
|
298
|
+
ignored: /(^|[\/])\../,
|
|
299
|
+
persistent: true,
|
|
300
|
+
ignoreInitial: true,
|
|
301
|
+
awaitWriteFinish: {
|
|
302
|
+
stabilityThreshold: 200,
|
|
303
|
+
pollInterval: 100,
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
watcher.on('change', async (changePath) => {
|
|
307
|
+
logger.info(`Plugin file changed: ${changePath}`);
|
|
308
|
+
await this.reloadPlugin(pluginName);
|
|
309
|
+
});
|
|
310
|
+
watcher.on('add', async (changePath) => {
|
|
311
|
+
logger.info(`New file added to plugin ${pluginName}: ${changePath}`);
|
|
312
|
+
await this.reloadPlugin(pluginName);
|
|
313
|
+
});
|
|
314
|
+
watcher.on('unlink', async (changePath) => {
|
|
315
|
+
logger.info(`File removed from plugin ${pluginName}: ${changePath}`);
|
|
316
|
+
await this.reloadPlugin(pluginName);
|
|
317
|
+
});
|
|
318
|
+
this.pluginWatchers[pluginName] = watcher;
|
|
319
|
+
}
|
|
320
|
+
async loadModule(pluginName) {
|
|
321
|
+
const plugin = await require(pluginName);
|
|
322
|
+
return plugin.default || plugin;
|
|
323
|
+
}
|
|
147
324
|
clearRequireCache(moduleId, visited) {
|
|
148
325
|
if (visited.has(moduleId)) {
|
|
149
|
-
return;
|
|
326
|
+
return;
|
|
150
327
|
}
|
|
151
328
|
visited.add(moduleId);
|
|
152
329
|
const module = require.cache[moduleId];
|
|
153
330
|
if (!module)
|
|
154
331
|
return;
|
|
155
|
-
// Recursively clear children's cache
|
|
156
332
|
if (module.children) {
|
|
157
333
|
for (const child of module.children) {
|
|
158
334
|
this.clearRequireCache(child.id, visited);
|
|
159
335
|
}
|
|
160
336
|
}
|
|
161
|
-
// Delete the module from cache
|
|
162
337
|
delete require.cache[moduleId];
|
|
163
338
|
}
|
|
164
|
-
async unloadPlugin(pluginName) {
|
|
165
|
-
if (!this.pluginCache[pluginName]) {
|
|
166
|
-
return; // Plugin not loaded
|
|
167
|
-
}
|
|
168
|
-
delete this.pluginCache[pluginName];
|
|
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}`);
|
|
174
|
-
}
|
|
175
339
|
async checkPluginDependencies(pluginPath) {
|
|
176
|
-
// TODO: Implement dependency checking from package.json
|
|
177
340
|
return true;
|
|
178
341
|
}
|
|
179
342
|
async installPluginDependencies(pluginName) {
|
|
@@ -192,4 +355,5 @@ class PluginLoader {
|
|
|
192
355
|
}
|
|
193
356
|
}
|
|
194
357
|
}
|
|
358
|
+
exports.PluginLoader = PluginLoader;
|
|
195
359
|
exports.default = PluginLoader;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yumerijs/loader",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Module loader for yumeri",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -25,12 +25,19 @@
|
|
|
25
25
|
},
|
|
26
26
|
"homepage": "https://github.com/yumerijs/yumeri#readme",
|
|
27
27
|
"devDependencies": {
|
|
28
|
+
"@types/js-yaml": "^4.0.9",
|
|
28
29
|
"@types/node": "^22.13.10",
|
|
29
30
|
"esbuild": "^0.25.9",
|
|
30
31
|
"esbuild-register": "^3.6.0",
|
|
32
|
+
"@yumerijs/core": "^2.0.1",
|
|
31
33
|
"typescript": "^5.8.2"
|
|
32
34
|
},
|
|
33
35
|
"dependencies": {
|
|
34
|
-
"@
|
|
36
|
+
"@types/js-yaml": "^4.0.9",
|
|
37
|
+
"chokidar": "^4.0.3",
|
|
38
|
+
"js-yaml": "^4.1.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@yumerijs/core": "^2.0.2"
|
|
35
42
|
}
|
|
36
43
|
}
|