Home

Awesome

<img src="https://raw.githubusercontent.com/hviana/faster_react_core/refs/heads/main/docs/programmer-man.gif" width="125">

πŸš€ faster_react

[!IMPORTANT]
Please give a star! ⭐


🌟 Introduction

faster_react is a tiny Full-Stack React framework. He avoids Overengineering. This framework uses its own RSC engine, combining SSR and CSR, and automatically generates routes for React components. To utilize this, you must use the routes helper provided by the framework (React Router). The framework's configuration file is located at options.json.

🎯 What Does faster_react Do for You?

Focus solely on development! This framework handles:

Note: The project includes a simple application example demonstrating each functionality. The example uses Tailwind CSS, but this is optional. You can use whatever CSS framework you want.


⚑ About Faster

This framework uses a middleware library called Faster. Faster is an optimized middleware server with an incredibly small codebase (~300 lines), built on top of native HTTP APIs with no dependencies. It includes a collection of useful middlewares:

Fully compatible with Deno Deploy and other enviroments. Examples of all resources are available in the README. Faster's ideology is simple: all you need is an optimized middleware manager; all other functionality is middleware.


πŸ“š Contents


⚑ Benchmarks

faster_react has only 0.9% of the code quantity of Deno Fresh.

Benchmark Command:

# Deno Fresh
git clone https://github.com/denoland/fresh.git
cd fresh
git ls-files | xargs wc -l
# Output: 104132 (version 1.7.3)

# faster_react
git clone https://github.com/hviana/faster_react.git
cd faster_react
git ls-files | xargs wc -l
# Output: 1037 (version 20.1)

πŸ—οΈ Architecture

This framework utilizes Headless Architecture [1] to build the application, combined with the Middleware Design Pattern [2] for defining API routes in the backend.

Architecture Diagram


πŸ“‚ App Structure

All application folders are inside the app folder.

πŸ“¦ Get Deno Kv and Deno Kv Fs

On the backend, if a Deno KV instance is available, access instances via Server.kv and Server.kvFs:

import { Server } from "faster";

See Deno KV settings in options.json.

More details: deno_kv_fs


πŸ“ Backend API


🧩 Backend Components


πŸ“ Backend Files


πŸ–₯️ Frontend Components


🎨 Frontend CSS

Application CSS style files.


πŸ“œ Frontend Files


🌎 Frontend Translations

In frontend/components/index.tsx:

import {
  detectedLang,
  useTranslation,
} from "@helpers/frontend/translations.ts";
const Home = () => {
  const t = useTranslation();
  //Any .init parameter of i18next (minus ns) is valid in useTranslation.
  //Ex: useTranslation({ lng: ["es"], fallbackLng: "en" }) etc.
  //On the client side, the language is automatically detected (if you don't specify).
  //On the server, the language is "en" (if you don't specify).
  //The "en" is also the default fallbackLng.
  return (
    <div className="app-name">
      {t("index.appName", { endExample: "!" })}
    </div>
  );
};
export default Home;

In frontend/translations/en/index.json:

{
  "appName": "My SaaS App {{endExample}}"
}

The framework translation is just a wrapper over i18next. See the i18next documentation if you have questions.


πŸ—‚οΈ Static

Files served statically. Routes are generated based on the folder and file structure.


🧭 React Router

Since the framework has its own routing system, a third-party routing library is unnecessary. Use the framework helper:

Note: Direct form submissions for page routes path also work.

import { getJSON, route } from "@helpers/frontend/route.ts";

Interface Parameters:

interface Route {
  headers?: Record<string, string>; // When routing to a page, headers are encoded in the URL. Intercept them in ctx.url.searchParams in a backend/components file.
  content?:
    | Record<any, any>
    | (() => Record<any, any> | Promise<Record<any, any>>);
  path: string;
  startLoad?: () => void | Promise<void>;
  endLoad?: () => void | Promise<void>;
  onError?: (e: Error) => void | Promise<void>;
  disableSSR?: boolean; //For component routes. Disables SSR; defaults to false.
  elSelector?: string; // Required for component routes.
  method?: string; // Only for API routes. Optional; defaults to GET or POST.
}

Examples

Navigating to a Page with Search Params:

// URL search params passed as properties to the page. Props receive `{a:1}`
<button onClick={route({ path: "/pages/test?a=1" })}>
  Go to Test Page
</button>;

Passing Additional Parameters:

