Repository: artusjs/core
Pull request #161 (2022-08-03 13:10:36)

fix: support resolve plugin path from framework
此 PR 旨在对插件正确寻址：每一层 framework 定义的插件如果使用 `package` 属性，则应当在 path 寻址时以对应的 framework path 为基础路径进行 `require.resolve` 操作，从而使得插件寻址这个动作是一个确定的结果。


Patch:
diff --git a/.gitignore b/.gitignore
index 3ed907a..9a2556f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -114,4 +114,6 @@ pnpm-lock.yaml
 lib
 
 # OSX
-.DS_Store
\ No newline at end of file
+.DS_Store
+
+!test/fixtures/frameworks/layer/foo/foo2/node_modules
\ No newline at end of file
diff --git a/jest.config.js b/jest.config.js
index 43eb663..64928b8 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -12,4 +12,5 @@ module.exports = {
   ],
   coverageReporters: ['json', 'json-summary', 'lcov', 'text', 'clover', 'text-summary', 'cobertura'],
   collectCoverageFrom: ['<rootDir>/src/**/*.ts'],
+  transformIgnorePatterns: ["/node_modules/(?!(artus_plugin_hbase)/)", "\\.pnp\\.[^\\\/]+$"]
 };
diff --git a/src/loader/impl/plugin_config.ts b/src/loader/impl/plugin_config.ts
index ec1544a..1cc26ff 100644
--- a/src/loader/impl/plugin_config.ts
+++ b/src/loader/impl/plugin_config.ts
@@ -29,7 +29,8 @@ class PluginConfigLoader extends ConfigLoader implements Loader {
           );
         }
         if (pluginConfigItem.enable) {
-          pluginConfigItem.path = ArtusPlugin.getPath(pluginConfigItem.package);
+          const loaderState = item._loaderState as { baseDir: string };
+          pluginConfigItem.path = ArtusPlugin.getPath(pluginConfigItem.package, [loaderState.baseDir]);
         }
         delete pluginConfigItem.package;
         configObj[pluginName] = pluginConfigItem;
diff --git a/src/plugin/base.ts b/src/plugin/base.ts
index 6d53a91..0118dda 100644
--- a/src/plugin/base.ts
+++ b/src/plugin/base.ts
@@ -3,8 +3,9 @@ import path from 'path';
 type PluginMap = Map<string, BasePlugin>;
 
 export class BasePlugin implements Plugin {
-  static getPath(packageName: string): string {
-    return path.resolve(require.resolve(packageName), '..');
+  static getPath(packageName: string, paths?: string[]): string {
+    const opts = paths ? { paths } : undefined;
+    return path.resolve(require.resolve(packageName, opts), '..');
   }
 
   public name: string;
diff --git a/src/scanner/scan.ts b/src/scanner/scan.ts
index b3885ce..2fa987b 100644
--- a/src/scanner/scan.ts
+++ b/src/scanner/scan.ts
@@ -177,6 +177,9 @@ export class Scanner {
         filename,
         loader,
         source: 'config',
+        _loaderState: {
+          baseDir,
+        },
       };
     }));
     await loaderFactory.loadItemList(configItemList.filter(v => v) as ManifestItem[]);


