solidjs / solid-router

A universal router for Solid inspired by Ember and React Router
MIT License
1.1k stars 137 forks source link

'use server' at top of file results in TypeError: action.apply is not a function #458

Closed sabercoy closed 1 week ago

sabercoy commented 2 weeks ago

Describe the bug

import { useAction } from '@solidjs/router'
import { doThingAction } from '../server-functions/send-verify-email'

export default function Home() {
  const doThing = useAction(doThingAction)

  const attemptThing = async (event: Event) => {
    event.preventDefault()

    await doThing({
      email: 'wouldbefromsignal'
    }).then(result => {
      console.log('then')
    }).catch(error => {
      console.log(error)
    })
  }

  return (
    <main>
      <form onSubmit={attemptThing}>
        <button onClick={attemptThing}>EXECUTE</button>
      </form>
    </main>
  );
}
'use server'

import { action } from '@solidjs/router'

export const doThingAction = action(async (params: any) => {
  //'use server'

  return 'hello'
})

this results in image

but doing 'use server' inside the function

//'use server'

import { action } from '@solidjs/router'

export const doThingAction = action(async (params: any) => {
  'use server'

  return 'hello'
})

works fine

Your Example Website or App

https://stackblitz.com/~/github.com/sabercoy/solid-useserver-action

Steps to Reproduce the Bug or Issue

copy the code into latest solid start

Expected behavior

'use server' being used in either case behaves the same

Screenshots or Videos

No response

Platform

Additional context

No response

ryansolid commented 1 week ago

Hmm... that error is probably because the action function is getting called outside of any router context. When you put action inside a server function it isn't in the same environment that did the calling. It is now on the server. So useAction or the form in the browser can't see it.

action doesn't make sense inside 'use server'. When you put 'use server' at the top of the file that means everything it exports is a server function. action belongs outside of the server function. It runs on the client to manage cache invalidation.

sabercoy commented 1 week ago

Hmm... that error is probably because the action function is getting called outside of any router context. When you put action inside a server function it isn't in the same environment that did the calling. It is now on the server. So useAction or the form in the browser can't see it.

action doesn't make sense inside 'use server'. When you put 'use server' at the top of the file that means everything it exports is a server function. action belongs outside of the server function. It runs on the client to manage cache invalidation.

okay, I think my understanding is that when 'use server' is inside the anonymous function (inside of action) it will make the anonymous function run on the server, not the action and when 'use server' is at the top, it makes the action run on the server which is not the correct place

Hmm, I guess I thought that the compiling/bundling would automatically see the action and know to make its inner function server-only. If my understanding is correct, we can close this issue and I thank you for the clarification!

ryansolid commented 1 week ago

Yeah.. both features are developed independently with server functions being the more primary one. So the compiler is aware of them, but has no idea what action is which comes from the router.