// Props receive `{a:1, example:"exampleStr"}`
<button
  onClick={route({
    path: "/pages/test?a=1",
    content: { example: "exampleStr" },
  })}
>
  Go to Test Page with Extra Data
</button>;

Using Asynchronous Content:

// Props receive `{a:1, ...JSONResponse}`
<button
  onClick={route({
    path: "/pages/test?a=1",
    content: async () => {
      return await getJSON({
        path: "/example/json",
        content: {
          test: "testData",
        },
      });
    },
  })}
>
  Go to Test Page with Async Data
</button>;

Programmatic Routing:

(async () => {
  if (user.loggedIn) {
    await route({
      path: "/pages/dash",
      content: { userId: user.id, token: token },
    })();
  } else {
    await route({ path: "/pages/users/login" })();
  }
})();

Loading a Component:

<button
  onClick={route({
    path: "/components/parts/counter",
    elSelector: "#counter",
  })}
>
  Load Counter Component
</button>;

Making an API Call:

<button
  onClick={async () => {
    const res = await getJSON({
      path: "/example/json",
      content: {
        test: "testData",
      },
    });
    console.log(res);
    alert(JSON.stringify(res));
  }}
>
  Fetch JSON Data
</button>;

In the case of page routes, you can use this example to pass the URL parameters for the headers in the backend (if you really need it):

const signupBackendComponent: BackendComponent = {
  before: [
    async (ctx: Context, next: NextFunc) => {
      ctx.req = new Request(ctx.req, {
        headers: {
          ...Object.fromEntries(ctx.req.headers as any),
          "Authorization": `Bearer token ${ctx.url.searchParams.get("token")}`,
        },
      });
      await next();
    },
  ],
};
export default signupBackendComponent;

Forms submit for page routes work. For components, you can use the following:

<form
  method="POST"
  action=""
  encType="multipart/form-data"
  onSubmit={async (event) => {
      event.preventDefault();
      const data: any = new FormData(event.target as any);
      const formObject = Object.fromEntries(data.entries());
      await route({
        startLoad: () => setLoading(true), //useState
        endLoad: () => setLoading(false),
        path: "/components/register",
        elSelector: "#dash-content",
        content: formObject,
      })();
  }}
>

πŸ“¦ Packages Included

Several packages are included to assist in developing React applications. Here are some examples of imports you can use without additional configuration:

import {/* your imports */} from "react";
import {/* your imports */} from "react/";
import {/* your imports */} from "i18next";
import {/* your imports */} from "react-dom";
import {/* your imports */} from "react-dom/server";
import {/* your imports */} from "react-dom/client";
import {/* your imports */} from "react/jsx-runtime";
s;
import {/* your imports */} from "@helpers/frontend/route.ts";
import {/* your imports */} from "@helpers/frontend/translations.ts";
import {/* your imports */} from "@helpers/backend/types.ts";
import {/* your imports */} from "faster";
import {/* your imports */} from "deno_kv_fs";
import {/* your imports */} from "jose"; //manage tokens
import { options, server } from "@core"; // Useful for accessing the server instance.

πŸ› οΈ Creating a Project

You can simply download this repository. Alternatively, use the command (requires git installed and configured):

deno run -A -r "https://deno.land/x/faster_react_core/new.ts" myProjectFolder

Customize and configure the server in options.json.


πŸš€ Running a Project

Execute the command:

Development:

deno task serve

Production:

deno serve main.ts #Add your permissions, port, certificate etc. see: https://docs.deno.com/runtime/reference/cli/serve

🌐 Deploy

Note: For production, set framework => "dev": false in options.json.


πŸ“– References

<a id="1">[1]</a> Dragana Markovic, Milic Scekic, Alessio Bucaioni, and Antonio Cicchetti. 2022. Could Jamstack Be the Future of Web Applications Architecture? An Empirical Study. In Proceedings of the 37th ACM/SIGAPP Symposium on Applied Computing (SAC '22). Association for Computing Machinery, New York, NY, USA, 1872–1881. DOI: 10.1145/3477314.3506991

<a id="2">[2]</a> Brown, Ethan. Web Development with Node and Express: Leveraging the JavaScript Stack. O'Reilly Media, 2019. URL: http://www.oreilly.com/catalog/9781492053484


πŸ‘¨β€πŸ’» About

Author: Henrique Emanoel Viana, a Brazilian computer scientist and web technology enthusiast.

Improvements and suggestions are welcome!