Outline
- Introduction
- Create Client Rendered Solid Project
- Migrate Project to SolidStart
- Components and Reactive Primitives
- API Routes
- Deployment Adapters
All of this project's code can be found in the First Look monorepo on my GitHub.
Introduction
On November 9, 2022, Ryan Carniato published Introducing SolidStart: The SolidJS Framework to announce the beta launch of SolidStart, the eagerly awaited metaframework for SolidJS. SolidStart provides a first-party project starter and metaframework for SolidJS. It prescribes a recommended way to organize, architect, and deploy SolidJS applications.
Vite is included for the build tool along with extra Solid packages for common functionality and a CLI for generating templated projects. These packages enable features such as routing, MetaTags, different rendering modes, TypeScript support, and deployment adapters. In addition to Node and static hosting, adapters currently exist for the following platforms:
- Netlify Functions and Edge
- Vercel Functions and Edge
- Cloudflare Workers and Pages
- Deno Deploy
A History of SolidJS and How it Compares to React
Before diving into SolidStart, it's worth taking a moment to outline the history and motivation behind the creation of Solid. Branded as "a reactive JavaScript library for building user interfaces," Ryan open sourced the framework on April 24, 2018. It was designed as a spiritual successor to the reactive programming model exemplified by KnockoutJS.
React wasn’t the first JavaScript “Just a Render Library”. I attribute that honor to a much older library, KnockoutJS. Knockout didn’t have components but identified an application was built from 3 parts,
Model
,ViewModel
, andView
, and only cared about how you organized the latter. TheViewModel
was a revolutionary concept.
ViewModels
are instances much like components. But what set Knockout apart wasViewModels
could be anything you wanted; an object, a function, a class. There were no lifecycle functions. You could bring your own models and organize your application as you saw fit. Without best practices it could be a complete mess.But it was truly “Just a Render Library.” Those boundaries haven’t changed in over a decade... As
Controllers
transformed toRouters
,Models
toStores
, andViewModels
/Views
got wrapped together asComponents
, the anatomy of a Component (even in a smaller library like React) is still 3 main parts:
- Container
- Change (Local State) Manager
- Renderer
Ryan Carniato - B.Y.O.F. Writing a JS Framework in 2018 (November 10, 2018)
As the 2010s progressed, Ryan believed the JavaScript world had moved on from using composable reactive primitives in favor of class components and lifecycle methods. Dissatisfied with this direction, Ryan aimed for Solid to be a more modern reactive framework inspired by Knockout but with features informed by newer component frameworks like Angular, React, and Vue.
Shortly after the framework's release, React introduced hooks. Their debut in React Today and Tomorrow and 90% Cleaner React With Hooks, October 26, 2018 became a pivotal moment for Solid. React hooks are functions that can access React state and lifecycle methods from functional components. These functions can be composed into more complex UIs much like Solid.
Within a few years, the majority of React developers would be developing with composable, functional patterns. This ensured that React developers would find Solid easily comprehensible. But despite the surface level similarities between Solid and React's syntax, Solid has a few key advantages over React due to its underlying implementation.
Solid removes the need for some of React's more complex hooks that patch over the leaky abstraction underlying React. useCallback
exists to give React developers a mechanism for preventing rerenders. But in Solid, components only mount once and don't rerender so there is no need for an equivalent hook.
SolidJS Benchmark Performance
Solid is also one of the most performant JavaScript libraries. This is evidenced by the results of the JS Framework Benchmark. A large, randomized table of entries is created and modified. Rendering duration is measured along with how long various operations take to complete (lower scores are better).
While admittedly a contrived example, the benchmark allows factoring multiple measurements into a single geometric mean representing comparative performance between frameworks. For a combination of all types of read and write operations, Solid ranks just below vanilla JavaScript:
Framework | Version | Mean |
---|---|---|
Vanilla JS | N/A | 1.00 |
Solid | 1.5.4 | 1.10 |
Lit-html | 1.1.0 | 1.19 |
Vue | 3.2.37 | 1.25 |
Svelte | 3.50.1 | 1.30 |
Preact | 10.7.3 | 1.43 |
Angular | 13.0.0 | 1.58 |
Marko | 4.12.3 | 1.70 |
React | 18.2.0 | 1.73 |
Solid ties vanilla JS and ranks just below Svelte on lighthouse startup metrics:
Framework | Version | Mean |
---|---|---|
Svelte | 3.50.1 | 1.03 |
Solid | 1.5.4 | 1.04 |
Vanilla JS | N/A | 1.04 |
Preact | 10.7.3 | 1.06 |
Lit-html | 1.1.0 | 1.07 |
Marko | 4.12.3 | 1.18 |
Vue | 3.2.37 | 1.27 |
React | 18.2.0 | 1.69 |
Angular | 13.0.0 | 1.77 |
SolidStart Motivations
SolidStart takes influence from other JavaScript metaframeworks including Next.js, Nuxt.js, and SvelteKit by introducing multiple build modes, routing conventions, opinionated project structures, and pre-configured deployment adapters. The framework can produce sites or applications that employ either:
- Static site generation (SSG)
- Client-side rendering (CSR)
- Server-side rendering (SSR)
- Streaming SSR (SSSR)
In the future, you'll also be able to choose:
- Some combination of all the above through route level controls
- Islands through newly created conventions like Hybrid Routing and Minimal Hydration
Create Client Rendered Solid Project
mkdir ajcwebdev-solidstart
cd ajcwebdev-solidstart
pnpm init
pnpm add solid-js @solidjs/meta @solidjs/router solid-start
pnpm add -D solid-start-node vite-plugin-solid vite undici typescript
Add vite
scripts to package.json
and set type
to module
.
{
"name": "ajcwebdev-solidstart",
"version": "1.0.0",
"description": "An example SolidStart application deployed on Netlify, Vercel, and Cloudflare Pages",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"keywords": [ "SolidJS", "SolidStart", "Netlify", "Vercel", "Cloudflare" ],
"author": "Anthony Campolo",
"license": "MIT"
}
Create a .gitignore
file.
echo 'node_modules\n.env\n.DS_Store\ndist\n.solid\nnetlify\n.netlify\n.vercel' > .gitignore
There's only a handful of files needed for a working Solid project. These include a configuration file for Vite (vite.config.ts
), an entry point for our JavaScript application (src/root.tsx
), and an entry point for our HTML page (index.html
).
Run the following commands:
mkdir src
echo > tsconfig.json # TypeScript Configuration
echo > vite.config.ts # Vite Configuration
echo > index.html # HTML entry point where JavaScript app loads
echo > src/root.css # CSS stylesheet
echo > src/root.tsx # Defines the document the app renders
In addition to the required files we also created optional files for CSS styling and TypeScript configuration. Later in the tutorial when we migrate this project to SolidStart, we'll remove the HTML file and replace it with two files, entry-server.tsx
and entry-client.tsx
.
TypeScript and Vite Project Configuration
Copy/paste this impenetrable hunk of gibberish into your tsconfig.json
and say a prayer to Microsoft.
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"jsxImportSource": "solid-js",
"jsx": "preserve",
"types": ["vite/client"],
"baseUrl": "./",
"paths": {
"~/*": ["./src/*"]
}
}
}
The vite.config.ts
file is where we'll add the Solid Plugin to define our Vite Configuration. Import solidPlugin
from vite-plugin-solid
and add it to the plugins
array inside Vite's defineConfig
helper.
// vite.config.ts
import solidPlugin from "vite-plugin-solid"
import { defineConfig } from "vite"
export default defineConfig({
plugins: [solidPlugin()]
})
HTML Entry, CSS Styling, and Render Function
The root Solid component will be imported as an ESM module from /src/root.tsx
and set to the src
attribute.
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="An example SolidJS single-page application." />
<title>A First Look at SolidStart</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="/src/root.tsx" type="module"></script>
</body>
</html>
Include the following CSS styles in src/root.css
.
/* src/root.css */
body {
background-color: #282c34;
color: white;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
margin: 0;
text-align: center;
}
header {
font-size: calc(10px + 2vmin);
margin: 1rem;
}
a {
color: #b318f0;
}
To mount Solid and automatically create a reactive root, import render
from solid-js/web
and pass in two arguments, a top-level component function and an element to mount on:
- The first argument returns the root component and must be passed a function.
- The mounting container is passed for the second argument and wired up to the
root
div.
// src/root.tsx
/* @refresh reload */
import { render } from "solid-js/web"
import "./root.css"
function App() {
return (
<>
<header>
<h1>A First Look at SolidStart</h1>
<a href="https://github.com/solidjs/solid">Learn Solid</a>
</header>
<footer>
<span>
Visit <a href="https://ajcwebdev.com">ajcwebdev.com</a> for more tutorials
</span>
</footer>
</>
)
}
render(
() => <App />, document.getElementById('root') as HTMLElement
)
Start Development Server
pnpm dev # or npm run dev | yarn dev
Open localhost:5173
to view the running application in your browser. The page will reload if you make edits.
At this point, we could build and deploy a dist
folder to any static host provider. Run pnpm build
and pnpm serve
to test serving your bundle on localhost:4173
. Instead of deploying this project, we'll continue to the next section and begin modifying our project to make it work with SolidStart.
Migrate Project to SolidStart
First, delete your existing HTML file and create a routes
directory inside src
.
rm -rf index.html
mkdir src/routes
echo > src/entry-server.tsx # Server entry point
echo > src/entry-client.tsx # Browser entry point
echo > src/routes/index.tsx # Home route
SolidStart Scripts and Vite Configuration
Replace the Vite scripts with the following SolidStart scripts.
{
"scripts": {
"dev": "solid-start dev",
"build": "solid-start build",
"start": "solid-start start"
},
}
Remove solidPlugin
from vite-plugin-solid
and replace it with solid
from solid-start/vite
.
// vite.config.ts
import solid from "solid-start/vite"
import { defineConfig } from "vite"
export default defineConfig({
plugins: [solid()]
})
Index Route, Root, and Entry Points
Copy the App
component from src/root.tsx
and include it in src/routes/index.tsx
with export default
.
// src/routes/index.tsx
export default function App() {
return (
<>
<header>
<h1>A First Look at SolidStart</h1>
<a href="https://github.com/solidjs/solid">Learn Solid</a>
</header>
<footer>
<span>
Visit <a href="https://ajcwebdev.com">ajcwebdev.com</a> for more tutorials
</span>
</footer>
</>
)
}
root.tsx
is the point where your code runs on both the server and client. It exports a Root
component that is shared on the server and browser as an isomorphic entry point to your application. Since SolidStart is designed for file-system routing, routes are defined via a folder structure under the /routes
folder. You can pass them into the <Routes>
component with the <FileRoutes>
component.
This collects routes from the file-system in the /routes
folder to be inserted into a parent <Routes>
component. Since <FileRoutes>
returns a route configuration, it must be placed directly between <Routes>
, typically in the root.tsx
file. <Routes>
is a special Switch
component that renders the correct <Route>
child based on the users' location, and switches between them as the user navigates.
// src/root.tsx
// @refresh reload
import { Suspense } from "solid-js"
import { Body, ErrorBoundary, FileRoutes, Head, Html, Meta, Routes, Scripts, Title } from "solid-start"
import "./root.css"
export default function Root() {
return (
<Html lang="en">
<Head>
<Title>A First Look at SolidStart</Title>
<Meta charset="utf-8" />
<Meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta name="description" content="An example SolidStart application deployed on Netlify, Vercel, and Cloudflare Pages." />
</Head>
<Body>
<ErrorBoundary>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<FileRoutes />
</Routes>
</Suspense>
</ErrorBoundary>
<Scripts />
</Body>
</Html>
)
}
entry-client.tsx
starts the application in the browser by passing <StartClient>
to a mount
function. mount
is an alias over Solid's hydrate
and render
methods. It ensures that the client always starts up properly whether you are using SolidStart for client-only rendering or server-side rendering.
// src/entry-client.tsx
import { mount, StartClient } from "solid-start/entry-client"
mount(() => <StartClient />, document)
entry-server.tsx
starts the application on the server by passing <StartServer>
to a render function called renderAsync
. createHandler
enables a mechanism for introducing middleware into server rendering. <StartServer>
wraps the application root and includes Context providers for Routing and MetaData. It takes the Event
object originating from the underlying runtime and includes information such as the request
, responseHeaders
and status codes.
// src/entry-server.tsx
import { StartServer, createHandler, renderAsync } from "solid-start/entry-server"
export default createHandler(
renderAsync((event) => <StartServer event={event} />)
)
While this example uses renderAsync
, there are three different render functions provided by SolidStart. Each wraps Solid's rendering method and returns a unique output:
-
renderSync
callsrenderToString
to synchronously respond immediately and render the application to a string. -
renderAsync
callsrenderToStringAsync
to asynchronously respond when the page has fully been loaded and render the application to a promise. -
renderStream
callsrenderToStream
to asynchronously respond as soon as it can and render the application to aReadableStream
.
Check that everything still displays as expected.
pnpm dev
Open localhost:3000.
Components and Reactive Primitives
Since this is a tutorial about a frontend framework it will be considered illegitimate until we build a counter. Create a components
directory and then a file called Counter.tsx
inside of it.
mkdir src/components
echo > src/components/Counter.tsx
There are two foundational building blocks at the core of Solid's fine grained reactivity that will enable us to craft this magnificent counter into existence:
-
Components contain stateless DOM elements within functions that accept
props
and return JSX elements. - Reactive Primitives including Signals, Effects, and Memos track and broadcast the changing values that represent the state of the components over time.
In this component we'll create a signal to track the changing value of the counter and an effect to modify the value with button clicks.
Create Signal
Signals contain values that change over time. They are tracked by the framework and update automatically by broadcasting to the rest of the interface. Use createSignal
to initialize a value of 0
and set it to count
. Increment the counter once every second by passing a setCount(count() + 1)
function to a setInterval()
method that executes every 1000 milliseconds.
// src/components/Counter.tsx
import { createSignal } from "solid-js"
export default function Counter() {
const [count, setCount] = createSignal(0)
setInterval(() => setCount(count() + 1), 1000)
return (
<>The count is now: {count()}</>
)
}
Inside src/routes/index.tsx
, import Counter
from ../components/Counter
. Return a <Counter />
component in the return function of the App
component.
// src/routes/index.tsx
import Counter from "../components/Counter"
export default function App() {
return (
<>
<header>
<h1>A First Look at SolidStart</h1>
<a href="https://github.com/solidjs/solid">Learn Solid</a>
</header>
<main>
<Counter />
</main>
<footer>
<span>
Visit <a href="https://ajcwebdev.com">ajcwebdev.com</a> for more tutorials
</span>
</footer>
</>
)
}
Create Effect
An Effect is an example of an observer that runs a side effect depending on a signal. createEffect
creates a new computation (for example to modify the DOM manually) and runs the given function in a tracking scope.
// src/components/Counter.tsx
import { createSignal, createEffect } from "solid-js"
export default function Counter() {
const [count, setCount] = createSignal(0)
createEffect(() => count())
return (
<>
<button onClick={() => setCount(count() + 1)}>
Click Me
</button>
<div>The count is now: {count()}</div>
</>
)
}
This automatically tracks the dependencies and reruns the function whenever the dependencies update.
Create Route Data
Create a new file called students.tsx
inside the src/routes
directory. This will contain a third party API call to return a list of Harry Potter characters.
echo > src/routes/students.tsx
createRouteData
is a wrapper over createResource
for handling async data fetching and refetching. With SolidStart's file system routing, components defined under /routes
can utilize a routeData
function which executes when navigation to that component begins. This hook returns the JSON parsed data from the loader function. We'll use the Fetch API to query Harry Potter information on Deno Deploy.
// src/routes/students.tsx
import { useRouteData, createRouteData } from "solid-start"
type Student = { name: string; }
export function routeData() {
return createRouteData(async () => {
const response = await fetch("https://hogwarts.deno.dev/students")
return (await response.json()) as Student[]
})
}
export default function Page() { }
This routeData
function can be thought of like a "loader" function (what a brilliant idea, amazing no one thought of it before) which includes a useRouteData
hook to access the returned data.
// src/routes/students.tsx
import { useRouteData, createRouteData } from "solid-start"
type Student = { name: string; }
export function routeData() {
return createRouteData(async () => {
const response = await fetch("https://hogwarts.deno.dev/students")
return (await response.json()) as Student[]
})
}
export default function Page() {
const students = useRouteData<typeof routeData>()
return (
<>
<header>
<h1>Students</h1>
</header>
<main>
<code>{JSON.stringify(students(), null, 2)}</code>
</main>
</>
)
}
useRouteData
can use whatever data is returned from the routeData
loader function.
The <For>
component loops over an array of objects. The <For>
component has only one prop, each
, which is passed an array to loop over with a callback similar to JavaScript's map callback.
// src/routes/students.tsx
import { useRouteData, createRouteData } from "solid-start"
import { For } from "solid-js"
type Student = { name: string; }
export function routeData() {
return createRouteData(async () => {
const response = await fetch("https://hogwarts.deno.dev/students")
return (await response.json()) as Student[]
})
}
export default function Page() {
const students = useRouteData<typeof routeData>()
return (
<>
<header>
<h1>Students</h1>
</header>
<main>
<For each={students()}>
{student => <li>{student.name}</li>}
</For>
</main>
</>
)
}
API Routes
API routes are similar to other routes except instead of exporting a default Solid component with a routeData
function, they export functions that are named after the HTTP methods they handle such as GET
or POST
.
mkdir src/routes/api
echo > src/routes/api/index.ts
json
is a helper function to send JSON HTTP responses. Return a JSON object with the key set to hello
and the value set to world
.
// src/routes/api/index.ts
import { json } from "solid-start"
export function GET() {
return json(
{ hello: "world" }
)
}
Open 127.0.0.1:3000/api or make a request with cURL.
curl http://127.0.0.1:3000/api
{"hello":"world"}
Deployment Adapters
Here is the directory and file structure for the final project before including any files related to deployment:
.
├── src
│ ├── components
│ │ └── Counter.tsx
│ ├── routes
│ │ ├── api
│ │ │ └── index.ts
│ │ ├── index.tsx
│ │ └── students.tsx
│ ├── entry-client.tsx
│ ├── entry-server.tsx
│ ├── root.css
│ └── root.tsx
├── package.json
├── tsconfig.json
└── vite.config.ts
Push your project to a GitHub repository.
git init
git add .
git commit -m "mr solid"
gh repo create ajcwebdev-solidstart \
--description="An example SolidJS application deployed on Netlify, Vercel, and Cloudflare Pages." \
--remote=upstream \
--source=. \
--public \
--push
If you only want to use a single deployment platform, select one of the next three options and push the changes to the main branch. I will deploy the project to all three by creating a different branch for each and specifying the correct branch on the deployment platform.
Deploy to Netlify
Import the netlify
adapter from solid-start-netlify
.
// vite.config.ts
// @ts-ignore
import netlify from "solid-start-netlify"
import solid from "solid-start/vite"
import { defineConfig } from "vite"
export default defineConfig({
plugins: [solid({
adapter: netlify({ edge: true })
})]
})
Install solid-start-netlify
and the Netlify CLI.
pnpm add -D solid-start-netlify netlify-cli @types/node
Create a netlify.toml
file for the build instructions.
echo > netlify.toml
Set the command
to pnpm build
and the publish
directory to netlify
.
# netlify.toml
[build]
command = "pnpm build"
publish = "netlify"
Connect the repository to your Netlify account through the Netlify dashboard or use the following commands with the Netlify CLI.
pnpm ntl login
pnpm ntl init
The build commands will be automatically entered from the netlify.toml
file.
pnpm ntl deploy --prod --build
Open ajcwebdev-solidstart.netlify.app to see a running example.
Deploy to Vercel
Install solid-start-vercel
and the Vercel CLI.
pnpm add -D solid-start-vercel vercel
Import the vercel
adapter from solid-start-vercel
.
// vite.config.ts
// @ts-ignore
import vercel from "solid-start-vercel"
import solid from "solid-start/vite"
import { defineConfig } from "vite"
export default defineConfig({
plugins: [solid({
adapter: vercel({ edge: true })
})]
})
Deploy the project with the Vercel CLI.
pnpm vercel --yes --prod
Open ajcwebdev-solidstart.vercel.app.
Deploy to Cloudflare
SolidStart includes two adapters for Cloudflare, one for Cloudflare Workers and another for Cloudflare Pages. It's important to note that the Cloudflare Pages adapter is also using Workers through Pages Functions. Install solid-start-cloudflare-pages
and the wrangler
CLI.
pnpm add -D solid-start-cloudflare-pages wrangler
Import the cloudflare
adapter from solid-start-cloudflare-pages
.
// vite.config.ts
// @ts-ignore
import cloudflare from "solid-start-cloudflare-pages"
import solid from "solid-start/vite"
import { defineConfig } from "vite"
export default defineConfig({
plugins: [solid({
adapter: cloudflare({})
})],
})
Build the project's assets and run a local Worker emulation on localhost:8788 with wrangler pages dev
.
pnpm wrangler login
pnpm build
pnpm wrangler pages dev ./dist/public
Create a project with wrangler pages project create
and deploy the project with wrangler pages publish
.
pnpm wrangler pages project create ajcwebdev-solidstart \
--production-branch production
pnpm wrangler pages publish dist/public \
--project-name=ajcwebdev-solidstart \
--branch=production
Top comments (21)
In case anybody is wondering, the
routeData(args: RouteDataArgs)
(RouteDataFuncArgs
insolid-router
) is passed an argument containing the routing information.SolidStart: Fetching data with a key
Thank you for the reference, this part of Solid Start in particular is just straight up magic to me right now 🪄.
Most of the information is with solid-router.
The file routes handle the route configuration implicitly which is where the magic comes from.
solid-router
data functions are the equivalent to SolidStart'srouteData()
function.The route data function is passed the routing information so that it can obtain any additional information that is needed for the page (component). The page obtains the information that was prepared by the route data function via the
useRouteData
function.It took me some time to figure out this situation:
src/routes/users/index.tsx
defines the content for the/users
route butsrc/routes/users.tsx
defines the layout that will be used for that content and the content is projected via the<Outlet>
component. (Nested Routes).Note that
src/routes/users.tsx
itself is projected via the<FileRoutes>
component inroot.tsx
.However given:
root.tsx
acts as the layout for the/
route and the content is projected via the<FileRoutes>
component.If you are interested some examples can be found in here:
peerreynders / solid-start-notes-basic
Basic client rendered notes app using SolidStart beta
SolidStart Notes (basic)
Overview
First exploration of SolidStart (beta 0.2.6). The app is a port of the December 2020 React Server Components Demo (LICENSE; no pg fork) but here it's just a basic client side routing implementation. It doesn't use a database but just holds the notes in server memory synchronized to the
notes-db.json
file. This app is not intended to be deployed but simply serves as an experimental platform.The longer term goal is to eventually leverage island routing to maximum effect once it's more stable and documented (nksaraf already demonstrated that capability (live demo) with a non-standard branch of SolidStart).
a first deep long stare at solidstart* (thank you :))
Thank you 🙏, I try to be thorough.
yet another JavaScript framework with compare table, yaaay!
Ha, if there's not a table is it even a real benchmark?
Love to see that I'm not the only one that has an interest in solid start! Nice article :)
Yeah I've been watching Solid closely for at least a year and was patiently awaiting the release of Solid Start. The community is really starting to pick up steam.
Thank You! For This Type Of Nice articles :)
Thanks for reading!
Very nice article! The Form stuff is super cool tooo maybe you should add a bit about it in the post
Yeah I always struggle with deciding how much to include before an article just becomes totally ridiculous in length. I'm thinking I'll have a follow up article that will include both tRPC and forms/mutations.
I think the already included
createServerData$
,createServerAction$
and API Routes delay the need to reach for solutions like tRPC.Not to mention islands + islandsrouter that can provide "server-component-like" functionality (experimental source, demo).
Interesting, will those provide end-to-end typesafety?
I was getting the impression that the TS settings are still pretty loose right now as SolidStart is still in beta.
But IIRC from the Theo stream the intention is to make it typesafe (can't be sure though).
Cool cool, thanks for the insights! Honestly, my desire to integrate tRPC has less to do with any actual technical reasons and more to do with following along with my tried-and-true Hype Based Development strategy 😆.
Right, which is why it's included in the SolidStart docs.
However, in my view tRPC is a solution that largely fits the React/Next.js space or perhaps between node applications and only really makes sense when the same team is in charge of both ends anyway (background: A Brief History of Distributed Programming: RPC; also in the long term React Server Components (once fully supported) may lessen the need for tRPC).
But SolidStart already has baked in solutions for server/client communication that should fit most use cases.
tRPC would likely only come into play if the server already existed prior to using SolidStart and if islandsrouter is used that interaction could move to the server anyway as the client may only need HTML updates.
React performance pretty atrocious in these 2 tests, especially compared to Vue, while React makes you work harder (makes you jump through a lot of hoops with useMemo and whatnot, putting the burden on the programmer to manually optimize re-renders) ... Vue takes care of more stuff for you, with a smaller bundle size!
The only thing that React has going for it is that it's dominant in the marketplace, the proverbial 900 pound gorilla, but it's not the smartest ape in the family :-P
Not sure how you came away from this article thinking that Vue is the solution to React's performance problems (instead of maybe, I dunno, Solid) but I commend your ability to arrive at whatever conclusion you want.