embroider 和 pnpm 都要求包正确声明其依赖项:如果使用则列出依赖项(当且仅)。
在使用yarn@v1的大型单一存储库(考虑具有许多ember插件和node包的ember应用程序)上工作时,这是很难做到的。开发人员可能会忘记更新 package.json,因为即使缺少依赖项,ember 应用程序也可以构建和运行,只要从另一个包中拉入即可。
因此,构建和运行都无法告诉我们某个包是否未正确声明其依赖项。我们还能如何修复 package.json 以便引入 embroidery 和 pnpm?
1.静态代码分析
给定一个文件,我们可以看到应该存在哪些依赖项,因为我们知道 javascript 和 ember 是如何工作的。
例如,要显示 javascript(或 typescript)文件,
import { setupintl } from 'ember-intl/test-support'; import { setuprenderingtest as upstreamsetuprenderingtest } from 'ember-qunit'; export function setuprenderingtest(hooks, options) { upstreamsetuprenderingtest(hooks, options); // additional setup for rendering tests can be done here. setupintl(hooks, 'de-de'); }
从 import 语句中我们可以看出该包依赖于 ember-intl 和 ember-qunit。
并且,如果要显示模板文件,
{{page-title "my app"}} <welcomepage></welcomepage> {{outlet}}
我们对 ember 及其插件生态系统的了解分别引导我们进入 ember-page-title、ember-welcome-page 和 ember-source。即使事情是隐式的(例如双花括号中的歧义、模块解析、服务注入),由于 ember 强大的约定,我们也可以高精度地猜测资产的来源。
2. 代码修改
不过,我们不应该手动检查每个包中的每个文件。这既耗时又容易出错。
相反,我们使用@codemod-utils 编写一个codemod(实际上是一个linter)。对于每个包,codemod 都会解析相关内容并创建应该存在的依赖项列表(“实际”)。然后,它将列表与 package.json 中的列表进行比较(“预期”)。
要分析隐式代码,需要有一个已知资产列表(一次性创建),它将我们想要考虑的每个包映射到其资产。我们可以使用 map 来记录这些信息。
const known_assets = new map([ [ 'ember-intl', { helpers: [ 'format-date', 'format-list', 'format-message', 'format-number', 'format-relative', 'format-time', 't', ], services: ['intl'], }, ], [ 'ember-page-title', { helpers: ['page-title'], services: ['page-title'], }, ], [ 'ember-welcome-page', { components: ['welcome-page'], }, ], ]);
现在,由于 ember 的工作原理,对 import 语句的简单分析可能会导致误报。举个例子:
import route from '@ember/routing/route'; import fetch from 'fetch';
当我们不提供正确的上下文时(即此代码适用于 ember),codemod 会将 @ember/routing 和 fetch 视为依赖项,而不是 ember-source 和(可能)ember-fetch。 codemod 应该以这样的方式呈现其分析,以便我们可以轻松检查误报。
// Results for my-package-37 { missingDependencies: [ 'ember-asset-loader', 'ember-truth-helpers' ], unusedDependencies: [ '@babel/core', 'ember-auto-import', 'ember-cli-babel' ], unknowns: [ 'Services - host-router (addon/routes/registration.ts)', ] }
3. 结果
我(几天内)构建的 codemod 在 49 秒内分析了包含 129 个包的生产存储库。总共有 12,377 个文件,但 codemod 只知道分析其中的 6,013 个(不到一半)。平均每个文件 0.008 秒,每个包 0.38 秒!
要了解有关编写 codemod 的更多信息,请查看 @codemod-utils 的主要教程。