From 8e3536ea84384d6e5a85fea51e16a8716bfffe43 Mon Sep 17 00:00:00 2001 From: "Alexis H. Munsayac" Date: Fri, 19 Jun 2026 09:22:42 +0800 Subject: [PATCH 1/4] fix #2160 --- .../src/directives/remove-unused-variables.ts | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/start/src/directives/remove-unused-variables.ts b/packages/start/src/directives/remove-unused-variables.ts index 6155bfea7..bc7bfdcc0 100644 --- a/packages/start/src/directives/remove-unused-variables.ts +++ b/packages/start/src/directives/remove-unused-variables.ts @@ -2,6 +2,20 @@ import type * as babel from "@babel/core"; import * as t from "@babel/types"; import { isPathValid } from "./paths.ts"; +function isInvalidForRemoval(path: babel.NodePath) { + if (isPathValid(path, t.isCatchClause)) { + // This case is for `catch (error)` blocks + return true; + } + + // This one is for destructured variables + let target = path; + if (isPathValid(path, t.isVariableDeclarator)) { + target = path.get('id'); + } + return isPathValid(target, t.isObjectPattern) || isPathValid(target, t.isArrayPattern); +} + export function removeUnusedVariables(program: babel.NodePath) { // TODO(Alexis): // This implementation is simple but slow @@ -24,17 +38,18 @@ export function removeUnusedVariables(program: babel.NodePath) { case "hoisted": case "module": if (binding.references === 0 && !binding.path.removed) { - if (isPathValid(binding.path.parentPath, t.isImportDeclaration)) { const parent = binding.path.parentPath; + if (isPathValid(parent, t.isImportDeclaration)) { if (parent.node.specifiers.length === 1) { parent.remove(); } else { binding.path.remove(); } - } else { + dirty = true; + } else if (!(isInvalidForRemoval(binding.path))) { binding.path.remove(); + dirty = true; } - dirty = true; } break; case "local": From 02b1763b3d3c1dbdb0adab39a3a79b6d0a067555 Mon Sep 17 00:00:00 2001 From: Katja Lutz Date: Sat, 27 Jun 2026 15:35:28 +0200 Subject: [PATCH 2/4] test: build server function with unused try catch variable --- apps/tests/src/e2e/server-function.test.ts | 7 +++++ .../server-function-unused-trycatch.tsx | 26 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 apps/tests/src/routes/server-function-unused-trycatch.tsx diff --git a/apps/tests/src/e2e/server-function.test.ts b/apps/tests/src/e2e/server-function.test.ts index c77656e9d..157a39c63 100644 --- a/apps/tests/src/e2e/server-function.test.ts +++ b/apps/tests/src/e2e/server-function.test.ts @@ -91,4 +91,11 @@ test.describe("server-function", () => { await page.goto("http://localhost:3000/server-env"); await expect(page.locator("#server-fn-test")).toContainText('{"result":true}'); }); + + test("should build with a server function including an unused try/catch variable", async ({ + page, + }) => { + await page.goto("http://localhost:3000/server-function-unused-trycatch"); + await expect(page.locator("#server-fn-test")).toContainText("false"); + }); }); diff --git a/apps/tests/src/routes/server-function-unused-trycatch.tsx b/apps/tests/src/routes/server-function-unused-trycatch.tsx new file mode 100644 index 000000000..a7a4bfe6e --- /dev/null +++ b/apps/tests/src/routes/server-function-unused-trycatch.tsx @@ -0,0 +1,26 @@ +import { createEffect, createSignal } from "solid-js"; + +function serverFnTryCatch() { + "use server"; + + try { + throw new Error(); + } catch (error) { + return false; + } +} + +export default function App() { + const [output, setOutput] = createSignal(); + + createEffect(async () => { + const result = await serverFnTryCatch(); + setOutput(result); + }); + + return ( +
+ {JSON.stringify(output())} +
+ ); +} From c4ebb445adbb57699796e071b3090c16b136e706 Mon Sep 17 00:00:00 2001 From: Katja Lutz Date: Sat, 27 Jun 2026 15:39:38 +0200 Subject: [PATCH 3/4] test: build server function with unused destructured variable --- apps/tests/src/e2e/server-function.test.ts | 7 +++++ .../server-function-unused-destructure.tsx | 28 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 apps/tests/src/routes/server-function-unused-destructure.tsx diff --git a/apps/tests/src/e2e/server-function.test.ts b/apps/tests/src/e2e/server-function.test.ts index 157a39c63..73df02fe3 100644 --- a/apps/tests/src/e2e/server-function.test.ts +++ b/apps/tests/src/e2e/server-function.test.ts @@ -98,4 +98,11 @@ test.describe("server-function", () => { await page.goto("http://localhost:3000/server-function-unused-trycatch"); await expect(page.locator("#server-fn-test")).toContainText("false"); }); + + test("should build with a server function including an unused destructured variable", async ({ + page, + }) => { + await page.goto("http://localhost:3000/server-function-unused-destructure"); + await expect(page.locator("#server-fn-test")).toContainText("false"); + }); }); diff --git a/apps/tests/src/routes/server-function-unused-destructure.tsx b/apps/tests/src/routes/server-function-unused-destructure.tsx new file mode 100644 index 000000000..c1c574767 --- /dev/null +++ b/apps/tests/src/routes/server-function-unused-destructure.tsx @@ -0,0 +1,28 @@ +import { createEffect, createSignal } from "solid-js"; + +function serverFnDestructure() { + "use server"; + + const rawItems = [{ id: "", age: 42 }]; + const items: { age: number }[] = []; + for (const { id, ...rest } of rawItems) { + items.push(rest); + } + + return false; +} + +export default function App() { + const [output, setOutput] = createSignal(); + + createEffect(async () => { + const result = await serverFnDestructure(); + setOutput(result); + }); + + return ( +
+ {JSON.stringify(output())} +
+ ); +} From 02cb296b6667b88df4fd005a9eb1314e05eace85 Mon Sep 17 00:00:00 2001 From: "Alexis H. Munsayac" Date: Mon, 29 Jun 2026 02:42:48 +0800 Subject: [PATCH 4/4] fix: #2168 --- packages/start/src/config/index.ts | 22 ++++++++++++---------- packages/start/src/directives/index.ts | 1 + 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/start/src/config/index.ts b/packages/start/src/config/index.ts index 9cdc6830e..447f26ab7 100644 --- a/packages/start/src/config/index.ts +++ b/packages/start/src/config/index.ts @@ -63,6 +63,18 @@ export function solidStart(options?: SolidStartOptions): Array { server: `${start.appRoot}/entry-server${entryExtension}`, }; return [ + // TODO (Alexis): check if the comment below is still relevant + // + // Must be placed after fsRoutes, as treeShake will remove the + // server fn exports added in by this plugin + serverFunctionsPlugin({ + manifest: VIRTUAL_MODULES.serverFnManifest, + runtime: { + server: '@solidjs/start/fns/server', + client: '@solidjs/start/fns/client', + }, + filter: options?.serverFunctions?.filter, + }), { name: "solid-start:config", enforce: "pre", @@ -190,16 +202,6 @@ export function solidStart(options?: SolidStartOptions): Array { }), lazy(), envPlugin(options?.env), - // Must be placed after fsRoutes, as treeShake will remove the - // server fn exports added in by this plugin - serverFunctionsPlugin({ - manifest: VIRTUAL_MODULES.serverFnManifest, - runtime: { - server: '@solidjs/start/fns/server', - client: '@solidjs/start/fns/client', - }, - filter: options?.serverFunctions?.filter, - }), { name: "solid-start:virtual-modules", async resolveId(id) { diff --git a/packages/start/src/directives/index.ts b/packages/start/src/directives/index.ts index 0219fe346..04a30395c 100644 --- a/packages/start/src/directives/index.ts +++ b/packages/start/src/directives/index.ts @@ -196,6 +196,7 @@ export function serverFunctionsPlugin(options: ServerFunctionsOptions): Plugin[] }, { name: "solid-start:server-functions/compiler", + enforce: 'pre', async transform(code, fileId, opts) { const mode = opts?.ssr ? "server" : "client"; const [id] = fileId.split("?");