Skip to content

fix: keep non-picked route exports that picked exports reference#2205

Merged
birkskyum merged 9 commits into
mainfrom
fix/tree-shake-referenced-exports
Jul 20, 2026
Merged

fix: keep non-picked route exports that picked exports reference#2205
birkskyum merged 9 commits into
mainfrom
fix/tree-shake-referenced-exports

Conversation

@brenelz

@brenelz brenelz commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Fixes #2100

What is the current behavior?

The route tree-shaker deletes the entire binding of any export not in the ?pick list. An API route like

export const hello = () => "hello";
export const GET: APIHandler = async () => hello();

is imported with ?pick=GET, hello's declaration is removed, and the handler crashes at runtime with ReferenceError: hello is not defined (500 on every request). Verified end-to-end on a production build of the basic fixture.

There is also an always-true condition in the export-specifier handling that removes picked specifiers, so export { POST as GET } never survives — the root cause of #1659.

What is the new behavior?

Non-picked exports are un-exported instead of deleted: the export keyword is stripped and the binding stays in module scope. Kept bindings are registered with the existing sweep pass, which still removes them (and their imports) when nothing references them — so no code reaches a bundle it didn't already reach, addressing the server-code-leak concern discussed in #2104.

Details:

  • Mixed declarations (export const a = ..., GET = ...) are split into one declaration per declarator, preserving evaluation order; only picked ones stay exported.
  • Named default-export function/class declarations are kept in module scope (picked exports may reference them) and swept if unreferenced; anonymous ones are removed as before.
  • export { a, b as c } specifiers are now filtered by their exported name (fixes [Bug?]: export { POST as GET } is now broken #1659).
  • export class is handled like export function.

Other information

Added packages/start/src/config/fs-routes/tree-shake.spec.ts (9 tests, 5 of which fail without this fix). Full playwright e2e suite in apps/tests passes. Supersedes the approach in #2104, which un-exported picked declarators in mixed declarations, produced invalid syntax for anonymous default exports, and kept unreferenced non-picked exports in the output.

🤖 Generated with Claude Code

The route tree-shaker removed the entire binding of any export not in
the pick list, so an API handler calling a helper exported from the
same file crashed at runtime with a ReferenceError. Instead of deleting
the declaration, strip only the export keyword and register the kept
binding with the existing sweep pass, which still removes it (and its
imports) when nothing references it - so no extra code reaches a bundle
that didn't already reach it.

Also fixes an always-true condition in the export-specifier handling
that dropped picked exports declared via specifiers, e.g.
`export { POST as GET }`.

Mixed declarations (`export const a = ..., b = ...`) are split into one
declaration per declarator, preserving evaluation order, and only the
picked ones stay exported. Named default-export declarations are kept
in module scope when other exports reference them; anonymous ones are
still removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 60aa949

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@solidjs/start Patch

Not sure what this means? Click here to learn what changesets are.

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

@netlify

netlify Bot commented Jul 17, 2026

Copy link
Copy Markdown

Deploy Preview for solid-start-landing-page ready!

Name Link
🔨 Latest commit 60aa949
🔍 Latest deploy log https://app.netlify.com/projects/solid-start-landing-page/deploys/6a5e51b86fbec9000884b27c
😎 Deploy Preview https://deploy-preview-2205--solid-start-landing-page.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

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

Comment thread packages/start/src/config/fs-routes/tree-shake.ts
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pkg-pr-new

pkg-pr-new Bot commented Jul 17, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@solidjs/start@2205

commit: 60aa949

@lxsmnsyc lxsmnsyc left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'll approve this for now because of the tests, but I'll probably simplify this later

Copilot AI 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.

Pull request overview

This PR fixes SolidStart’s fs-routes tree-shaker so that non-picked exports that are still referenced by picked exports are no longer deleted (avoiding runtime ReferenceErrors), and so that export { ... } specifier exports are filtered correctly by exported name.

Changes:

  • Un-exports (strips export) instead of deleting certain non-picked bindings, allowing picked exports (e.g. GET) to reference helpers defined in the same module.
  • Fixes export { POST as GET } / aliased specifier handling by filtering based on the exported name.
  • Adds a dedicated Vitest suite covering the reported regressions and key edge cases (default export behavior, mixed declarations, import sweeping).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
packages/start/src/config/fs-routes/tree-shake.ts Adjusts the Babel transform to keep referenced non-picked bindings in module scope and correctly filter export specifiers by exported name.
packages/start/src/config/fs-routes/tree-shake.spec.ts Adds regression and behavior tests for keeping referenced helpers, alias specifiers, mixed declarations, default exports, and import cleanup.
.changeset/fix-2100-exports-disappear.md Publishes a patch changeset describing the fixes for #2100 and #1659.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@birkskyum
birkskyum merged commit f66b5a9 into main Jul 20, 2026
10 checks passed
@birkskyum
birkskyum deleted the fix/tree-shake-referenced-exports branch July 20, 2026 16:55
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.

[Bug?]: exports disappear [Bug?]: export { POST as GET } is now broken

4 participants