@eggjs/core 6.0.3 → 6.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.
@@ -2,10 +2,10 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import assert from 'node:assert';
4
4
  import { debuglog, inspect } from 'node:util';
5
- import { isAsyncFunction, isClass, isGeneratorFunction, isObject } from 'is-type-of';
6
5
  import { homedir } from 'node-homedir';
6
+ import { isAsyncFunction, isClass, isGeneratorFunction, isObject, isPromise } from 'is-type-of';
7
7
  import type { Logger } from 'egg-logger';
8
- import { getParamNames, readJSONSync } from 'utility';
8
+ import { getParamNames, readJSONSync, readJSON } from 'utility';
9
9
  import { extend } from 'extend2';
10
10
  import { Request, Response, Context, Application } from '@eggjs/koa';
11
11
  import { pathMatching, type PathMatchingOptions } from 'egg-path-matching';
@@ -462,7 +462,7 @@ export class EggLoader {
462
462
  plugin.path = this.getPluginPath(plugin);
463
463
 
464
464
  // read plugin information from ${plugin.path}/package.json
465
- this.#mergePluginConfig(plugin);
465
+ await this.#mergePluginConfig(plugin);
466
466
 
467
467
  // disable the plugin that not match the serverEnv
468
468
  if (env && plugin.env.length > 0 && !plugin.env.includes(env)) {
@@ -538,7 +538,7 @@ export class EggLoader {
538
538
  for (const name in customPlugins) {
539
539
  this.#normalizePluginConfig(customPlugins, name, configPath);
540
540
  }
541
- debug('Loaded custom plugins: %j', Object.keys(customPlugins));
541
+ debug('Loaded custom plugins: %o', customPlugins);
542
542
  }
543
543
  return customPlugins;
544
544
  }
@@ -623,16 +623,18 @@ export class EggLoader {
623
623
  // "strict": true, whether check plugin name, default to true.
624
624
  // }
625
625
  // }
626
- #mergePluginConfig(plugin: EggPluginInfo) {
626
+ async #mergePluginConfig(plugin: EggPluginInfo) {
627
627
  let pkg;
628
628
  let config;
629
629
  const pluginPackage = path.join(plugin.path!, 'package.json');
630
- if (fs.existsSync(pluginPackage)) {
631
- pkg = readJSONSync(pluginPackage);
630
+ if (await utils.existsPath(pluginPackage)) {
631
+ pkg = await readJSON(pluginPackage);
632
632
  config = pkg.eggPlugin;
633
633
  if (pkg.version) {
634
634
  plugin.version = pkg.version;
635
635
  }
636
+ // support commonjs and esm dist files
637
+ plugin.path = this.#formatPluginPathFromPackageJSON(plugin.path!, pkg);
636
638
  }
637
639
 
638
640
  const logger = this.options.logger;
@@ -712,9 +714,9 @@ export class EggLoader {
712
714
  }
713
715
 
714
716
  // Following plugins will be enabled implicitly.
715
- // - configclient required by [hsfclient]
716
- // - eagleeye required by [hsfclient]
717
- // - diamond required by [hsfclient]
717
+ // - configclient required by [rpcClient]
718
+ // - monitor required by [rpcClient]
719
+ // - diamond required by [rpcClient]
718
720
  if (implicitEnabledPlugins.length) {
719
721
  let message = implicitEnabledPlugins
720
722
  .map(name => ` - ${name} required by [${requireMap[name]}]`)
@@ -769,7 +771,6 @@ export class EggLoader {
769
771
 
770
772
  #resolvePluginPath(plugin: EggPluginInfo) {
771
773
  const name = plugin.package || plugin.name;
772
-
773
774
  try {
774
775
  // should find the plugin directory
775
776
  // pnpm will lift the node_modules to the sibling directory
@@ -777,14 +778,38 @@ export class EggLoader {
777
778
  // 'node_modules/.pnpm/yadan@2.0.0/node_modules', <- this is the sibling directory
778
779
  // 'node_modules/.pnpm/egg@2.33.1/node_modules/egg/node_modules',
779
780
  // 'node_modules/.pnpm/egg@2.33.1/node_modules', <- this is the sibling directory
780
- const filePath = utils.resolvePath(`${name}/package.json`, { paths: [ ...this.lookupDirs ] });
781
- return path.dirname(filePath);
782
- } catch (err: any) {
781
+ const pluginPkgFile = utils.resolvePath(`${name}/package.json`, { paths: [ ...this.lookupDirs ] });
782
+ return path.dirname(pluginPkgFile);
783
+ } catch (err) {
783
784
  debug('[resolvePluginPath] error: %o', err);
784
- throw new Error(`Can not find plugin ${name} in "${[ ...this.lookupDirs ].join(', ')}"`);
785
+ throw new Error(`Can not find plugin ${name} in "${[ ...this.lookupDirs ].join(', ')}"`, {
786
+ cause: err,
787
+ });
785
788
  }
786
789
  }
787
790
 
791
+ #formatPluginPathFromPackageJSON(pluginPath: string, pluginPkg: {
792
+ eggPlugin?: {
793
+ exports?: {
794
+ import?: string;
795
+ require?: string;
796
+ };
797
+ };
798
+ }) {
799
+ if (pluginPkg.eggPlugin?.exports) {
800
+ if (typeof require === 'function') {
801
+ if (pluginPkg.eggPlugin.exports.require) {
802
+ pluginPath = path.join(pluginPath, pluginPkg.eggPlugin.exports.require);
803
+ }
804
+ } else {
805
+ if (pluginPkg.eggPlugin.exports.import) {
806
+ pluginPath = path.join(pluginPath, pluginPkg.eggPlugin.exports.import);
807
+ }
808
+ }
809
+ }
810
+ return pluginPath;
811
+ }
812
+
788
813
  #extendPlugins(targets: Record<string, EggPluginInfo>, plugins: Record<string, EggPluginInfo>) {
789
814
  if (!plugins) {
790
815
  return;
@@ -1036,9 +1061,10 @@ export class EggLoader {
1036
1061
  debug('loadExtend %s, filepaths: %j', name, filepaths);
1037
1062
 
1038
1063
  const mergeRecord = new Map();
1039
- for (let filepath of filepaths) {
1040
- filepath = this.resolveModule(filepath)!;
1064
+ for (const rawFilepath of filepaths) {
1065
+ const filepath = this.resolveModule(rawFilepath)!;
1041
1066
  if (!filepath) {
1067
+ debug('loadExtend %o not found', rawFilepath);
1042
1068
  continue;
1043
1069
  }
1044
1070
  if (filepath.endsWith('/index.js')) {
@@ -1421,6 +1447,9 @@ export class EggLoader {
1421
1447
  let mod = await this.requireFile(fullpath);
1422
1448
  if (typeof mod === 'function' && !isClass(mod)) {
1423
1449
  mod = mod(...inject);
1450
+ if (isPromise(mod)) {
1451
+ mod = await mod;
1452
+ }
1424
1453
  }
1425
1454
  return mod;
1426
1455
  }
@@ -1,6 +1,7 @@
1
1
  import { debuglog } from 'node:util';
2
2
  import path from 'node:path';
3
3
  import fs from 'node:fs';
4
+ import { stat } from 'node:fs/promises';
4
5
  import BuiltinModule from 'node:module';
5
6
  import { importResolve, importModule } from '@eggjs/utils';
6
7
 
@@ -18,14 +19,61 @@ const extensions = (Module as any)._extensions;
18
19
  const extensionNames = Object.keys(extensions).concat([ '.cjs', '.mjs' ]);
19
20
  debug('Module extensions: %j', extensionNames);
20
21
 
22
+ function getCalleeFromStack(withLine?: boolean, stackIndex?: number) {
23
+ stackIndex = stackIndex === undefined ? 2 : stackIndex;
24
+ const limit = Error.stackTraceLimit;
25
+ const prep = Error.prepareStackTrace;
26
+
27
+ Error.prepareStackTrace = prepareObjectStackTrace;
28
+ Error.stackTraceLimit = 5;
29
+
30
+ // capture the stack
31
+ const obj: any = {};
32
+ Error.captureStackTrace(obj);
33
+ let callSite = obj.stack[stackIndex];
34
+ let fileName = '';
35
+ if (callSite) {
36
+ // egg-mock will create a proxy
37
+ // https://github.com/eggjs/egg-mock/blob/master/lib/app.js#L174
38
+ fileName = callSite.getFileName();
39
+ /* istanbul ignore if */
40
+ if (fileName && fileName.endsWith('egg-mock/lib/app.js')) {
41
+ // TODO: add test
42
+ callSite = obj.stack[stackIndex + 1];
43
+ fileName = callSite.getFileName();
44
+ }
45
+ }
46
+
47
+ Error.prepareStackTrace = prep;
48
+ Error.stackTraceLimit = limit;
49
+
50
+ if (!callSite || !fileName) return '<anonymous>';
51
+ if (!withLine) return fileName;
52
+ return `${fileName}:${callSite.getLineNumber()}:${callSite.getColumnNumber()}`;
53
+ }
54
+
21
55
  export default {
22
56
  deprecated(message: string) {
23
- console.warn('[@eggjs/core:deprecated] %s', message);
57
+ if (debug.enabled) {
58
+ console.trace('[@eggjs/core:deprecated] %s', message);
59
+ } else {
60
+ console.warn('[@eggjs/core:deprecated] %s', message);
61
+ console.warn('[@eggjs/core:deprecated] set NODE_DEBUG=@eggjs/core:utils can show call stack');
62
+ }
24
63
  },
25
64
 
26
65
  extensions,
27
66
  extensionNames,
28
67
 
68
+ async existsPath(filepath: string) {
69
+ try {
70
+ await stat(filepath);
71
+ return true;
72
+ } catch {
73
+ return false;
74
+ }
75
+ },
76
+
29
77
  async loadFile(filepath: string) {
30
78
  try {
31
79
  // if not js module, just return content buffer
@@ -55,38 +103,7 @@ export default {
55
103
  return ctx ? fn.call(ctx, ...args) : fn(...args);
56
104
  },
57
105
 
58
- getCalleeFromStack(withLine?: boolean, stackIndex?: number) {
59
- stackIndex = stackIndex === undefined ? 2 : stackIndex;
60
- const limit = Error.stackTraceLimit;
61
- const prep = Error.prepareStackTrace;
62
-
63
- Error.prepareStackTrace = prepareObjectStackTrace;
64
- Error.stackTraceLimit = 5;
65
-
66
- // capture the stack
67
- const obj: any = {};
68
- Error.captureStackTrace(obj);
69
- let callSite = obj.stack[stackIndex];
70
- let fileName = '';
71
- if (callSite) {
72
- // egg-mock will create a proxy
73
- // https://github.com/eggjs/egg-mock/blob/master/lib/app.js#L174
74
- fileName = callSite.getFileName();
75
- /* istanbul ignore if */
76
- if (fileName && fileName.endsWith('egg-mock/lib/app.js')) {
77
- // TODO: add test
78
- callSite = obj.stack[stackIndex + 1];
79
- fileName = callSite.getFileName();
80
- }
81
- }
82
-
83
- Error.prepareStackTrace = prep;
84
- Error.stackTraceLimit = limit;
85
-
86
- if (!callSite || !fileName) return '<anonymous>';
87
- if (!withLine) return fileName;
88
- return `${fileName}:${callSite.getLineNumber()}:${callSite.getColumnNumber()}`;
89
- },
106
+ getCalleeFromStack,
90
107
 
91
108
  getResolvedFilename(filepath: string, baseDir: string) {
92
109
  const reg = /[/\\]/g;