Configuration

How to configure Jeasx

Jeasx offers minimal and sensible default settings to help you get started quickly, while also giving you full control to customize key aspects. You can adapt all plugins and configuration options provided by esbuild and Fastify to perfectly match and grow your project’s requirements.

Environment variables

To facilitate managing multiple configurations, Jeasx leverages layers of .env-files. This enables the use of different .env-files based on the NODE_ENV value, such as .env.development to override values from .env for development. The order of loading .env-files is the same as it is used by the well-known dotenv-flow library. To load the env-files into process.env, Jeasx makes use of the native implementation provided by Node.js via process.loadEnvFile via a custom utility function.

  • .env.[NODE_ENV].local (e.g. .env.development.local or .env.production.local)
  • .env.[NODE_ENV] (e.g. .env.development or .env.production)
  • .env.local
  • .env
  • .env.defaults

An existing environment variable will not be overwritten by subsequent environment files.

Please note: Jeasx only sets NODE_ENV=development automatically when running jeasx dev. For production or testing environments, you'll need to set the NODE_ENV environment variable to the desired value (e.g. production or test) depending on your requirements and workflows.

Fundamental environment variables

HOST

The hostname or IP address that the server should listen on. Defaults to :: which allows the server to listen on any interface (IPv4 or IPv6).

PORT

The port number that the server should listen on. Defaults to 3000.

BUILD_TIME

A value set at build time and encoded as base36 (lower case alphabet and digits). Use it to create a cache busting parameter for loading JavaScript and CSS files.

Environment variables for client code

For security reasons, only environment variables prefixed with BROWSER_PUBLIC_ are accessible in client-side JavaScript to prevent accidental exposure of sensitive data. The values are only updated at build time, so changes to environment variables will require a rebuild to take effect.

Configure esbuild and Fastify via jeasx.config.js

The configuration object from jeasx.config.js is imported directly into both the build process and server runtime and provides essential options for esbuild and Fastify, allowing you to use the full power of JavaScript (e.g package imports) to build advanced setups.

export default {
  /** @type {() => import("esbuild").BuildOptions} */
  ESBUILD_SERVER_OPTIONS: () => ({}),

  /** @type {() => import("esbuild").BuildOptions} */
  ESBUILD_BROWSER_OPTIONS: () => ({}),

  /** @type {(fastify: import("fastify").FastifyInstance) => import("fastify").FastifyInstance} */
  FASTIFY_SERVER: (fastify) => fastify,

  /** @type {() => import("fastify").FastifyServerOptions} */
  FASTIFY_SERVER_OPTIONS: () => ({}),

  /** @type {() => import("@fastify/send").SendOptions} */
  FASTIFY_SEND_OPTIONS: () => ({}),
};

ESBUILD_SERVER_OPTIONS

Useful to enhance esbuild for compiling server code with existing plugins (Jeasx config at GitHub). The esbuild website provides a detailed explanation of all configuration options.

If you want to use MDX with plugins, you can configure them in jeasx.config.js after installing them to your project:

import mdx from "@mdx-js/esbuild";
import rehypePrismPlus from "rehype-prism-plus";
import rehypeSlug from "rehype-slug";
import remarkGFM from "remark-gfm";

export default {
  /** @type {() => import("esbuild").BuildOptions} */
  ESBUILD_SERVER_OPTIONS: () => ({
    plugins: [
      mdx({
        development: process.env.NODE_ENV === "development",
        jsxImportSource: "jsx-async-runtime",
        elementAttributeNameCase: "html",
        stylePropertyNameCase: "css",
        remarkPlugins: [[remarkGFM, { singleTilde: false }]],
        rehypePlugins: [rehypePrismPlus, [rehypeSlug, { prefix: "jeasx-" }]],
      }),
    ],
  }),
};

ESBUILD_BROWSER_OPTIONS

Useful to configure build options for the browser bundle (Jeasx config at GitHub), e.g. reconfigure the browser target of esbuild. Full documentation at esbuild website.

export default {
  /** @type {() => import("esbuild").BuildOptions} */
  ESBUILD_BROWSER_OPTIONS: () => ({
    target: ["chrome130", "edge130", "firefox130", "safari18"],
  }),
};

FASTIFY_SERVER

This allows you to enhance the functionality of the underlying Fastify server, e.g. registering plugins.

export default {
  /** @type {(fastify: import("fastify").FastifyInstance) => import("fastify").FastifyInstance} */
  FASTIFY_SERVER: (fastify) => fastify.register(import("@fastify/compress")),
};

FASTIFY_SERVER_OPTIONS

Use these options to define the central configuration for the Fastify server.

Fastity-Server options reference.

export default {
  /** @type {() => import("fastify").FastifyServerOptions} */
  FASTIFY_SERVER_OPTIONS: () => ({
    logger: { level: process.env.NODE_ENV == "development" ? "error" : "info" },
    bodyLimit: 2 * 1024 * 1024,
  }),
};

FASTIFY_SEND_OPTIONS

Use these options to serve static files, such as those located in the public directory or compiled frontend assets from dist.

Fastify-Send options reference.

export default {
  /** @type {() => import("@fastify/send").SendOptions} */
  FASTIFY_SEND_OPTIONS: () => ({
    immutable: process.env.NODE_ENV !== "development",
    maxAge: process.env.NODE_ENV == "development" ? 0 : "365d",
  }),
};

Recommended Fastify plugins

Jeasx is built on the philosophy of providing a powerful core while pushing customizations to the user level. By avoiding opinionated defaults, Jeasx gives you the freedom to build a setup that is uniquely your own.

Need more features? No problem! Jeasx makes it easy to customize Fastify. Here are some Fastify plugins which help you to use common features in web development:

npm install @fastify/formbody @fastify/cookie @fastify/multipart

Next, update your jeasx.config.js with the following configuration to customize your Fastify server instance:

export default {
  /** @type {(fastify: import("fastify").FastifyInstance) => import("fastify").FastifyInstance} */
  FASTIFY_SERVER: (fastify) =>
    fastify
      .register(import("@fastify/formbody"), {/* formbody options */})
      .register(import("@fastify/multipart"), {/* multipart options */})
      .register(import("@fastify/cookie"), {/* cookie options */}),
};

Because plugins like @fastify/cookie and @fastify/multipart extend the request and reply objects, you should add the following imports to src/types.d.ts (or a similar definition file in your project) to ensure proper TypeScript support for your editor:

import "@fastify/cookie";
import "@fastify/multipart";

Handle form submissions without @fastify/formbody

Although @fastify/formbody is commonly used for processing POST form data, Fastify provides the flexibility to define custom content type parsers manually. The following configuration demonstrates this approach:

import querystring from "node:querystring";

export default {
  /** @type {(fastify: import("fastify").FastifyInstance) => import("fastify").FastifyInstance} */
  FASTIFY_SERVER: (fastify) =>
    fastify.addContentTypeParser(
      "application/x-www-form-urlencoded",
      { parseAs: "string" },
      async (_request, body) => querystring.parse(body),
    ),
};

This configuration allows you to remove @fastify/formbody as a dependency.

Please note: The native Node.js querystring parser may have slightly higher latency than @fastify/formbody, but for the majority of applications, this performance trade-off is insignificant.