Test patch:
diff --git a/test/fixtures/artus_application/src/controller/plugin.ts b/test/fixtures/artus_application/src/controller/plugin.ts
index 5b0bacf..d34bea7 100644
--- a/test/fixtures/artus_application/src/controller/plugin.ts
+++ b/test/fixtures/artus_application/src/controller/plugin.ts
@@ -7,6 +7,8 @@ import { Context } from '@artus/pipeline';
 export default class Hello {
   @Inject('ARTUS_MYSQL')
   private client: any;
+  @Inject('ARTUS_HBASE')
+  private client2: any;
 
   @HttpMethod({
     method: HTTPMethodEnum.GET,
@@ -36,4 +38,14 @@ export default class Hello {
     } : { message: 'plugin redis not enabled' };
     return result;
   }
+
+  @HttpMethod({
+    method: HTTPMethodEnum.GET,
+    path: '/plugin-hbase',
+  })
+  async getHbaseClient() {
+    return {
+      client: await this.client2.getClient(),
+    };
+  }
 }
diff --git a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/index.ts b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/index.ts
new file mode 100644
index 0000000..b9f001e
--- /dev/null
+++ b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/index.ts
@@ -0,0 +1,1 @@
+export * from './src/client'
\ No newline at end of file
diff --git a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/meta.json b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/meta.json
new file mode 100644
index 0000000..cab84c6
--- /dev/null
+++ b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/meta.json
@@ -0,0 +1,4 @@
+{
+  "name": "hbase",
+  "configDir": "src/custom_config"
+}
\ No newline at end of file
diff --git a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/package.json b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/package.json
new file mode 100644
index 0000000..24c1049
--- /dev/null
+++ b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/package.json
@@ -0,0 +1,3 @@
+{
+  "name": "@artus/plugin-hbase"
+}
\ No newline at end of file
diff --git a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/src/app.ts b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/src/app.ts
new file mode 100644
index 0000000..d2904df
--- /dev/null
+++ b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/src/app.ts
@@ -0,0 +1,19 @@
+import { Server } from 'http';
+import { LifecycleHookUnit, LifecycleHook } from '../../../../../../../../../src/decorator';
+import { ApplicationLifecycle } from '../../../../../../../../../src/types';
+import { ArtusApplication, Inject, ArtusInjectEnum } from '../../../../../../../../../src';
+import Client, { MysqlConfig } from './client';
+
+export let server: Server;
+
+@LifecycleHookUnit()
+export default class MyLifecycle implements ApplicationLifecycle {
+  @Inject(ArtusInjectEnum.Application)
+  app: ArtusApplication;
+
+  @LifecycleHook()
+  async willReady() {
+    const hbase = this.app.container.get('ARTUS_HBASE') as Client;
+    await hbase.init(this.app.config.hbase as MysqlConfig);
+  }
+}
diff --git a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/src/client.ts b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/src/client.ts
new file mode 100644
index 0000000..96ec9f5
--- /dev/null
+++ b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/src/client.ts
@@ -0,0 +1,20 @@
+import { Injectable } from "@artus/injection";
+
+export interface MysqlConfig {
+  clientName: string
+}
+
+@Injectable({
+  id: 'ARTUS_HBASE',
+})
+export default class Client {
+  private clientName = '';
+
+  async init(config: MysqlConfig) {
+    this.clientName = config.clientName;
+  }
+
+  async getClient(): Promise<string> {
+    return this.clientName;
+  }
+}
\ No newline at end of file
diff --git a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/src/custom_config/config.default.ts b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/src/custom_config/config.default.ts
new file mode 100644
index 0000000..cf0d1bc
--- /dev/null
+++ b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/src/custom_config/config.default.ts
@@ -0,0 +1,5 @@
+export default {
+  hbase: {
+    clientName: 'foo2-hbase',
+  },
+};
\ No newline at end of file
diff --git a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/meta.json b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/meta.json
new file mode 100644
index 0000000..7b58b02
--- /dev/null
+++ b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/meta.json
@@ -0,0 +1,3 @@
+{
+  "name": "mysql"
+}
\ No newline at end of file
diff --git a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/package.json b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/package.json
new file mode 100644
index 0000000..f8da133
--- /dev/null
+++ b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/package.json
@@ -0,0 +1,3 @@
+{
+  "name": "@artus/plugin-mysql-rds"
+}
\ No newline at end of file
diff --git a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/src/app.ts b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/src/app.ts
new file mode 100644
index 0000000..32c6ae0
--- /dev/null
+++ b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/src/app.ts
@@ -0,0 +1,19 @@
+import { Server } from 'http';
+import { LifecycleHookUnit, LifecycleHook } from '../../../../../../../src/decorator';
+import { ApplicationLifecycle } from '../../../../../../../src/types';
+import { ArtusApplication, Inject, ArtusInjectEnum } from '../../../../../../../src';
+import Client, { MysqlConfig } from './client';
+
+export let server: Server;
+
+@LifecycleHookUnit()
+export default class MyLifecycle implements ApplicationLifecycle {
+  @Inject(ArtusInjectEnum.Application)
+  app: ArtusApplication;
+
+  @LifecycleHook()
+  async willReady() {
+    const mysql = this.app.container.get('ARTUS_MYSQL') as Client;
+    await mysql.init(this.app.config.mysql as MysqlConfig);
+  }
+}
diff --git a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/src/client.ts b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/src/client.ts
new file mode 100644
index 0000000..bddcea5
--- /dev/null
+++ b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/src/client.ts
@@ -0,0 +1,20 @@
+import { Injectable } from "@artus/injection";
+
+export interface MysqlConfig {
+  clientName: string
+}
+
+@Injectable({
+  id: 'ARTUS_MYSQL',
+})
+export default class Client {
+  private clientName = '';
+
+  async init(config: MysqlConfig) {
+    this.clientName = config.clientName;
+  }
+
+  async getClient(): Promise<string> {
+    return this.clientName;
+  }
+}
\ No newline at end of file
diff --git a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/src/config/config.default.ts b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/src/config/config.default.ts
new file mode 100644
index 0000000..9b5306e
--- /dev/null
+++ b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/src/config/config.default.ts
@@ -0,0 +1,5 @@
+export default {
+  mysql: {
+    clientName: 'mysql-rds',
+  },
+};
\ No newline at end of file
diff --git a/test/fixtures/frameworks/layer/foo/foo2/src/config/plugin.ts b/test/fixtures/frameworks/layer/foo/foo2/src/config/plugin.ts
new file mode 100644
index 0000000..77ccf66
--- /dev/null
+++ b/test/fixtures/frameworks/layer/foo/foo2/src/config/plugin.ts
@@ -0,0 +1,6 @@
+export default {
+  hbase: {
+    enable: true,
+    package: 'artus_plugin_hbase',
+  },
+};
\ No newline at end of file
diff --git a/test/framework.test.ts b/test/framework.test.ts
index 7f556d0..376fb0e 100644
--- a/test/framework.test.ts
+++ b/test/framework.test.ts
@@ -51,6 +51,8 @@ describe('test/framework.test.ts', () => {
     assert(testResponseName4.data.client === 'mysql-ob');
     const testResponseName5 = await axios.get(`http://127.0.0.1:${port}/plugin-redis`);
     assert(testResponseName5.data.message === 'plugin redis not enabled');
+    const testResponseName6 = await axios.get(`http://127.0.0.1:${port}/plugin-hbase`);
+    assert(testResponseName6.data.client === 'foo2-hbase');
 
     await app.artus.close();
     assert(!app.isListening());