Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: form actions for progressive enhancement #20852

Closed
wants to merge 0 commits into from

Conversation

Hebilicious
Copy link
Member

@Hebilicious Hebilicious commented May 15, 2023

πŸ”— Linked issue

#20649

❓ Type of change

  • πŸ“– Documentation (updates to the documentation, readme or JSdoc annotations)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • πŸ‘Œ Enhancement (improving an existing functionality like performance)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

πŸ“š Description

Here's a standalone module with the most up-to-date version : https://github.com/Hebilicious/form-actions-nuxt

This PR is a POC that attempts to implements #20649. Almost everything is implemented as a Nuxt Module.

It adds the following helper features to Nuxt or Nitro :

  • defineServerLoader
  • defineFormActions
  • actionResponse

It adds the following helpers to H3 :

  • getRequestFromEvent
  • respondWithResponse
  • respondWithRedirect
  • getFormData

All of these should only be available on the server side (ie /server directory)
It could be argued that some of these helpers might be overkill and should be implemented by users, but for the sake of nice DX I added them anyways

It adds the useFormAction composable to Nuxt.
And the v-enhance directive.

Finally it adds the possibility to Nitro to specify fallback routes (nitro.config.routesWithFallback) to an array of route objects through the configuration ({ route: "api/todos", fallbackTo: '/**' }). The fallback route will be matched with a GET method.
Effectively This allows creating POST endpoints on the same route than pages.

There's a classic todo example with optimistic updates for the delete method.

πŸ“ Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@Hebilicious Hebilicious changed the title Form Actions feat: form actions for progressive enhancement May 15, 2023
@Hebilicious Hebilicious marked this pull request as ready for review May 23, 2023 12:57
@Hebilicious
Copy link
Member Author

Hebilicious commented May 23, 2023

@pi0 I would like to know your thoughts about the proposed changes to Nitro, and if you think the extra H3 helpers should go into H3 ?

  • H3 Helpers :
    • getRequestFromEvent : returns a native Request object.
    • respondWithResponse : sends a native Response object.
    • getFormData : returns a FormData object.
    • respondWithRedirect : small wrapper around sendRedirect (maybe un-necessary)

Personally I think the first 3 are great additions to H3 and make your life easier.

  • Nitro Helpers :
    • defineServerLoader : Helper to create a server loader (get event handler with a _nitro/loaders prefix)
    • defineFormActions : Helper to create form actions
    • actionResponse : Helper to respond to the client with progressive enhancement

The amount of value this brings to Nitro is debatable, so I'm not sure if that makes the cut in Nitro. Maybe this should be provided by the Nuxt part of the app.

  • Nitro Changes (Please check the pnpm patch)

This is required to make the feature works.

If you're happy with the way it looks, I will open PR in nitro and h3, and the rest of the changes in this PR can be distributed as a module so people can start playing around with it.

@danielroe There's a few things that I think could increase things nicely, but I'm not sure how to approach them.

  • Type extraction for the loaders :
    We could have some Typescript magic going on to have the loaders data typed in the template, which isn't currently the case. useFormAction call useFetch under the hood (const { data: result, refresh, pending } = useFetch(url, { watch, immediate: true, server: true })) so maybe this isn't too hard to achieve ?

  • Automatically bind v-enhance to the first form.
    Instead of this ...

<script setup>
const { enhance } = useFormAction()  //This would automatically bind to the form.
</script>
<template>
  <form method="POST" v-enhance="enhance">
	 ...
  </form>
</template>

... we could have this.

<script setup>
useFormAction() 
</script>
<template>
  <form method="POST">
     ...
  </form>
</template>

imo this isn't super important but it makes things neater in the simple use cases.

  • DevTools integration
    I'm actually not sure what that should look like, but I'm open to suggestions.

@danielroe danielroe marked this pull request as draft June 7, 2023 20:10
@danielroe
Copy link
Member

danielroe commented Jun 7, 2023

Marking as draft until we (ie. nuxt community) have time to test the amazing implementation work done at https://github.com/Hebilicious/form-actions-nuxt. ❀️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants