Skip to content

fix(build): bundle image-size in vinext - #2913

Merged
james-elicx merged 1 commit into
mainfrom
codex/bundle-image-size
Aug 14, 2026
Merged

fix(build): bundle image-size in vinext#2913
james-elicx merged 1 commit into
mainfrom
codex/bundle-image-size

Conversation

@james-elicx

Copy link
Copy Markdown
Member

Summary

  • bundle the build-time-only image-size package into vinext's published tooling output
  • move image-size from runtime dependencies to dev dependencies
  • keep both static image imports and metadata image dimension extraction working without exposing image-size in consumer install graphs

Validation

  • vp check
  • vp test run tests/image-imports.test.ts tests/metadata-route-build-data.test.ts
  • vp run vinext#build
  • packed vinext and confirmed its published package.json has no image-size dependency while the bundled implementation is present under dist/deps
  • installed the tarball in an isolated project with no image-size package, verified dimension extraction, and completed a production Pages Router build with a static image import
  • confirmed the built application output contains no image-size references or parser code

@pkg-pr-new

pkg-pr-new Bot commented Aug 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@2913
npm i https://pkg.pr.new/create-vinext-app@2913
npm i https://pkg.pr.new/@vinext/types@2913
npm i https://pkg.pr.new/vinext@2913

commit: ae26b9f

@github-actions

Copy link
Copy Markdown
Contributor
Example Preview Production Original
app-router-cloudflare preview production
pages-router-cloudflare preview production
app-router-playground preview production original
realworld-api-rest preview production
nextra-docs-template preview production
benchmarks preview production
hackernews preview production original
workers-cache preview production
web preview production

@github-actions

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared ae26b9f against base ee1d857 using alternating same-runner rounds. Next.js was unchanged and skipped.

0 improved · 0 regressed · 6 within ±1.5%

Scenario Framework Baseline Current Change
Client bundle size (gzip) vinext 135.4 KB 135.4 KB ⚫ +0.0%
Client entry size (gzip) vinext 122.8 KB 122.8 KB ⚫ +0.0%
Dev server cold start vinext 2.30 s 2.30 s ⚫ +0.3%
Production build time vinext 2.48 s 2.46 s ⚫ -0.6%
RSC entry closure size (gzip) vinext 114.6 KB 114.6 KB ⚫ +0.0%
Server bundle size (gzip) vinext 194.8 KB 194.8 KB ⚫ +0.0%

View detailed results and traces

🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head

@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: fix(build): bundle image-size in vinext

Verified locally: built the package, confirmed bundling, ran the cited tests, and checked format. This LGTM.

What I verified

  • Both usage sites are build-time only, matching the PR claim:
    • src/server/metadata-route-build-data.ts:3 (static import)
    • src/index.ts:6173 (dynamic import in the plugin load hook)
  • image-size@2.0.2 has zero dependencies, so bundling produces a self-contained 24KB chunk with no external imports — a clean candidate for alwaysBundle (same rationale as am-i-vibing/pathslash).
  • Build output is correct:
    • Static import → import imageSize from "../deps/.pnpm/image-size@2.0.2/deps/image-size/dist/index.js" in dist/server/metadata-route-build-data.js.
    • Dynamic import → rewritten to await import("./deps/.pnpm/image-size@2.0.2/deps/image-size/dist/index.js") in dist/index.js (relative, not a machine-specific absolute path — this is exactly the dynamic-import trap the externalizeBareThirdPartySpecifiers comment guards against, and it's handled correctly here via the new id === "image-size" early-return).
    • Emitted under dist/deps/... (not dist/node_modules/...), so build/standalone.ts's node_modules pruning won't drop it.
  • Published package.json no longer lists image-size under dependencies (now devDependencies); files: ["dist"] ships the bundled dist/deps output.
  • Tests pass: tests/image-imports.test.ts (27) + tests/metadata-route-build-data.test.ts (10) — all green.
  • Format check passes.
  • Lockfile diff only moves the image-size importer entry from prod to dev deps for packages/vinext; the other image-size reference in the lockfile is fumadocs-core's own transitive dep and is unrelated.

Minor observations (non-blocking)

  • neverBundle uses id.includes("image-size"), a substring match. I confirmed only one image-size@* package exists in the tree, so there's no collision today. This is consistent with the existing am-i-vibing/pathslash substring pattern, so it's fine to keep for consistency — just noting the same fragility applies to all four entries.
  • Consider a regression test asserting the built output contains no bare image-size specifier (the PR description mentions doing this manually). Not required, but would lock in the guarantee that this dep stays out of consumer install graphs.

Nice, well-scoped change with thorough manual validation. No issues found.

@ask-bonk

ask-bonk Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Review posted to PR #2913.

Summary

I reviewed fix(build): bundle image-size in vinext and it LGTM — no blocking issues found. I validated it locally rather than just reading the diff:

Verified:

  • Both image-size usages are build-time only (metadata-route-build-data.ts:3 static, index.ts:6173 dynamic).
  • image-size@2.0.2 has zero deps → self-contained 24KB bundled chunk with no external imports.
  • Ran vp run vinext#build and confirmed:
    • Static import rewritten to relative ../deps/.pnpm/image-size@2.0.2/...
    • Dynamic import rewritten to relative ./deps/.pnpm/... — correctly avoids the machine-specific absolute-path trap the config comment warns about (handled by the new id === "image-size" early-return in externalizeBareThirdPartySpecifiers).
    • Output lands under dist/deps/ (not dist/node_modules/), surviving standalone.ts pruning.
  • Published package.json drops image-size from dependencies (moved to dev); files: ["dist"] ships the bundle.
  • Tests pass (37/37), format check passes.
  • Lockfile diff only relocates the importer entry; the other image-size lockfile ref is fumadocs-core's unrelated transitive dep.

Non-blocking notes raised in the review:

  • neverBundle uses a substring includes("image-size") match — safe today (only one such package), consistent with existing am-i-vibing/pathslash pattern.
  • Suggested a regression test asserting no bare image-size specifier in built output, to lock in the guarantee.

Clean, well-scoped change with thorough manual validation.

github run

@james-elicx
james-elicx marked this pull request as ready for review August 14, 2026 08:30
@james-elicx
james-elicx merged commit a3d1d1d into main Aug 14, 2026
66 checks passed
@james-elicx
james-elicx deleted the codex/bundle-image-size branch August 14, 2026 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant