DEV Community

Cover image for SolidStart, Netlify and Forms
Matti Bar-Zeev
Matti Bar-Zeev

Posted on

SolidStart, Netlify and Forms

My daughter has ventured into the world of bracelet crafting, and now she's on a mission to conquer the internet with her handmade creations and maybe even get some orders going. I thought it was a good opportunity to have a go on SolidStart and build a complete (yet very naive) eComm site with it.

You may wonder why I chose SolidStart. Well, I am particularly impressed with SolidJS and believe that this framework offers a compelling alternative to other UI frameworks out there, mainly React. However, that is a separate discussion altogether.

Fueled by an abundance of motivation and under the watchful eye of my sweet yet demanding child, I embarked on my late-night coding sessions, completely unaware of the intriguing (or should I say, "frustrating") challenges that awaited me.

Curious to know how I conquered those obstacles? Well, you're in for a treat. Just keep reading...


Hey! for more content like the one you're about to read check out @mattibarzeev on Twitter 🍻


First let’s set some background

SolidStart?

SolidStart is a meta-framework (I didn’t coin the term, look it up) that stands shoulder-to-shoulder with the likes of NextJS, SvelteKit, and Remix. It's a game-changer when it comes to simplifying the development process of robust web applications. Think of it as your go-to solution for effortlessly bundling essential components like routing, authentication, and other features that are often deemed repetitive and mundane.

Netlify?

Netlify is a platform which helps developers publish their web content efficiently and fast. From efficient hosting solutions to seamless integration with your codebase, automation workflows, form submission handling, and powerful APIs, Netlify has got you covered and then some.

What's particularly exciting is that Netlify has recently welcomed Rayn Corniato, the mastermind behind SolidJS, as one of its employees, so this all comes together quite nicely :)

Deploying SolidStart on Netlify

I’ve created the site, with nested routes and what-have-you and reached a point where I want to deploy it and check the end-to-end “purchase” flow.
I utilize Netlify's Github deployment option, which involves granting Netlify access to a specific Github repository. In this setup, I define a command, typically an npm script like npm run build, that generates the site artifacts. Additionally, I specify the distribution directory.

With this configuration, Netlify actively monitors any changes made to a designated branch on Github. When a change occurs, Netlify automatically triggers the build command and deploys the resulting artifacts from the specified distribution directory. This seamless integration ensures that my site stays up to date with minimal effort.

This works well in most ordinary cases, but SolidStart is a bit different.
You see, the “dist” directory does not contain any HTML files nor does it have any edge functions that handles the site’s requests. This means that if we give Netlify the out-of-the-box “dist” directory as the distribution directory, the site won’t work.

Luckily there is a solution for that - A Vite plugin called solid-start-netlify.
Though still experimental, I found out that it did the work for me. You use it like this in your vite.config.js:

import netlify from 'solid-start-netlify';
...


export default defineConfig({
    plugins: [
        solid({
            adapter: netlify({edge: true}),
        }),
    ],
});
Enter fullscreen mode Exit fullscreen mode

By setting the adapter like so, Vite will now create a new distribution directory called “netlify” and in it you will find the edge functions’ declaration that Netlify can work with in order to respond with the site’s content.
Here is the netlify directory content:

Image description

Now you can set Netlify to take the “netlify” directory as the distribution directory and it works as expected.

SolidStart forms submission on Netlify

Netlify offers a cool feature that simplifies form submission handling. Here's how it works: by annotating your form as being managed by Netlify, you enable Netlify to automatically analyze the form, extract the necessary data, and attentively listen for any submissions. Once a form is submitted, you can conveniently access the data in a dedicated section within your Netlify admin console.

But again, it’s different when it comes to SolidStart 🙂
There are 2 challenges here - the first one is not related specifically to SolidStart (or SolidJS for that matter), but it is a general issue that Netlify has with JS generated forms.

When I say JS generated forms I mean any form which is generated using JS (that obviously means JSX as well). You see, when netlify is “asked” to inspect a certain form, it expects it to be a real markup, so it can traverse it and extract the different fields that will be submitted.
It cannot do that with JS generated form (yet, I believe this is something that they are either working on now or in the near future), so we have to use a workaround for that

The workaround is to create an html file which has the form, named as you desire, and with the same fields the JSX form has. Here is an example for the form tag of a “regular” html form:

<form name="checkout" netlify netlify-honeypot="bot-field" hidden>
...
Enter fullscreen mode Exit fullscreen mode

“netlify” tells Netlify to inspect this form. I created such a file and placed it in the “public” directory.
The next step is to take our JSX form and add a hidden input field to it which adds a “form-name” field to the submission with a value of the same name we gave the “regular” html form.
So If we named our “regular” form “checkout” we need to add this field to our JSX form:

<input type="hidden" name="form-name" value="checkout" />
Enter fullscreen mode Exit fullscreen mode

Now Netlify can inspect that “regular” html form and register it with its fields. You can read more about this approach here.

The second challenge is a bit more complex, and sadly not documented (so I hope you’ve found this resource after a short search) -
I would like to have a onSubmit callback for my form, cause I would like to do some data manipulations before sending it to the server, so I add this:

<form onSubmit={handleSubmit}>
Enter fullscreen mode Exit fullscreen mode

And according to the docs, this is what you need to do in the callback:

const handleSubmit = (event) => {
event.preventDefault();


const myForm = event.target;
const formData = new FormData(myForm);


fetch('/', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams(formData).toString(),
});
};
Enter fullscreen mode Exit fullscreen mode

We gather to form data and do a POST request to the root route.
But this does not submit the form… why?

The reason is that the root route, or any other SolidStart route for that matter, is handled by an edge function, and submitting a form to a route which is handled by an edge function cripples Netlify form submission handling.

So what do we do then? We submit the form to a route we know is static, like… the “regular” html form we’ve used before (it’s in the public directory and therefore available). Changing the POST endpoint to that file solved the issue!

To recap

  • Netlify does not know how to inspect JS generated forms out-of-the-box
  • Make sure that you have a “regular” html form with a name and all the fields of the JSX form, available on the public directory
  • Add hidden input in your JSX form which defines a “form-name” field with the value of the name you gave the “regular” html form
  • You cannot submit a Netlify managed form to an endpoint which is handled by an edge function
  • On submit, make sure that the endpoint you’re submitting to is not being handled by edge functions

I hope this helps you, and if you’re aware of other or better ways to achieve that, make sure you share with the rest of us in the comments below :)


Hey! for more content like the one you've just read check out @mattibarzeev on Twitter 🍻

Top comments (0)