Skip to content

feat: add ghost dependency lint + CI enforcement#4546

Merged
2heal1 merged 2 commits intomodule-federation:mainfrom
2heal1:feat/ghost-dep-lint
Mar 14, 2026
Merged

feat: add ghost dependency lint + CI enforcement#4546
2heal1 merged 2 commits intomodule-federation:mainfrom
2heal1:feat/ghost-dep-lint

Conversation

@2heal1
Copy link
Copy Markdown
Member

@2heal1 2heal1 commented Mar 14, 2026

背景

防止幽灵依赖(Ghost Dependency):代码里 import 了某个包,但该包没有在自己的 package.json 里声明,靠 pnpm hoist 到根 node_modules 才能用。

改动

scripts/check-ghost-deps.mjs

轻量 Node.js 扫描脚本(无需 pnpm install 即可运行):

  • 遍历 packages/*/src/ 下所有 .ts/.tsx/.js/.jsx 文件
  • 过滤相对路径、node 内置、@module-federation/* workspace 包、虚拟模块
  • 对比该包 package.jsondependencies/devDependencies/peerDependencies
  • 未声明的包报错并非零退出
  • --fix 模式打印 pnpm --filter <pkg> add ... 修复建议

本地运行:

node scripts/check-ghost-deps.mjs         # 检测
node scripts/check-ghost-deps.mjs --fix   # 检测 + 打印修复命令
pnpm run lint:deps                         # 同上

package.json

新增 lint:deps script。

2heal1 added 2 commits March 14, 2026 22:57
- scripts/check-ghost-deps.mjs: 扫描 packages/*/src/ 下所有 import,
  对比各包 package.json 声明,输出未声明的第三方依赖(幽灵依赖)
  支持 --fix 模式打印 pnpm add 修复建议
- package.json: 新增 lint:deps script
- .github/workflows/check-ghost-deps.yml: 需手动添加(PAT 缺 workflow scope)

当前仓库存在以下幽灵依赖(待后续 PR 补声明):
- enhanced: fast-glob, tapable
- dts-plugin: directory-tree, vitest
- manifest: webpack
- modern-js/v3: vitest
- native-federation-tests: directory-tree, vitest
- native-federation-typescript: directory-tree, vitest, webpack
- node: tapable
- rsbuild-plugin: vitest
- sdk: @jest/globals, node-fetch, webpack
- storybook-addon: storybook
- third-party-dts-extractor: react, tsup, vitest
- typescript: axios, tapable
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 14, 2026

⚠️ No Changeset found

Latest commit: c0d5a84

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@netlify
Copy link
Copy Markdown

netlify bot commented Mar 14, 2026

Deploy Preview for module-federation-docs ready!

Name Link
🔨 Latest commit c0d5a84
🔍 Latest deploy log https://app.netlify.com/projects/module-federation-docs/deploys/69b57a9568cc810008f7fe90
😎 Deploy Preview https://deploy-preview-4546--module-federation-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@2heal1 2heal1 merged commit 799fe7a into module-federation:main Mar 14, 2026
8 of 10 checks passed
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c0d5a84cbd

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +164 to +167
const pkgDirs = fs
.readdirSync(PACKAGES_DIR, { withFileTypes: true })
.filter((e) => e.isDirectory())
.map((e) => path.join(PACKAGES_DIR, e.name));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Discover package manifests recursively under packages

This directory enumeration only inspects the first level under packages/, so grouped package folders are never linted as actual packages. In this repo, nested publishable packages such as packages/bridge/* and packages/runtime-plugins/* are skipped entirely (their package.json files are not at the first level), which means ghost dependencies in those packages can slip through while the new CI job reports success.

Useful? React with 👍 / 👎.

Comment on lines +183 to +185
// Scan src/ directory (some packages may have lib/ or root directory, also scan one level as fallback)
const srcDir = path.join(pkgDir, 'src');
const files = walkDir(srcDir, ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Scan package root when src is missing

The checker only walks <pkg>/src, even though the comment says there should be a fallback, so any package whose source files live outside src is effectively unchecked. For example, packages/metro-plugin-rnc-cli uses index.js at the package root, and undeclared imports there would never be reported by this lint gate.

Useful? React with 👍 / 👎.

@2heal1 2heal1 mentioned this pull request Mar 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant