@yumerijs/loader 2.1.1 → 2.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 +3 -7
- package/dist/index.js +37 -117
- package/dist/runtime/vueLoader.js +11 -17
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { Core, Config, Logger, Context, PluginStatus } from '@yumerijs/core';
|
|
1
|
+
import { Core, Config, Logger, Context, PluginStatus, Schema } 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
|
render?: string;
|
|
8
|
+
config?: Schema<any>;
|
|
8
9
|
}
|
|
9
10
|
export declare class PluginLoader {
|
|
10
11
|
private pluginsDir;
|
|
@@ -29,24 +30,19 @@ export declare class PluginLoader {
|
|
|
29
30
|
* This does NOT reload any plugins.
|
|
30
31
|
*/
|
|
31
32
|
reloadConfigFile(): Promise<void>;
|
|
33
|
+
saveConfig(): Promise<void>;
|
|
32
34
|
getCore(): Core;
|
|
33
35
|
getContext(pluginName: string, injections?: Record<string, any>): Context;
|
|
34
36
|
unregall(pluginName: string): void;
|
|
35
37
|
loadConfig(configPath: string): Promise<void>;
|
|
36
|
-
getPluginConfig(pluginName: string): Promise<Config>;
|
|
37
38
|
loadPlugins(): Promise<void>;
|
|
38
39
|
loadSinglePlugin(pluginName: string, triggerPendingCheck?: boolean, onlypending?: boolean): Promise<boolean>;
|
|
39
40
|
private _loadPendingPlugins;
|
|
40
41
|
unloadPlugin(pluginNameToUnload: string, ispending?: boolean): Promise<void>;
|
|
41
42
|
private _unloadSinglePlugin;
|
|
42
|
-
/**
|
|
43
|
-
* Reloads a single plugin's code by clearing the require cache and then reloading it.
|
|
44
|
-
* @param pluginName The name of the plugin to reload.
|
|
45
|
-
*/
|
|
46
43
|
reloadPlugin(pluginName: string): Promise<void>;
|
|
47
44
|
private watchPlugin;
|
|
48
45
|
loadModule(pluginName: string): Promise<Plugin>;
|
|
49
|
-
private clearRequireCache;
|
|
50
46
|
checkPluginDependencies(pluginPath: string): Promise<boolean>;
|
|
51
47
|
installPluginDependencies(pluginName: string): Promise<void>;
|
|
52
48
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,53 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.PluginLoader = void 0;
|
|
37
|
-
const path = __importStar(require("path"));
|
|
38
|
-
const core_1 = require("@yumerijs/core");
|
|
39
|
-
const fs = __importStar(require("fs"));
|
|
40
|
-
const util_1 = require("util");
|
|
41
|
-
const child_process_1 = require("child_process");
|
|
42
|
-
const yaml = __importStar(require("js-yaml"));
|
|
43
|
-
const chokidar = __importStar(require("chokidar"));
|
|
44
|
-
const vueLoader_1 = require("./runtime/vueLoader");
|
|
45
|
-
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
46
|
-
class PluginLoader {
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import { Core, Logger, Context, fallback, I18n } from '@yumerijs/core';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import { promisify } from 'util';
|
|
5
|
+
import { exec } from 'child_process';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import * as yaml from 'js-yaml';
|
|
8
|
+
import * as chokidar from 'chokidar';
|
|
9
|
+
const execAsync = promisify(exec);
|
|
10
|
+
export class PluginLoader {
|
|
47
11
|
pluginsDir;
|
|
48
12
|
core;
|
|
49
13
|
config = null;
|
|
50
|
-
logger = new
|
|
14
|
+
logger = new Logger('loader');
|
|
51
15
|
plugins = {};
|
|
52
16
|
pluginStatus = {};
|
|
53
17
|
pluginWatchers = {};
|
|
@@ -57,37 +21,25 @@ class PluginLoader {
|
|
|
57
21
|
isDev = false;
|
|
58
22
|
constructor(core, pluginsDir = 'plugins') {
|
|
59
23
|
this.pluginsDir = pluginsDir;
|
|
60
|
-
this.core = core || new
|
|
24
|
+
this.core = core || new Core(this, undefined, false);
|
|
61
25
|
this.isDev = process.env.NODE_ENV === 'development';
|
|
62
|
-
|
|
63
|
-
(0, vueLoader_1.registerVueRuntimeLoader)();
|
|
26
|
+
Logger.setCore(this.core);
|
|
64
27
|
}
|
|
65
28
|
/**
|
|
66
29
|
* Reloads the config file from disk into memory and emits a 'config-reloaded' event.
|
|
67
30
|
* This does NOT reload any plugins.
|
|
68
31
|
*/
|
|
69
32
|
async reloadConfigFile() {
|
|
70
|
-
this.
|
|
33
|
+
this.core.coreConfig = this.config.core || {};
|
|
34
|
+
this.core.emit('config-reloaded', this.config);
|
|
35
|
+
}
|
|
36
|
+
async saveConfig() {
|
|
71
37
|
try {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
let doc;
|
|
75
|
-
if (ext === '.yaml' || ext === '.yml') {
|
|
76
|
-
doc = yaml.load(fileContent);
|
|
77
|
-
}
|
|
78
|
-
else if (ext === '.json') {
|
|
79
|
-
doc = JSON.parse(fileContent);
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
throw new Error(`Unsupported config file extension: ${ext}`);
|
|
83
|
-
}
|
|
84
|
-
this.config = doc;
|
|
85
|
-
this.core.coreConfig = this.config.core || {};
|
|
86
|
-
this.core.emit('config-reloaded', this.config);
|
|
87
|
-
this.logger.info('Config file reloaded successfully.');
|
|
38
|
+
const jsonConfig = JSON.stringify(this.config, null, 2);
|
|
39
|
+
fs.writeFileSync(this.configPath, jsonConfig, 'utf8');
|
|
88
40
|
}
|
|
89
41
|
catch (e) {
|
|
90
|
-
this.logger.error('Failed to
|
|
42
|
+
this.logger.error('Failed to save config file:', e);
|
|
91
43
|
}
|
|
92
44
|
}
|
|
93
45
|
getCore() {
|
|
@@ -95,7 +47,7 @@ class PluginLoader {
|
|
|
95
47
|
}
|
|
96
48
|
getContext(pluginName, injections = {}) {
|
|
97
49
|
if (!this.pluginContexts[pluginName]) {
|
|
98
|
-
this.pluginContexts[pluginName] = new
|
|
50
|
+
this.pluginContexts[pluginName] = new Context(this.core, pluginName, null, injections);
|
|
99
51
|
}
|
|
100
52
|
return this.pluginContexts[pluginName];
|
|
101
53
|
}
|
|
@@ -120,20 +72,13 @@ class PluginLoader {
|
|
|
120
72
|
this.config = doc;
|
|
121
73
|
this.logger.info('Config loaded.');
|
|
122
74
|
this.core.coreConfig = this.config.core || {};
|
|
123
|
-
this.core.i18n = new
|
|
75
|
+
this.core.i18n = new I18n(this.core.coreConfig.lang || ['zh', 'en']);
|
|
124
76
|
}
|
|
125
77
|
catch (e) {
|
|
126
78
|
this.logger.error('Failed to load config:', e);
|
|
127
79
|
throw e;
|
|
128
80
|
}
|
|
129
81
|
}
|
|
130
|
-
async getPluginConfig(pluginName) {
|
|
131
|
-
const actualPluginName = pluginName.startsWith('~') ? pluginName.substring(1) : pluginName;
|
|
132
|
-
if (!this.config.plugins[actualPluginName]) {
|
|
133
|
-
return new core_1.Config(actualPluginName);
|
|
134
|
-
}
|
|
135
|
-
return new core_1.Config(actualPluginName, this.config.plugins[actualPluginName]);
|
|
136
|
-
}
|
|
137
82
|
async loadPlugins() {
|
|
138
83
|
if (!this.config || typeof this.config.plugins !== 'object' || this.config.plugins === null) {
|
|
139
84
|
this.logger.info('No plugins configuration found. No plugins to load.');
|
|
@@ -206,7 +151,7 @@ class PluginLoader {
|
|
|
206
151
|
};
|
|
207
152
|
const rendererPackageName = rendererPackageMap[rendererName] || rendererName;
|
|
208
153
|
this.logger.info(`Loading renderer package: "${rendererPackageName}"...`);
|
|
209
|
-
const RendererClass =
|
|
154
|
+
const RendererClass = await import(rendererPackageName);
|
|
210
155
|
// Handle both ES modules (default export) and CommonJS modules
|
|
211
156
|
const ActualRendererClass = RendererClass.default || RendererClass;
|
|
212
157
|
const rendererInstance = new ActualRendererClass();
|
|
@@ -230,9 +175,15 @@ class PluginLoader {
|
|
|
230
175
|
for (const injection of depend) {
|
|
231
176
|
injections[injection] = this.core.getComponent(injection);
|
|
232
177
|
}
|
|
233
|
-
|
|
178
|
+
// ### NEW CONFIG LOGIC ###
|
|
179
|
+
const rawConfig = (this.config.plugins && this.config.plugins[pluginName]) || {};
|
|
180
|
+
const schema = pluginInstance.config; // The schema is exported as 'config'
|
|
181
|
+
const finalConfig = fallback(schema, rawConfig);
|
|
182
|
+
// Update the in-memory config with the fully resolved one
|
|
183
|
+
this.config.plugins[pluginName] = finalConfig;
|
|
184
|
+
// ### END NEW CONFIG LOGIC ###
|
|
234
185
|
const context = this.getContext(pluginName, injections);
|
|
235
|
-
await this.core.plugin(pluginInstance, context,
|
|
186
|
+
await this.core.plugin(pluginInstance, context, finalConfig);
|
|
236
187
|
this.pluginStatus[pluginName] = "enabled" /* PluginStatus.ENABLED */;
|
|
237
188
|
if (triggerPendingCheck) {
|
|
238
189
|
await this._loadPendingPlugins();
|
|
@@ -240,7 +191,8 @@ class PluginLoader {
|
|
|
240
191
|
if (this.isDev) {
|
|
241
192
|
let pluginPathToWatch = null;
|
|
242
193
|
try {
|
|
243
|
-
const
|
|
194
|
+
const packageJsonUrl = import.meta.resolve(`${pluginName}/package.json`);
|
|
195
|
+
const pkgJsonPath = fileURLToPath(packageJsonUrl);
|
|
244
196
|
pluginPathToWatch = path.dirname(pkgJsonPath);
|
|
245
197
|
}
|
|
246
198
|
catch (e) {
|
|
@@ -323,27 +275,11 @@ class PluginLoader {
|
|
|
323
275
|
this.logger.error(`Failed to unload plugin "${pluginName}":`, error);
|
|
324
276
|
}
|
|
325
277
|
}
|
|
326
|
-
/**
|
|
327
|
-
* Reloads a single plugin's code by clearing the require cache and then reloading it.
|
|
328
|
-
* @param pluginName The name of the plugin to reload.
|
|
329
|
-
*/
|
|
330
278
|
async reloadPlugin(pluginName) {
|
|
331
279
|
this.logger.info(`Reloading plugin: "${pluginName}"...`);
|
|
332
|
-
// Clear the module cache for the plugin. This is critical for hot-reloading.
|
|
333
|
-
try {
|
|
334
|
-
const resolvedPath = require.resolve(pluginName);
|
|
335
|
-
this.clearRequireCache(resolvedPath, new Set());
|
|
336
|
-
this.logger.info(`Cache cleared for plugin "${pluginName}".`);
|
|
337
|
-
}
|
|
338
|
-
catch (e) {
|
|
339
|
-
this.logger.error(`Could not resolve path for plugin ${pluginName} to clear cache.`, e);
|
|
340
|
-
}
|
|
341
|
-
// Reload the configuration from disk to catch any changes.
|
|
342
280
|
await this.reloadConfigFile();
|
|
343
|
-
// Unload the plugin and its dependents.
|
|
344
281
|
await this.unloadPlugin(pluginName, true);
|
|
345
|
-
|
|
346
|
-
const success = await this.loadSinglePlugin(pluginName);
|
|
282
|
+
const success = await this.loadSinglePlugin(pluginName, true, false);
|
|
347
283
|
if (success) {
|
|
348
284
|
this.logger.info(`Plugin "${pluginName}" reloaded successfully.`);
|
|
349
285
|
this.core.emit('plugin-reloaded', pluginName);
|
|
@@ -356,7 +292,7 @@ class PluginLoader {
|
|
|
356
292
|
if (this.pluginWatchers[pluginName]) {
|
|
357
293
|
return;
|
|
358
294
|
}
|
|
359
|
-
const logger = new
|
|
295
|
+
const logger = new Logger('hmr');
|
|
360
296
|
const watcher = chokidar.watch(pluginPath, {
|
|
361
297
|
ignored: /(^|[\/])\../,
|
|
362
298
|
persistent: true,
|
|
@@ -381,24 +317,9 @@ class PluginLoader {
|
|
|
381
317
|
this.pluginWatchers[pluginName] = watcher;
|
|
382
318
|
}
|
|
383
319
|
async loadModule(pluginName) {
|
|
384
|
-
const plugin = await
|
|
320
|
+
const plugin = await import(pluginName);
|
|
385
321
|
return plugin.default || plugin;
|
|
386
322
|
}
|
|
387
|
-
clearRequireCache(moduleId, visited) {
|
|
388
|
-
if (visited.has(moduleId)) {
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
visited.add(moduleId);
|
|
392
|
-
const module = require.cache[moduleId];
|
|
393
|
-
if (!module)
|
|
394
|
-
return;
|
|
395
|
-
if (module.children) {
|
|
396
|
-
for (const child of module.children) {
|
|
397
|
-
this.clearRequireCache(child.id, visited);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
delete require.cache[moduleId];
|
|
401
|
-
}
|
|
402
323
|
async checkPluginDependencies(pluginPath) {
|
|
403
324
|
return true;
|
|
404
325
|
}
|
|
@@ -418,5 +339,4 @@ class PluginLoader {
|
|
|
418
339
|
}
|
|
419
340
|
}
|
|
420
341
|
}
|
|
421
|
-
|
|
422
|
-
exports.default = PluginLoader;
|
|
342
|
+
export default PluginLoader;
|
|
@@ -1,24 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.registerVueRuntimeLoader = registerVueRuntimeLoader;
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
-
const compiler_sfc_1 = require("@vue/compiler-sfc");
|
|
10
|
-
const esbuild_1 = require("esbuild");
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import { parse, compileScript, compileTemplate } from '@vue/compiler-sfc';
|
|
4
|
+
import { transformSync } from 'esbuild';
|
|
11
5
|
let vueLoaderRegistered = false;
|
|
12
6
|
const SUPPORTED_ESBUILD_LOADERS = new Set(['js', 'ts', 'tsx', 'jsx']);
|
|
13
7
|
function getScopeId(filename) {
|
|
14
|
-
return
|
|
8
|
+
return crypto.createHash('md5').update(filename).digest('hex').slice(0, 8);
|
|
15
9
|
}
|
|
16
10
|
function inferLoader(lang) {
|
|
17
11
|
if (!lang)
|
|
18
12
|
return 'js';
|
|
19
13
|
return SUPPORTED_ESBUILD_LOADERS.has(lang) ? lang : 'js';
|
|
20
14
|
}
|
|
21
|
-
function registerVueRuntimeLoader() {
|
|
15
|
+
export function registerVueRuntimeLoader() {
|
|
22
16
|
if (vueLoaderRegistered) {
|
|
23
17
|
return;
|
|
24
18
|
}
|
|
@@ -26,8 +20,8 @@ function registerVueRuntimeLoader() {
|
|
|
26
20
|
require.extensions['.vue'] = function registerVueSFC(module, filename) {
|
|
27
21
|
const nodeModule = module;
|
|
28
22
|
try {
|
|
29
|
-
const source =
|
|
30
|
-
const { descriptor } =
|
|
23
|
+
const source = fs.readFileSync(filename, 'utf8');
|
|
24
|
+
const { descriptor } = parse(source, { filename });
|
|
31
25
|
if (!descriptor.script && !descriptor.scriptSetup && !descriptor.template) {
|
|
32
26
|
nodeModule._compile('module.exports = {};\n', filename);
|
|
33
27
|
return;
|
|
@@ -36,7 +30,7 @@ function registerVueRuntimeLoader() {
|
|
|
36
30
|
let code = '';
|
|
37
31
|
const lang = descriptor.scriptSetup?.lang || descriptor.script?.lang;
|
|
38
32
|
if (!descriptor.script && !descriptor.scriptSetup && descriptor.template) {
|
|
39
|
-
const templateResult =
|
|
33
|
+
const templateResult = compileTemplate({
|
|
40
34
|
id,
|
|
41
35
|
filename,
|
|
42
36
|
source: descriptor.template.content,
|
|
@@ -53,7 +47,7 @@ export default __component__;
|
|
|
53
47
|
`;
|
|
54
48
|
}
|
|
55
49
|
else {
|
|
56
|
-
const compiled =
|
|
50
|
+
const compiled = compileScript(descriptor, {
|
|
57
51
|
id,
|
|
58
52
|
inlineTemplate: Boolean(descriptor.template),
|
|
59
53
|
templateOptions: {
|
|
@@ -62,7 +56,7 @@ export default __component__;
|
|
|
62
56
|
});
|
|
63
57
|
code = compiled.content;
|
|
64
58
|
}
|
|
65
|
-
const transformed =
|
|
59
|
+
const transformed = transformSync(code, {
|
|
66
60
|
loader: inferLoader(lang),
|
|
67
61
|
format: 'cjs',
|
|
68
62
|
target: 'node18',
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yumerijs/loader",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Module loader for yumeri",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
7
8
|
"files": [
|
|
8
9
|
"dist"
|
|
9
10
|
],
|
|
@@ -40,6 +41,6 @@
|
|
|
40
41
|
"js-yaml": "^4.1.0"
|
|
41
42
|
},
|
|
42
43
|
"peerDependencies": {
|
|
43
|
-
"@yumerijs/core": "^2.0
|
|
44
|
+
"@yumerijs/core": "^2.2.0"
|
|
44
45
|
}
|
|
45
46
|
}
|