0.1.27 • Published 5 months ago

realight v0.1.27

Weekly downloads
-
License
MIT
Repository
github
Last release
5 months ago

Realight

Really small react framwork for Bun to fetch data and mutate them easily, inspired by Remix api's

Can only be used for toy projects and is really far from being production ready (it will never be!).

Getting started

Installation

bun i realight

You first route

Realight is based on the file system router that Bun provides which is itself based on the Nextjs Page router.

First create a views folder which will contain all the routes, then create a home.tsx file. It will create the /home url.

In each view you have to export a default react component, for example:

export default function View() {
  return <p>My first route !</p>;
}

APIs

Loading data

Realight uses the same api than remix to fetch data by asking you to write a special async function in the same file as your view:

export async function query() {
    const data = await fetch("https://jsonplaceholder.typicode.com/todos")
    const todos = await data.json() as Array<Record<string, unknown>>
    return {
        title: "Arbitrary data",
        todos,
    };
}

From which you can retrieve the content in your view using a special hook: useQueryData

import {useQueryData} from "realight"

export async function query() {
    const data = await fetch("https://jsonplaceholder.typicode.com/todos")
    const todos = await data.json() as Array<Record<string, unknown>>
    return {
        title: "Arbitrary data",
        todos,
    };
}

export default function View() {
    const {title, todos} = useQueryData<typeof query>()
    return (
        <article>
            <h1>{title}</h1>
            <ul>
                {todos?.map(todo => {
                    <li key={todo.id}>{todo.title}</li>
                })}
            </ul>
        </article>
    )
}

Mutate data

To mutate data you have to use the useForm hook that returns a Form component and a state react state.

import { useForm } from "realight";

export default function View() {
  const form = useForm(); // or const {Form, state} = useForm()
  return (
    <form.Form method="POST">
      <input type="email" name="email " />
      <button type="submit">
        {form.state === "submitting"
          ? "loading"
          : "Subscribe to the newsletter !"}
      </button>
    </form.Form>
  );
}

To retrieve the form data you can export an async mutate function:

import { useForm } from "realight";
import { fakeDb } from "fake-db-service";

export default function View() {
  const form = useForm(); // or const {Form, state} = useForm()
  return (
    <form.Form method="POST">
      <input type="email" name="email " />
      <button type="submit">
        {form.state === "submitting"
          ? "loading"
          : "Subscribe to the newsletter !"}
      </button>
    </form.Form>
  );
}

export async function mutate({ req }: { req: Request }) {
  const formData = req.formData;
  const success = await fakeDb.add({
    email: formData.get("email"),
  });
  return JsonResponse({ success });
}

Retrieve the result

If you need to retrieve the result of the mutate function in your view you can use the useMutationData.

import {useForm, useMutationData} from "realight"
import {fakeDb} from "fake-db-service"

export default function View() {
    const form = useForm()
    const {success} = useMutationData<typeof mutate>()
    return (
        <>
            <form.Form method="POST">
                <input type="email" name="email " />
                <button type="submit">
                    {form.state === "submitting" ? "loading" : "Subscribe to the newsletter !"}
                </button>
            </form.Form>
            <p>{success ? "Thank you !" : null}</p>
        </>
    )
}

export async function mutate({ req }: { req: Request }) {
    const formData = req.formData
    const success = await fakeDb.add({
        email: formData.get("email")
    })
    return JsonResponse({success});
}

Revalidation

When you update some data in the mutate function, Realight automaticcaly re-run the query and show the updated data right after the mutation is done without you having to do anything.

import {useForm, useMutationData, useQueryData} from "realight"
import {fakeDb} from "fake-db-service"

