Rakkas 0.6: React 18, API-less data fetching, and more

Fatih Aygün
July 4, 2022

💃 Rakkas, the bleeding edge React framework powered by Vite, has just released version 0.6.0. First release since December, this is the largest and least backward compatible update so far. But we believe the quantity and the quality of the new features justify the number of breaking changes. See if you agree.

React 18

Rakkas 0.6 was redesigned from the ground up to be compatible with React 18. It supports the new Concurrent Mode, Streaming SSR, and Suspense for data fetching.

Streaming SSR means that Rakkas apps, when doing server-side rendering (SSR), now send chunks of a page's HTML as soon as they are available instead of waiting until everything is fully rendered. This way, the user starts seeing meaningful content as soon as possible instead of waiting in front of a blank screen. Streaming SSR integrates seamlessly with Suspense and the new data fetching system we'll describe below.

If you're worried about streaming SSR interfering with SEO, you'll be relieved to know that Rakkas also implements dynamic rendering: It sends fully rendered pages with correct status codes, HTTP headers, and head tags to search bots while streaming HTML to normal browsers. In any case, you can opt out of streaming on a global, per-route, or per-request basis without giving up Suspense-based data fetching.

New data fetching system

Instead of the page-centric data fetching functions that ran before the page was rendered (“fetch-then-render”), Rakkas 0.6 adopts a Suspense-based data fetching system (“render-as-you-fetch“). The new system comes in the form of useQuery and useMutation hooks that implement a Suspense-only subset of the react-query API.

API-less data fetching

If you're familiar with Next.js, you know how cool getServerSideProps is. With it, you can put, say, your database access code right next to your page component without worrying about implementing and maintaining a REST/GraphQL/RPC/whatever API. Next.js cleverly strips this function and its imports from the client bundle. During SSR, it's called directly. On the client, Next sends a request to the server instead of calling the function.

We believe we've one-upped the ease of use of this data fetching method. Enter useServerSideQuery:

import db from "./my-db-access-lib";

export default function UserCard(props) {
  const userName = props.userName;

  const userQuery = useServerSideQuery(() => {
    if (typeof userName !== "string") {
      // This is server-side code,
      // always validate user input!
      throw new Error("Invalid request");
    }

    return db.user.findOne(userName);
  });

  return (
    <div class="card">
      <img src={userQuery.data.image} />
      <caption>{userQuery.data.fullName}</caption>
    </div>
  );
}

This isn't a page, just an ordinary React component that you can use on many pages. In Rakkas 0.6 pages aren't very special in terms of data fetching anymore. Just like getServerSideProps, the function passed to useServerSideQuery (useSSQ for short) always runs on the server: On the client, a request is sent to the server instead of calling the function directly. Rakkas performs a code transform similar to Next's to strip the function and its imports from the client bundle.

useSSQ's return type is inferred, so, if you're using TypeScript, you get IDE completion just like you would with a local function call. Another nice feature is that, unlike other similar data fetching hooks, useSSQ doesn't return loading or error states. Those are handled higher up in the component tree, with Suspense fallbacks and error boundaries respectively. This way, your component code stays clean and focused.

One practical application of useSSQ that may not be immediately obvious is circumventing CORS restrictions when calling third-party APIs:

const result = useServerSideQuery(() =>
  fetch("https://some.cors.restricted.api.example.com").then((res) =>
    res.json(),
  ),
);

This works because the fetch call inside useServerSideQuery runs on the server-side (Rakkas makes fetch globally available on all deployment targets) and, as such, is not affected by CORS restrictions. In effect, it creates an ad-hoc CORS proxy.

Paired with Remix-inspired action handlers or useServerSideMutation, useSSQ lets you write code as if the server-client barrier didn't exist. But, of course, API routes are still available to allow you to implement REST, GraphQL, RPC etc. endpoints that you can access via useQuery and useMutation or other methods if you prefer to stick with traditional data fetching.

Avoiding waterfalls

Even though we said that in Rakkas 0.6 pages and layouts are not very special in terms of data fetching anymore, you can still have a preload function to start fetching early. preload functions of a page and its parent layouts all run in parallel to avoid late discovery of data dependencies and waterfalls. preload also provides a way to inject SEO-critical title and meta tags into the page even when streaming.

Other new features

Rakkas 0.6 is now built on HatTip, an HTTP server library that abstracts away the differences between various JavaScript runtimes building on the web standards like Request, Response, and streams. Rakkas already ran on Node, Vercel Serverless Functions, Netlify Functions, and Cloudflare Workers. HatTip integration adds support for Vercel Edge, and Netlify Edge. There's also preliminary support for Deno (including Deno Deploy). Bun support is work in progress.

HatTip also makes it possible to integrate with Express or other Connect-compatible Node.js server frameworks: Now you can use Express middleware and routes in your Rakkas app or build your app as an Express middleware to be used in other Express apps.

The new route guards feature allows you to do things like making some routes available to logged-in users only. Catch-all routes and better 404 handling are also among the new features.

Conclusion

If this is the first time you hear of Rakkas, it has other cool features like a lightning-fast development server (courtesy of Vite), file system routing, nested layouts, static site generation, and more.

Rakkas uses experimental and/or beta features of React and Vite. As such, expect breaking changes until we hit 1.0. But go ahead and give it a try and share your thoughts. Star us on Github, join our Discord server, and follow me on Twitter for updates.

If you have any questions, problems, or suggestions open a Github issue. If you want to contribute, fork and send a pull request. Check out the open issues to see how you can help. As always, all feedback is welcome.