What is SolidJS?
SolidJS, a powerful, lightweight real alternative to established libraries such as react.js. Despite the fact that it only weighs 7 kilobytes, it comes packed with powerful features such as a truly reactive system built on top of signals, an intuitive templating system based on the popular JSX, a lean built-in state management solution, and last but not least, an efficient solution to perform DOM updates, which helps Solid rank better than most competitors on this topic.
If you are still not convinced, the Solid team just released another amazing product: its meta-framework called SolidStart.
This is a huge step forward for the Solid ecosystem, so let's spend the next few minutes looking into SolidStart, analyze its main features, and figure out if it is as good as some of its competitors.
If you are not familiar with the concept of meta-frameworks, it is enough for you to know that these are a set of libraries and concepts bundled together around a popular UI library. The end goal of this approach is to provide an environment which allows developers to optimize their front-end apps and also, more importantly, do some server work, create REST APIs, and interact with databases.
SolidStart is not really innovating in this area, and other established libraries already have meta-frameworks for quite a while now. Think here of Next.js, which builds on top of React; Nuxt.js, which builds on top of Vue; and more recently, SvelteKit, which is built for the Svelte ecosystem.
Project Setup and File Structure
Okay, so let's start by creating a new project, and then we'll go through the framework's main features one by one. I am using NVM to make sure my Node version is up to date, and then I'm simply running the npm init solid command. This will start a small setup wizard for us, and we'll choose the basic project template, and of course, we'll use TypeScript for all the obvious reasons. Next, we'll run the npm install command so that all dependencies are downloaded locally in our node_modules folder, and we should be ready to go.
The resulting project will look like this. Let's briefly go through the structure so we know we are all on the same page. So, this uses Vite as a bundler and we also got a tsconfig file since we decided to use TypeScript here. And static assets can be stored in the public folder.
And now let's focus a bit on the source directory. We already have two folders in here: one where we can store our Solid components and one called routes.
Understanding File-Based UI Routing
This is where all the magic happens. In any well-designed application, everything relies on routes. This is the same in SolidStart, which uses the common file system-based routing approach to handle requests and map them to the corresponding components. There are two categories of routes: UI routes, which define the, quote unquote, pages or views of your application, and API routes, which define data endpoints running on the server.
So let's start by creating an index.tsx file directly under the routes folder. This will map the Home Solid component to the root path of the application. Inside the component, I'm simply returning some JSX with a list of URLs to some other pages in our application.
One thing to note here is the usage of a special Link component. This is a wrapper around the native link element, and it is able to work on the client side even when the application is not fully hydrated by leveraging the Islands architecture. As a big side note, the Islands architecture is a technique gaining a lot of traction in the front-end space at the moment. The approach leads to better performance by allowing devs to create HTML-first apps and deliver less JavaScript to the browser. One big proponent of this architecture is Astro.js, so check out the link in the top right corner to find out more about all this.
Creating Nested Routes
Our links are pointing to some nested routes that start with the learn string. We'll use nested folders to handle nested routes. So I'll create a learn directory and inside it a solid.sx file to map the /learn/solid path. There isn't anything interesting inside this component since we are simply rendering a header for our demo purposes. Now when the user will click on the Solid link, the appropriate page will be rendered accordingly. Let's do the same for Svelte next. If it looks repetitive, don't worry, we'll discuss dynamic routes in just a second.
Dynamic Routes and 404 Pages
Okay, so clicking on the Solid link is taking you to the right page, but let's see what happens when we try to access the React page, which is not mapped yet. The default not-found scenario simply renders a blank page, but we can override this behavior by defining a 404 page inside our learn directory.
Two things to keep in mind here. First of all, this 404 template will only apply to routes nested under the learn directory. And second, the square brackets and the leading dots are necessary because of the imposed naming conventions.
This looks promising, but can easily get out of hand when you have a large number of technologies you could learn. So we can leverage the power of dynamic routes here. Using the square brackets, let's define a [tech].tsx file. Inside the component, SolidStart will know to extract the URL information associated with the tech parameter and inject it into our component. So we can now easily handle not only the React route but any other future routes as well.
Okay, so you should now have an idea about the power of UI routes. However, this is not all, and API routes are actually more impressive. Let's remove the Svelte and the Solid TSX files, since our dynamic route will capture all tech options. Next, I am going to allow users to subscribe to a specific technology feed by inputting their email and sending a POST request to the server. We are able to do all this, including the backend work, directly with SolidStart.
I'll begin by declaring a signal to store the email value as component internal state. Signals are the building blocks of Solid's reactivity, and you can find more details on this topic in the link posted in the top right corner.
In the JSX, binding the input element to the signal is fairly straightforward, especially if you worked with UI libraries in the past. When the user clicks on the register button, the register function is called. A couple of things to note here: I am using the standard fetch API to make a POST request to the server. In a real application, you'd either move this code in some sort of service method or you could actually generate the code automatically using a standard such as the OpenAPI. Fetch returns a promise, so I'm using async/await to retrieve the response. Finally, the email and the tech parameter are sent in the request body as JSON.
Following the known convention, I am adding a subscribe.ts file under the api directory, and in here we can define our API routes. We can easily listen to any type of request method here by exporting a function with the same name as the HTTP method. So in our case, let's export a post function where we are simply extracting the body information and storing it somewhere for later usage. We'll return a 200 success message, and that's pretty much it.
Next, let's take a little detour and discuss another important aspect of web apps: handling page titles and meta tags. The root.tsx file contains some interesting stuff. Besides the special Title and Meta components, Suspense is a component that tracks all resource reads underneath and shows a fallback placeholder until they are resolved. ErrorBoundary is also important because it catches errors triggered in the component tree and renders a nice fallback if necessary. We can use any of these components anywhere in our app.
So let's add an appropriate title for our tech page. SolidStart will know to extract the Title tag from your component and will update the corresponding HTML tag.
The Full-Stack Power of SolidStart
Now in theory, we defined and implemented an entire HTTP request-response cycle with SolidStart. We have the front end up running our UI components, and we have a Node server under the hood which is able to listen to incoming requests and send back responses. This is the main selling point of any meta-framework, and SolidStart is able to gracefully handle such scenarios while also giving you access to a reactive, easy-to-use UI library which is built with efficiency in mind.
Server Data Fetching with routeData
There is another thing I'd like to do before we wrap things up. We can refactor our index.tsx page and fetch the available technologies directly from the back end. To do this, I added the technologies.ts file under the api directory where I'm simply returning a list of strings. Then, on the front end, we can retrieve the list by making an async GET request.
We are doing this in a special method called routeData, which will be automatically triggered when the component is loaded. Inside here, we are using Solid's built-in createResource method, which provides a useful wrapper around the HTTP call, and we are returning the result as an object.
In our Home component, we can then retrieve the data using the useRouteData method. Finally, in the JSX, we can now refactor our code and replace the hard-coded technologies with the list retrieved from the server. I am using Solid's utility <For> component here for convenience, but as always, this is JSX, so you can write your own custom components if you don't like them.
Conclusion
SolidStart provides other powerful features as well, so be sure to subscribe to this channel if you want to stay up to date with such topics. Please don't forget to like this video, and thank you for watching.