@jpmart/fastify-jsx
v0.0.7
Published
This is a rendering engine for Fastify that supports JSX. The JSX runtime used is the super good [@kitajs/html](https://github.com/kitajsl). See their documentation for more information.
Downloads
17
Readme
@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:
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
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" }] } }
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 yourpackage.json
file and add the following script:// package.json { "scripts": { "test": "xss-scan" } }
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" }
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 aXSS
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, asString.name
has a type ofstring
, 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.