fix(guard): derive must-not-bundle candidates independently of external
Addresses the suppressed review comment on #2099, which was the sharpest of the three rounds: the guard stopped looking at a package the moment its `external` entry was removed — so deleting `"undici"` from the web config would have made the pre-fix bundle pass. That is self-referential, and #2067 was precisely a MISSING declaration, so the guard covered its regression but not the bug. Candidates are now the union of two independently-derived lists: each client's `external` array, and the root manifest's `dependencies` — root-declared by rule, reached through `core/`, and required to be external in every client bundle. Removing a package from an `external` list can no longer remove it from scrutiny. That immediately surfaced one latent instance of the same rule violation: `@modelcontextprotocol/ext-apps` is root-declared and reached through `core/mcp/apps.ts`, but was absent from the CLI's `external` list and was being inlined into `index.js` — dragging the transitive v1 SDK and zod-to-json-schema in with it. It is ESM, so it was not failing the way `undici` did; what it violated was the rule. Adding it drops the CLI bundle from 590KB to 518KB. It is also a real example of the shape the previous revision could not see: it was inlined into the entry, emitting no `<pkg>-HASH.js` chunk at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JTHVxSu8AUgHRLvo1ntZ8H Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
2f83549bc3
commit
dbe95e58ed
1 changed files with 87 additions and 10 deletions
|
|
@ -205,12 +205,56 @@ describe("evaluateClient", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("flags a root dependency even when the external list omits it", () => {
|
||||
// THE #2067 SHAPE, and the reason the candidate set is not just `externals`.
|
||||
// `undici` was missing from the web and TUI external lists — that omission
|
||||
// WAS the bug — so a guard driven only by those lists would have inspected
|
||||
// the inlined 1.05MB bundle and reported success. Removing a package from an
|
||||
// `external` list must not remove it from scrutiny.
|
||||
const failures = evaluateClient({
|
||||
name: "web",
|
||||
build: "clients/web/build",
|
||||
externals: ["pino"],
|
||||
rootDependencies: ["undici", "pino"],
|
||||
files: [
|
||||
{
|
||||
name: "undici-HXPKCIY3.js",
|
||||
source: banner("../../node_modules/undici/lib/core/symbols.js"),
|
||||
},
|
||||
],
|
||||
});
|
||||
assert.equal(failures.length, 1);
|
||||
assert.match(failures[0], /"undici" is declared external but was inlined/);
|
||||
});
|
||||
|
||||
test("does not flag a deliberately inlined package that is not a root dependency", () => {
|
||||
// The TUI inlines `ink-form` / `ink-scroll-view` on purpose (#1952). They are
|
||||
// declared in the TUI's own manifest, never at the root, which is exactly
|
||||
// what keeps them out of the candidate set.
|
||||
assert.deepEqual(
|
||||
evaluateClient({
|
||||
name: "tui",
|
||||
build: "clients/tui/build",
|
||||
externals: ["react", "ink"],
|
||||
rootDependencies: ["react"],
|
||||
files: [
|
||||
{
|
||||
name: "index.js",
|
||||
source: banner("../../node_modules/ink-form/lib/Form.js"),
|
||||
},
|
||||
],
|
||||
}),
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
test("passes a clean bundle", () => {
|
||||
assert.deepEqual(
|
||||
evaluateClient({
|
||||
name: "web",
|
||||
build: "clients/web/build",
|
||||
externals: ["undici"],
|
||||
rootDependencies: ["undici"],
|
||||
files: clean,
|
||||
}),
|
||||
[],
|
||||
|
|
|
|||
Loading…
Reference in a new issue