solid-start icon indicating copy to clipboard operation
solid-start copied to clipboard

[Bug?]: (v1.1.0) Unable to inline server functions in components

Open peterhirn opened this issue 10 months ago • 2 comments

Duplicates

  • [x] I have searched the existing issues

Latest version

  • [x] I have tested the latest version

Current behavior 😯

Previously we were able to inline server functions directly in components. Since v1.1.0 this is no longer possible and throws a very verbose error (including the full component three times).

Expected behavior 🤔

I'm wondering if this change is deliberate or a bug. If it is deliberate, maybe the error message can be improved.

Steps to reproduce 🕹

import { action, useAction } from "@solidjs/router";
import { isServer } from "solid-js/web";

export default function Home() {
  const myAction = useAction(
    action(async () => {
      "use server";
      console.log(isServer);
    }),
  );

  return (
    <main>
      <button onClick={myAction}>Action</button>
    </main>
  );
}

pnpm build

📦 Compiling ssr router...
vinxi building router ssr in http mode
vite v6.1.0 building SSR bundle for production...
✓ 1 modules transformed.
x Build failed in 63ms

 ERROR  [tanstack-start-directive-vite-plugin]    1 | import { action, useAction } from "@solidjs/router";                                                                                                                  4:06:43 AM
   2 | import { isServer } from "solid-js/web";
>  3 | export default function Home() {
     |                               ^^
>  4 |   const myAction = useAction(action(async () => {
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  5 |     "use server";
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  6 |
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  7 |     console.log(isServer);
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  8 |   }));
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  9 |   return <main>
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 10 |       <button onClick={myAction}>Action</button>
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 11 |     </main>;
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 12 | }
     | ^ Server Functions cannot be nested in other blocks or functions
file: /home/peter/Projects/test/solid-start-inline-fn/src/routes/index.tsx?pick=default&pick=$css

      2 | import { isServer } from "solid-js/web";
    >  3 | export default function Home() {
        |                               ^^
    >  4 |   const myAction = useAction(action(async () => {
        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    >  5 |     "use server";
        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    >  6 |
        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    >  7 |     console.log(isServer);
        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    >  8 |   }));
        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    >  9 |   return <main>
        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    > 10 |       <button onClick={myAction}>Action</button>
        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    > 11 |     </main>;
        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    > 12 | }
        | ^ Server Functions cannot be nested in other blocks or functions
    file: src/routes/index.tsx?pick=default&pick=$css
    at codeFrameError (node_modules/.pnpm/@[email protected]/node_modules/@tanstack/directive-functions-plugin/dist/esm/compilers.js:326:10)
    at DirectiveLiteral (node_modules/.pnpm/@[email protected]/node_modules/@tanstack/directive-functions-plugin/dist/esm/compilers.js:177:19)
    at NodePath._call (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/path/context.js:49:20)
    at NodePath.call (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/path/context.js:39:18)
    at NodePath.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/path/context.js:88:31)
    at TraversalContext.visitQueue (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:90:16)
    at TraversalContext.visitSingle (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:66:19)
    at TraversalContext.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:113:19)
    at traverseNode (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/traverse-node.js:22:17)
    at NodePath.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/path/context.js:94:52)
    at TraversalContext.visitQueue (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:90:16)
    at TraversalContext.visitMultiple (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:62:17)
    at TraversalContext.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:111:19)
    at traverseNode (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/traverse-node.js:22:17)
    at NodePath.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/path/context.js:94:52)
    at TraversalContext.visitQueue (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:90:16)
    at TraversalContext.visitSingle (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:66:19)
    at TraversalContext.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:113:19)
    at traverseNode (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/traverse-node.js:22:17)
    at NodePath.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/path/context.js:94:52)
    at TraversalContext.visitQueue (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:90:16)
    at TraversalContext.visitMultiple (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:62:17)
    at TraversalContext.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:111:19)
    at traverseNode (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/traverse-node.js:22:17)
    at NodePath.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/path/context.js:94:52)
    at TraversalContext.visitQueue (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:90:16)
    at TraversalContext.visitMultiple (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:62:17)
    at TraversalContext.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:111:19)
    at traverseNode (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/traverse-node.js:22:17)
    at NodePath.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/path/context.js:94:52)
    at TraversalContext.visitQueue (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:90:16)
    at TraversalContext.visitSingle (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:66:19)
    at TraversalContext.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:113:19)
    at traverseNode (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/traverse-node.js:22:17)
    at NodePath.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/path/context.js:94:52)
    at TraversalContext.visitQueue (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:90:16)
    at TraversalContext.visitMultiple (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:62:17)
    at TraversalContext.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:111:19)
    at traverseNode (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/traverse-node.js:22:17)
    at NodePath.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/path/context.js:94:52)
    at TraversalContext.visitQueue (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:90:16)
    at TraversalContext.visitMultiple (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:62:17)
    at TraversalContext.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:111:19)
    at traverseNode (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/traverse-node.js:22:17)
    at NodePath.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/path/context.js:94:52)
    at TraversalContext.visitQueue (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:90:16)
    at TraversalContext.visitSingle (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:66:19)
    at TraversalContext.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/context.js:113:19)
    at traverseNode (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/traverse-node.js:22:17)
    at NodePath.visit (node_modules/.pnpm/@[email protected]/node_modules/@babel/traverse/lib/path/context.js:94:52)



 ERROR  [tanstack-start-directive-vite-plugin]    1 | import { action, useAction } from "@solidjs/router";                                                                                                                  4:06:43 AM
   2 | import { isServer } from "solid-js/web";