export default function View() {
    const form = useForm()
    const {emails} = useQueryData<typeof query>()
    return (
        <>
            {emails?.map(email => (
                <form.Form method="POST">
                    <input type="hidden" name="id" value={email.id}>
                    <input type="email" name="email" value={email.email} />
                    <button type="submit">
                        {form.state === "submitting" ? "loading" : "Update email"}
                    </button>
                </form.Form>
            )}
        </>
    )
}

export async function query() {
    const emails = await fakeDb.get("emails")
    return {emails};
}

export async function mutate({ req }: { req: Request }) {
    const formData = req.formData
    const success = await fakeDb.update(formData.get("id"), {
        email: formData.get("email")
    })
    return JsonResponse({success});
}

It allows the view to always be in sync with the data.

If you want not to refetch anything to avoid unnecessary request, you can use the revalidate option:

export async function mutate({ req }: { req: Request }) {
    const formData = req.formData
    const success = await fakeDb.update(formData.get("id"), {
        email: formData.get("email")
    })
    return JsonResponse({success}, {revalidate: false});
}

Redirect

If you want to redirect to a new url after the mutation you can use RedirectResponse:

export async function mutate({ req }: { req: Request }) {
    const formData = req.formData
    const success = await fakeDb.update(formData.get("id"), {
        email: formData.get("email")
    })
    return RedirectResponse("/home");
}

Meta data

If you want to change the title description and favicon you can export a meta const from your view:

import type {Meta} from "realight"

export const meta: Meta = {
    title: "My blog"
    description: "The description of my blog"
    icon: "favicon.png"
}

The favicon will be searched in the public folder. If you want to customize your title and description based on the query data you can export a function instead which will have the data passed as an argument:

import type { Meta } from "realight";

export const meta: Meta<typeof query> = (data) => {
  title: data.meta.title;
  description: data.meta.description;
  icon: "favicon.png";
};

Database

If you want to store data in a database you can use the realight/db package that exposes a bun sqlite database. You can also use the native bun sqlite db but you'll have to import it dynamically in either the query or mutate function. Using the realight/db you'll be able to import it from the top.

Middlewares

If you want to execute something at each request you can create a middleware.ts file in your src folder. This file should export a default function of type MiddlewareType:

// src/middleware.ts
import { RedirectResponse, type RequestType } from "realight";

const middleware: MiddlewareType = ({request, params, searchParams}) => {
    if (Math.random() > 0.5) {
        return RedirectResponse("https://example.com")
    }
}

export default middleware

Bootstrap scripts

If you want to execute something before the server starts you can create a bootstrap.ts file in your src folder. This file should export a default function of type BootstrapType:

// src/bootstrap.ts
import createDb from "super-db"

export default () => {
    createDb()
}
0.1.27

5 months ago

0.1.26

5 months ago

0.1.25

5 months ago

0.1.24

5 months ago

0.1.23

6 months ago

0.1.22

6 months ago

0.1.21

6 months ago

0.1.20

6 months ago

0.1.19

6 months ago

0.1.18

6 months ago

0.1.17

6 months ago

0.1.16

6 months ago

0.1.15

6 months ago

0.1.14

6 months ago

0.1.13

6 months ago

0.1.12

6 months ago

0.1.11

6 months ago

0.1.10

6 months ago

0.1.9

6 months ago

0.1.8

6 months ago

0.1.7

6 months ago

0.1.6

6 months ago

0.1.5

6 months ago

0.1.4

6 months ago

0.1.3

6 months ago

0.1.2

6 months ago

0.1.1

6 months ago

0.1.0

6 months ago

0.0.41

6 months ago

0.0.40

6 months ago

0.0.39

6 months ago

0.0.38

6 months ago

0.0.37

6 months ago

0.0.36

6 months ago

0.0.35

6 months ago

0.0.34

6 months ago

0.0.33

6 months ago

0.0.32

6 months ago

0.0.31

6 months ago

0.0.30

6 months ago

0.0.29

6 months ago

0.0.28

6 months ago

0.0.27

6 months ago

0.0.26

6 months ago

0.0.25

6 months ago

0.0.24

6 months ago

0.0.23

6 months ago

0.0.22

6 months ago

0.0.21

6 months ago

0.0.20

6 months ago

0.0.19

6 months ago

0.0.18

6 months ago

0.0.17

6 months ago

0.0.16

6 months ago

0.0.15

6 months ago

0.0.14

6 months ago

0.0.13

6 months ago

0.0.12

6 months ago

0.0.11

6 months ago

0.0.10

6 months ago

0.0.9

6 months ago

0.0.8

6 months ago

0.0.7

6 months ago

0.0.6

6 months ago

0.0.5

6 months ago

0.0.4

6 months ago

0.0.3

6 months ago

0.0.2

6 months ago

0.0.1

6 months ago