The race for innovation between frontend frameworks has been evolving for quite some time now. While React has innovated with features like JSX, which makes expressing UI logic more declarative, Svelte has introduced compilation to reduce the size of client bundles. On the other hand, SolidJS combines these ideas, along with the smart use of composable primitives and observables.
Parallel to the innovation of these frameworks is the evolution of the meta-frameworks built on top of them, like Next.js for React, SvelteKit for Svelte, and more recently, SolidStart for SolidJS. In this article, we’ll explore SolidStart, consider its features and use cases, and finally, build a simple app. To follow along, you can access the full code for the tutorial on GitHub. Let’s get started!
Table of contents
- SolidStart features
- Setting up our SolidStart app
- Folder structure
- Defining our business trips data
- Using API routes with SolidStart
- Bringing in the trips data to the route
- The
Trips
component - Displaying the
Trips
component
SolidStart features
SolidJS offers many of the features you’d expect from a meta-framework, including file-based routing, API endpoints, and support for server-side, client-side, and static rendering.
SolidStart also comes equipped with some amazing, unique features, like the ability to use forms to trigger server actions, similar to RemixJS, as well as the ability to easily define RPC functions using its $server
function.
It’s important to note that at the time of writing, SolidStart is still in experimental status, and many features may be missing or incomplete. It’s advised to use SolidStart at your own risk. With that said, we can still use SolidStart to set up a simple app.
Setting up our SolidStart app
In this tutorial, we’ll build a simple application that stores data about business trips, including mileage and location. To begin, you should already have Node.js installed on your machine.
First, open up your code editor to an empty folder. If you don’t already have pnpm installed, run npm install -g pnpm
. Then, run pnpm create solid
.
When prompted to add server-side rendering, select yes. Select no for TypeScript, then choose a bare template. Once the app is generated, run pnpm install
.
Folder structure
When using SolidStart, the code you’ll work with will live in the /src
folder, which in itself contains some files and folders that you should be familiar with.
/components
: Store all components that aren’t pages in the/components
folder/routes
: Store components that are pages in/routes
. A page would be the default export of that fileroot/entry-client/entry-server
: Store files that handle the application startup, which we don’t need to touch
Create a /lib
folder, which you’ll use to create supporting files, for example, a lot of our API implementation details, support functions, and more.
Defining our business trips data
Instead of using a database, we’ll use an array to demonstrate more simply how to work with our data models. If you’d rather use MongoDB, you can check out this article.
Create a file called src/lib/trips.js
:
// The Trips Array const trips = [ { location: "Miami, FL", mileage: 80, }, { location: "Savannah, GA", mileage: 120, }, ]; // functions for working with trips we can then convert into API routes or RPC calls export function getTrips(){ return trips } export function createTrip(newTrip){ trips.push(newTrip) return trips } export function updateTrip(id, updatedTrip){ trips[id] = updatedTrip return trips } export function deleteTrip(id){ trips.splice(id, 1) return trips }
In this file, we’ve created a trip
array to hold our data, as well as functions for working with our array:
getTrips
: Returns the array of trips, similar toSELECT * FROM table
in SQLcreateTrip
: Takes in an object and creates a new trip by pushing it into an array, simulating aINSERT INTO table VALUES (…)
query in a databaseupdateTrip
: Updates a trip in the array, similar toUPDATE table WHERE conditions SET updates
querydeleteTrip
: Deletes a trip in the array, similar toDELETE FROM table WHERE conditions
query
These functions essentially will simulate having a data model from a database ORM.
Now, we can make these functions usable to our application in two ways. For one, we can write API routes that use these functions. Alternately, in relevant components, we can define RPC calls using these functions with the $server
function. Keep in mind that RPC, a Remote Procedure Call, refers to when a function that is run on the server is called from a function call on the client.
Using API routes with SolidStart
Any route can be an API endpoint. The route file just needs to export an async GET
/POST
/PUT
/DELETE
function to handle that type of request for that route. If the route renders a page by export defaulting a component, then you can’t define an additional GET
for that route.
To show an example of this, we’ll create a file called src/routes/api/trips/(trips).js
. Notice that the file name has parenthesis around it. This is a feature of SolidStart that allows you to denote the main file in a folder for a route. So, this file would handle the /api/trips
URL. Normally, we would have to name the file index.jsx
. After a while, having so many files with the same name gets confusing.
Place the following code in the index.jsx
file:
// json function for sending json responses import { json } from "solid-start"; import { getTrips, createTrip } from "~/lib/trips"; export async function GET(){ // return the array of trips return json(getTrips()) } export async function POST({request}){ // get the request body const body = await new Response(request.body).json() // create new trip createTrip(body) // return all trips return json(getTrips()) }
Now, start your server with npm run dev
, and you should be able to use something like Postman or Insomnia to test the routes.
Make a GET
request to http://localhost:3000/api/trips/
, and you should get all your trips back:
Make a POST
request to http://localhost:3000/api/trips/
with a JSON body like the one below, and you should see the trip added:
{ "location": "Manchester,ct", "mileage": 1000 }
Awesome, we now have working API endpoints, how easy was that!
Bringing in the trips data to the route
In SolidStart, we can pre-fetch data for the route that is available to the page
route and all the child components.
We export routeData
, and its return value becomes available to the page and subcomponents via the useRouteData
Hook.
Let’s set up our main page src/routes/index.jsx
to create route data as the result of an API call to our API Route:
import { createRouteData } from "solid-start"; // define our route data, server provided data to frontend export function routeData() { return createRouteData(async () => { // fetch data from api endpoint const response = await fetch("http://localhost:3000/api/trips") const data = await response.json() return data }); } export default function Home() { return ( <main> </main> ); }
Notice that we used the createRouteData
function. This function works a lot like React Query, where we can wrap an asynchronous action with the following benefits:
- Whenever a route action occurs, the async function will run again, updating our data
- The data can be given a unique name to assist with caching if we’re using the same data in multiple routes
We’ll see in our trip
component how we can use actions and route data.
The Trips
component
Now, we’ll create a file to put this all together in src/components/Trips.jsx
:
import { createRouteAction, useRouteData} from "solid-start"; import { createTrip } from "~/lib/trips"; import server$ from "solid-start/server"; export default function Trips() { // bring the route data into our component const trips = useRouteData(); // Define an RPC call of what we want to run on the server const makeTrip = server$(async (trip) => createTrip(trip)) // define a form for creating a trip using solid-states action system const [_, { Form }] = createRouteAction(async (formData) => { // create the new trip object const trip = { location: formData.get("location"), mileage: formData.get("mileage") } // pass object RPC call to create new trip on server makeTrip(trip) }); return ( <div> <ul> {trips()?.map((trip) => ( <li>{trip.location} - mileage: {trip.mileage}</li> ))} </ul> <Form> <input type="input" name="location" placeholder="location"/> <input type="number" name="mileage" placeholder="mileage"/> <input type="submit"/> </Form> </div> ); }
In this component, we use many SolidStart features; for one, we use useRouteData
to get the routeData
defined in the page
component. server$
defines a function that runs solely on the server. In this case, we want the function that creates Trips
to run only on the server since it wouldn’t work on the client.
Finally, createRouteAction
creates a function and the corresponding Form
component. The Form
component calls the function that acts as an action, triggering a refetch of routeData
.
Displaying the Trips
component
Edit your src/routes/index.jsx
as follows:
import { createRouteData } from "solid-start"; import Trips from "~/components/Trips"; // define our route data, server provided data to frontend export function routeData() { return createRouteData(async () => { // fetch data from api endpoint const response = await fetch("http://localhost:3000/api/trips") const data = await response.json() return data }); } export default function Home() { return ( <main> <Trips/> </main> ); }
Using the useRouteData
Hook, we export the routeData()
function, which allows us to pre-fetch data to be used by the page and it’s subcomponents.
The createRouteData
creates a resource that will refetch anytime an action like the one our form triggers on submit
occurs. Finally, the <Trips/>
component displays our trips and form.
Conclusion
Hopefully, you’ve gotten a sense of just how powerful the SolidStart framework can be. Although it is still experimental at the time of writing, SolidStart has a promising future. If you want to see other variations of what you can do with SolidStart, check out the following builds:
The post Getting started with SolidStart: A SolidJS framework appeared first on LogRocket Blog.
from LogRocket Blog https://ift.tt/uNG2aE8
Gain $200 in a week
via Read more