@jpmart/fastify-jsx
TypeScript icon, indicating that this package has built-in type declarations

0.0.7 • Public • Published

@jpmart/fastify-jsx

This is a rendering engine for Fastify that supports JSX. The JSX runtime used is the super good @kitajs/html. See their documentation for more information.

This plugin supports Fastify >= 4.x

This plugin uses

Installing

To use the @jpmart/fastify-jsx package, follow these steps:

  1. Install the required npm packages, @jpmart/fastify-jsx and @kitajs/ts-html-plugin, to enable editor intellisense. Open your terminal and run:

    npm install @jpmart/fastify-jsx @kitajs/ts-html-plugin
  2. Configure your TypeScript project to transpile TSX/JSX into JavaScript and using our LSP Plugin. Update your tsconfig.json file with the following settings:

    // tsconfig.json
    
    {
      "compilerOptions": {
        "jsx": "react",
        "jsxFactory": "Html.createElement",
        "jsxFragmentFactory": "Html.Fragment",
        "plugins": [{ "name": "@kitajs/ts-html-plugin" }]
      }
    }
  3. Append the xss-scan command into your test script. This CLI comes from @kitajs/ts-html-plugin, which catches XSS vulnerabilities that may be introduced into your codebase, automating the XSS scanning process to run every time you test your code, like inside your CI/CD environment. Open your package.json file and add the following script:

    // package.json
    
    {
      "scripts": {
        "test": "xss-scan"
      }
    }
  4. Ensure that your code editor is using the TypeScript version from your project's node_modules instead of the globally installed TypeScript. For Visual Studio Code, you can configure this in your workspace settings:

    // .vscode/settings.json
    
    {
      "typescript.tsdk": "node_modules/typescript/lib"
    }
  5. Register the plugin in your Fastify application

    // app.tsx
    
    import fastify from 'fastify';
    import fastifyJsx from '@jpmart/fastify-jsx';
    
    const app = fastify();
    
    app.register(fastifyJsx);
    
    app.get('/', (req, res) => {
      return res.render(() => <YourHomepageComponent />);
    });
    
    app.listen(3000);

[!CAUTION]

Be sure your setup is working correclty!

Try writing console.log(<div>{String.name}</div>); in your editor. If it THROWS a XSS error, then your setup is correct. Refer to the @kitajs/ts-html-plugin repository for more details on setting up editor intellisense. (It should throw, as String.name has a type of string, type which may or may not have special caracters)

Context

As in React, the context is a way to access some data from a parent component in a child component without having to pass it as a prop. This library provides a context implementation using two primitives: defineContext and consumeContext. The names are different from React's createContext and useContext to avoid confusion with the React implementation. Here is an example of how to use the context:

const MyContext = defineContext<{ name: string }>();

const MyComponent = () => {
  const { name } = consumeContext(MyContext);
  return <div>Hello {name}</div>;
};

// ...

app.get('/', (req, res) => {
  return res.render(() => (
    <MyContext.Provider value={{ name: 'John' }}>
      <MyComponent />
    </MyContext.Provider>
  ));
});

This library exposes two primitives based on the context implementation that are generally useful:

  • consumeFastify: This is a context that provides the Fastify instance. It is useful to access the Fastify instance in a component without having to pass it as a prop.
  • consumeRequest: This is a context that provides the Fastify request instance. It is useful to access the request instance in a component without having to pass it as a prop.

They can be used like this:

const MyComponent = async () => {
  const fastify = consumeFastify();
  const request = consumeRequest();

  const table = request.headers['x-table-name'];

  const data = await fastify.db.query(`SELECT * FROM ${table}`);

  return (
    <div>
      <p>Data from table {table}</p>
      <pre>{JSON.stringify(data)}</pre>
    </div>
  );
};

NOTE: If you are using a type inference strategy for your Fastify request, you will need to cast the request properties to the expected type. This is by design because the hook consumeRequest had no way of knowing for which request it had been called. This makes it possible to use the same component for different requests.

Suspense

This library wraps the Suspense component provided by @kitajs/html. This is done to have a better user experience when using Suspense. The Suspense component provided by @kitajs/html requires passing a render ID given by the internal render to support HTML streaming. Thanks to the context implementation this property is provided implicitly. This means that you can use Suspense like this:

import { Suspense } from '@jpmart/fastify-jsx';

async function MyAsyncComponent() {
  const data = await asyncFetchData();
  return <div>{data}</div>;
}

const MyComponent = () => {
  return (
    <div>
      <p>Page title</p>
      <Suspense fallback={<div>Loading...</div>}>
        <MyAsyncComponent />
      </Suspense>
    </div>
  );
};

Usage with HTMX or Other similar libraries

This library has been developed to make developing a fastify application with those libraries easier. To have a better developer experience we recommend importing the relative type definitions in your entry point like so:

For HTMX:

// app.tsx
import '@jpmart/fastify-jsx/htmx';

For Hotwire-Turbo:

// app.tsx
import '@jpmart/fastify-jsx/hotwire-turbo';

This will include all the type definitions for the library you are using.

Readme

Keywords

none

Package Sidebar

Install

npm i @jpmart/fastify-jsx

Weekly Downloads

0

Version

0.0.7

License

none

Unpacked Size

18.5 kB

Total Files

17

Last publish

Collaborators

  • jacopo_patroclo