Skip to main content

ADR004 模块导出结构

上下文

随着诸如@backstage/core-components现在越来越难回答以下问题

该模块中的导出是否也由软件包导出?

该目录导出了什么?

目前,我们没有使用任何模式来构建导出结构。 我们混合使用了深入目录树的软件包级再导出、每个目录的浅层再导出、使用*这种混杂和缺乏可预测性的情况,使我们很难推理模块的边界,例如,很难知道在给定文件中导出某个符号是否安全。

决定

我们将使每个导出的符号都能通过索引文件一直追溯到软件包的根目录、src/index.ts每个索引文件只会从自己的直接子目录重新导出,只有索引文件才会有重新导出。 这样就得到了类似下面的文件树:

index.ts
components/index.ts
/ComponentX/index.ts
/ComponentX.tsx
/SubComponentY.tsx
lib/index.ts
/UtilityX/index.ts
/UtilityX.ts
/helper.ts

例如SubComponentY如果有任何索引文件没有导出前一个索引文件,则该符号不会被公开导出。 例如,如果components/ComponentX/index.ts出口SubComponentY但是components/index.ts不会再出口./ComponentX我们应该确定SubComponentY不会导出到软件包之外。index.ts再出口./components/ComponentX

此外,重新导出其他索引文件的索引文件应始终使用通配符形式,即

// in components/index.ts
export * from './ComponentX';

从非索引文件重新导出符号的索引文件应始终枚举所有导出符号,即

// in components/ComponentX/index.ts
export { ComponentX } from './ComponentX';
export type { ComponentXProps } from './ComponentX';

例如,允许从非索引模块向索引模块进行内部跨目录导入:

// in components/ComponentX/ComponentX.tsx
import { UtilityX } from '../../lib/UtilityX';

我们不鼓励绕过索引文件进行导入,但有时可能是必要的,例如:

// in components/ComponentX/ComponentX.tsx
import { helperFunc } from '../../lib/UtilityX/helper';

后果

我们将积极努力重新设计代码库中的导出结构,优先考虑库软件包,如@backstage/core-components@backstage/backend-common.

如果可能,我们将添加一些工具,如 lint 规则,以帮助执行导出结构。