Repository: artusjs/core
Pull request #197 (2022-09-15 10:00:42)

feat(scanner): add parsed pluginConfig to manifest
本 PR 向 Manifest 类型定义和 Scanner.scan 方法逻辑中增加了 `pluginConfig` 字段，值为经解析后的插件配置，用于：

- 运行时数据上报 / 构建时依赖分析
- 多 Env 场景下的运行时 Manifest 合并逻辑中，作为 plugin 启用判断的辅助数据

codecov-commenter: # [Codecov](https://codecov.io/gh/artusjs/core/pull/197?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
Base: **90.71**% // Head: **90.76**% // Increases project coverage by **`+0.04%`** :tada:
> Coverage data is based on head [(`e0ccd9f`)](https://codecov.io/gh/artusjs/core/pull/197?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) compared to base [(`d171511`)](https://codecov.io/gh/artusjs/core/commit/d171511503c5c0ecac38205eddfbc05bbf18b791?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).
> Patch coverage: 100.00% of modified lines in pull request are covered.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #197      +/-   ##
==========================================
+ Coverage   90.71%   90.76%   +0.04%     
==========================================
  Files          48       48              
  Lines        1099     1104       +5     
  Branches      195      197       +2     
==========================================
+ Hits          997     1002       +5     
  Misses        102      102              
```


| [Impacted Files](https://codecov.io/gh/artusjs/core/pull/197?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [src/scanner/scan.ts](https://codecov.io/gh/artusjs/core/pull/197/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL3NjYW5uZXIvc2Nhbi50cw==) | `95.23% <100.00%> (+0.16%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/artusjs/core/pull/197?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).

hyj1991: 给 `Manifest` 增加额外属性，是否可以考虑把 `config` 完整 dump 出来，`plugin` 作为 config 的一个字段属性：

```ts
{
  items: [ ],
  config: { },
  relative: boolean
}
```

实践中一般 `config` 也需要静态 dump 用作分析，这样后面也无需增加额外字段来存储了。
noahziheng: @hyj1991 这里有个问题是现在 config 支持 Function 模型，这样的话其值是动态的 cc @JerrysShan 
hyj1991: > 这里有个问题是现在 config 支持 Function 模型，这样的话其值是动态的

这确实是一个问题，那么考虑将明确静态的配置导出到 `config` 字段下呢，其实比如 `framework` 继承链，有时候也需要导出用作分析（尤其在继承链复杂的场景）
noahziheng: > > 这里有个问题是现在 config 支持 Function 模型，这样的话其值是动态的
> 
> 这确实是一个问题，那么考虑将明确静态的配置导出到 `config` 字段下呢，其实比如 `framework` 继承链，有时候也需要导出用作分析（尤其在继承链复杂的场景）

那感觉还是要特定化 frameworkConfig 可以放进来，对于其他的配置项，还得是走动态 dump app.config 这种运行时分析方案
hyj1991: 其实 #196 和本 PR 有类似的问题，我在想既然 `plugin` & `framework` 处理这么特殊，是不是可以把定义从 `config` 目录中分离出来，放到比如 `meta.json` 里面作为元信息申明

好处是：
* `meta.json` 是一个已有的设计，目前只存在 plugin & framework 中，那么考虑在 app 中也允许元信息的申明
* 将配置的动态和静态部分分开，`meta.json` 中只会存在静态的元信息
noahziheng: @hyj1991 我个人认为有点激进了，对目前的设计冲击似乎太大，转个 Issue 讨论下吧
hyj1991: 嗯，我可以搞个 POC 看看对目前的逻辑的冲击，到时候和 RFC 一并放出来，本 PR 和 #196 作为关联项作为参考

Patch:
diff --git a/src/loader/types.ts b/src/loader/types.ts
index a3d82e4..6ed9ea7 100644
--- a/src/loader/types.ts
+++ b/src/loader/types.ts
@@ -1,8 +1,10 @@
 import { Container } from '@artus/injection';
 import { ScanPolicy } from '../constant';
+import { PluginConfigItem } from '../plugin/types';
 
 interface Manifest {
   items: ManifestItem[];
+  pluginConfig?: Record<string, PluginConfigItem>;
   relative?: boolean;
 }
 
diff --git a/src/scanner/scan.ts b/src/scanner/scan.ts
index e4e6401..a686414 100644
--- a/src/scanner/scan.ts
+++ b/src/scanner/scan.ts
@@ -129,9 +129,18 @@ export class Scanner {
     // 4. scan all file in app
     await this.walk(root, this.formatWalkOptions('app', root, ''));
 
+    const relative = this.options.useRelativePath;
+    if (relative) {
+      for (const [pluginName, pluginConfigItem] of Object.entries(pluginConfig)) {
+        if (pluginConfigItem.path) {
+          pluginConfig[pluginName].path = path.relative(root, pluginConfigItem.path);
+        }
+      }
+    }
     const result: Manifest = {
-      items: this.getItemsFromMap(this.options.useRelativePath, root, env),
-      relative: this.options.useRelativePath,
+      pluginConfig,
+      items: this.getItemsFromMap(relative, root, env),
+      relative,
     };
     return result;
   }


Test patch:
diff --git a/test/scanner.test.ts b/test/scanner.test.ts
index 5204fdb..f93c1e0 100644
--- a/test/scanner.test.ts
+++ b/test/scanner.test.ts
@@ -27,6 +27,11 @@ describe('test/scanner.test.ts', () => {
     expect(manifest.items.filter(item => item.unitName === 'redis').length).toBe(2);
     expect(manifest.items.filter(item => item.unitName === 'mysql').length).toBe(0);
     expect(manifest.items.filter(item => item.source === 'app').length).toBe(8);
+    expect(manifest.pluginConfig).toStrictEqual({
+      redis: { enable: true, path: path.join('src', 'redis_plugin') },
+      mysql: { enable: false, path: path.join('src', 'mysql_plugin') },
+      testDuplicate: { enable: false, path: path.join('..', '..', '..', 'node_modules', '@artus', 'injection', 'lib') },
+    });
 
     const { dev: devManifest } = scanResults;
     // console.log('devManifest', devManifest);
@@ -36,6 +41,11 @@ describe('test/scanner.test.ts', () => {
     expect(devManifest.items.filter(item => item.loader === 'config').length).toBe(2);
     expect(devManifest.items.filter(item => item.loader === 'plugin-meta').length).toBe(2);
     expect(devManifest.items.find(item => item.unitName === 'testDuplicate')).toBeDefined();
+    expect(devManifest.pluginConfig).toStrictEqual({
+      redis: { enable: true, path: path.join('src', 'redis_plugin') },
+      mysql: { enable: false, path: path.join('src', 'mysql_plugin') },
+      testDuplicate: { enable: true, path: path.join('src', 'test_duplicate_plugin') },
+    });
   });
 
   it('should scan module with custom loader', async () => {