>  3 | export default function Home() {
     |                               ^^
>  4 |   const myAction = useAction(action(async () => {
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  5 |     "use server";
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  6 |
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  7 |     console.log(isServer);
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  8 |   }));
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  9 |   return <main>
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 10 |       <button onClick={myAction}>Action</button>
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 11 |     </main>;
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 12 | }
     | ^ Server Functions cannot be nested in other blocks or functions
file: /home/peter/Projects/test/solid-start-inline-fn/src/routes/index.tsx?pick=default&pick=$css


 ERROR  Exited with code: 1                                                                                                                                                                                                 4:06:43 AM

    at CommandChild.pipedStdoutBuffer (node_modules/.pnpm/[email protected]/node_modules/dax-sh/esm/mod.js:9392:19)
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)



 ERROR  Exited with code: 1                                                                                                                                                                                                 4:06:43 AM

 ELIFECYCLE  Command failed with exit code 1.

Context 🔦

No response

Your environment 🌎


peterhirn avatar Feb 17 '25 03:02 peterhirn

Hi, @peterhirn yes, that's an unpredicted regression. It's on me and I'm really sorry about that.

The new server-function plugin has much more aggressive treeshaking, this prevents code from leaking to the frontend. Unfortunately, as a consequence of that, it does not perform closure extraction.

As a workaround, you can refactor your code like such:

import { action, useAction } from "@solidjs/router";
import { isServer } from "solid-js/web";

const yourServerAction = action(async () => {
      "use server";
      console.log(isServer);
    }),

export default function Home() {
  const myAction = useAction(yourServerAction);

  return (
    <main>
      <button onClick={myAction}>Action</button>
    </main>
  );
}

And that would work again, plus, even in the old plugin - that would make your code safer, imho, by making it easier for the code-removal preventing it to land in the client-side bundle.


I'm still working on a better DX, either to migrate or to add code-extraction to the plugin.

atilafassina avatar Feb 18 '25 07:02 atilafassina

Hello, I wanted to confirm this is the same issue

This code causes the same error original post showed:

import { createAsync } from "@solidjs/router";

export default function Home() {
    const test = createAsync(async () => {
        "use server";
        console.log("Test!");
        return;
    });

    return <main class=""></main>;
}

While this code works fine:

import { createAsync } from "@solidjs/router";
import { isServer } from "solid-js/web";

export default function Home() {
    const test = createAsync(async () => {
        if (!isServer) return;

        console.log("Test!");
        return;
    });

    return <main class=""></main>;
}

It seems related/the same but I just thought I'd put this here in case anyone needs more info

MintyDoggo avatar Mar 22 '25 04:03 MintyDoggo