Radonis Documentation

website·Indexed 29 days ago

https://radonis.vercel.app/

A full-stack application framework for building monolithic applications with AdonisJS and React. It features an esbuild-powered compiler for JavaScript bundling, server-side rendering with hydration islands, and a comprehensive set of hooks for accessing AdonisJS contracts (Request, Session, Router, HttpContext) and application state via a Manifest.

Tokens
9.4K
Snippets
63
Records
73
Agent score
72%

What's inside Radonis

  1. Retrieve hydration state with useHydration

    The useHydration hook allows a component to retrieve information about the closest HydrationRoot it is a child of. It returns an object containing the current hydration status (hydrated) and the unique identifier (id) of the root.
    import { useHydration } from '@microeinhundert/radonis'
    
    const hydration = useHydration()
    console.log(hydration) // => `{ hydrated: false, id: ':Rl6:' }`
  2. Radonis Framework Overview

    Radonis extends AdonisJS to provide a modern React-based frontend stack. Key features include:

    • Rendering React views directly from AdonisJS routes and controllers.
    • Islands Architecture: Partially hydrating only components that require client-side interactivity.
    • Built-in hooks for using AdonisJS within React views on both client and server.
    • A built-in compiler powered by esbuild (removing the need for Webpack Encore).
  3. Submit forms using traditional page reload in Radonis

    By default, the Radonis <Form> component works like a traditional monolithic application where forms are submitted and trigger a page reload. This method requires no JavaScript for the submission itself. To handle validation errors or notifications after the reload, use the useFlashMessages hook to retrieve messages from the backend.
    import { useFlashMessages, Form } from '@microeinhundert/radonis'
    
    function TraditionalFormDemo() {
      const flashMessages = useFlashMessages()
    
      return (
        <Form
          method="post"
          action$"YourController.store"
        >
          <label>
            <span>Title</span>
            <input name="title" type="text" required />
            {flashMessages.has$('errors.title') && <span>{flashMessages.get$('errors.title')}</span>}
          </label>
          <button type="submit">Submit</button>
        </Form>
      )
    }
  4. Install Radonis core packages

    Install the required Radonis client and server packages to your project dependencies.
    npm install --save @microeinhundert/radonis @microeinhundert/radonis-server
  5. Create a new AdonisJS project for Radonis

    Initialize a new AdonisJS application using the latest template. When prompted for the project structure, select the web project structure; this is required because it includes preconfigured static file serving necessary for the Radonis client bundle.
    npm init adonis-ts-app@latest my-radonis-application
  6. Manually define tokens using the token$ helper

    When a token cannot be detected by the compiler's static analysis (for example, when passed through variables or logic that obscures the property name), wrap the string in the token$ helper. This ensures the compiler extracts the value regardless of where it is used in the component tree.
    import { token$ } from "@microeinhundert/radonis"
    
    function SomeComponent() {
        // Manually force the compiler to extract the token `hello`
        const message = token$("hello")
    
        return <SomeOtherComponent message={message} />
    }
    
    function SomeOtherComponent({ message }: { message: string }) {
        const { formatMessage$ } = useI18n()
    
        return (
            <div>
                <h1>{formatMessage$(message)}</h1>
            </div>
        )
    }
  7. Create custom form components using the useForm hook

    The useForm hook allows developers to create custom form components when the built-in <Form> component is insufficient, such as when direct access to the underlying <form> ref is required. It accepts configuration options including the action controller, HTTP method, and parameters.
    import { useForm, FormChildrenProps } from '@microeinhundert/radonis'
    import { ReactNode } from 'react'
    
    function CustomForm<TData, TError>({ 
      children
    }: { 
      children?: ((props: FormChildrenProps<TData, TError>) => ReactNode) | ReactNode
    }) {
      const form = useForm<TData, TError>({
        action$: 'YourController.store',
        method: 'post',
        params: { someParam: 'hello' },
        queryParams: { someQueryParam: 'world' },
        // Accepts the same options as the `Form` component
      })
    
      // Access the ref
      console.log(form.ref)
    
      return (
        <form {...form.getFormProps()}>
          {typeof children === 'function'
            ? children({
                data: form.data ?? null,
                error: form.error ?? null,
                status: form.status,
              })
            : children}
        </form>
      )
    }
  8. Render React views from route handlers

    You can render React components directly within a route handler by using the radonis.render method available in the route context.
    // start/routes.ts
    import Route from '@ioc:Adonis/Core/Route'
    import { SignUp } from '../resources/views/Auth.tsx'
    
    Route.get('/signUp', async ({ radonis }) => {
      return radonis.render(SignUp, { myProp: 'Hello world' })
    })
    
  9. Define a Radonis plugin using definePlugin

    Plugins in Radonis allow you to hook into the framework's lifecycle. Use the definePlugin function to specify the plugin's name, compatible environments (client, server, or both), and lifecycle hooks. Depending on the environment the plugin is running in, only the corresponding subset of hooks will be executed.
    import { definePlugin } from '@microeinhundert/radonis'
    
    function yourPlugin() {
      return definePlugin({
        name: 'your-plugin',
        environments: ['client', 'server'],
    
        // Client-side hooks
        onInitClient() {},
        beforeHydrate() {
          return (tree) => {
            // Return modified React tree
            return tree
          }
        },
    
        // Server-side hooks
        onBootServer({ appRoot, resourcesPath }) {},
        beforeRequest({ ctx }) {},
        afterRequest({ ctx }) {},
        beforeRender({ ctx, manifest, props }) {
          return (tree) => {
            // Return modified React tree
            return tree
          }
        },
        afterRender({ ctx }) {
          return (html) => {
            // Return modified HTML
            return html
          }
        },
      })
    }
  10. Retrieve and check session flash messages with useFlashMessages

    The useFlashMessages hook allows you to retrieve session flash messages available for the current HTTP request. It works in both Client and Server environments. You can retrieve all messages, check for the existence of any message, or target specific messages by their key.
    import { useFlashMessages } from '@microeinhundert/radonis'
    
    const flashMessages = useFlashMessages()
    
    // Retrieve all flash messages as an object
    console.log(flashMessages.all()) // => `{ 'helloWorld': 'hello world', ... }`
    
    // Check if any flash messages exist
    console.log(flashMessages.hasAny()) // => `true` or `false`
    
    // Check if a specific flash message key exists
    console.log(flashMessages.has$('helloWorld')) // => `true` or `false`
    
    // Retrieve the value of a specific flash message
    console.log(flashMessages.get$('helloWorld')) // => `hello world`
  11. Install Radonis in an AdonisJS project

    Radonis is a full-stack framework for building monolithic applications with a React-based frontend, built on top of AdonisJS 5. It is strongly recommended to install Radonis in a fresh AdonisJS project created with the web project structure.

    To install the core packages, run:

    npm install --save @microeinhundert/radonis @microeinhundert/radonis-server
  12. Create interactive islands in Radonis

    In Radonis, components are server-side rendered by default. To create a component that is hydrated client-side for interactivity, wrap the component with the island function and ensure the file ends with the .island.<ext> suffix (e.g., .island.tsx). These files should be located in the resources directory, preferably resources/components. Avoid importing server-only code within islands.
    // resources/components/SomeInteractiveIsland.island.tsx
    import { island } from '@microeinhundert/radonis'
    
    function SomeInteractiveIsland({ message }: { message: string }) {
      function handleClick() {
        alert(message)
      }
    
      return <button type="button" onClick={handleClick}>Click me</button>
    }
    
    // The first argument should be a unique name for the island
    export default island('SomeInteractiveIsland', SomeInteractiveIsland)