jeasx 2.3.1 β†’ 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,81 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026-02-20 - Jeasx 2.4.0 released
4
+
5
+ πŸŽ‰ This release is both a step forward and a step back: the recently introduced support for MDX has been removed from the core project. Jeasx aims to keep its core as lean as possible, so this change aligns with the project's overall goals. Since MDX is not essential for every Jeasx website or application, it makes sense to move it out of the core.
6
+
7
+ Another key goal of Jeasx is to empower users to implement their own custom solutions in userland, providing the right tools to do so. In short, while MDX remains a fantastic technology for content-driven websites, Jeasx now lets you configure MDX support yourself through a much improved configuration system for its base technologies like esbuild and Fastify.
8
+
9
+ For esbuild, two new configuration options are available: `ESBUILD_SERVER_OPTIONS` and `ESBUILD_BROWSER_OPTIONS`. These can be defined as functions in `.env.js` that return additional configuration settings for esbuild.
10
+
11
+ Why use functions instead of plain objects for the configuration? Because using functions allows configurations to be created lazily - only when needed - which is especially helpful for more complex setups over time.
12
+
13
+ If you want to use MDX with Jeasx, simply run `npm install @mdx-js/esbuild` and add the configuration below to `ESBUILD_SERVER_OPTIONS` in `.env.js`.
14
+
15
+ If you've used `ESBUILD_BROWSER_TARGET` in the past, you have to move this configuration to `ESBUILD_BROWSER_OPTIONS` as shown below.
16
+
17
+ ```jsx
18
+ import mdx from "@mdx-js/esbuild";
19
+
20
+ export default {
21
+ /** @type {() => import("esbuild").BuildOptions} */
22
+ ESBUILD_SERVER_OPTIONS: () => ({
23
+ plugins: [
24
+ mdx({
25
+ development: process.env.NODE_ENV === "development",
26
+ jsxImportSource: "jsx-async-runtime",
27
+ elementAttributeNameCase: "html",
28
+ stylePropertyNameCase: "css"
29
+ })
30
+ ]
31
+ }),
32
+
33
+ /** @type {() => import("esbuild").BuildOptions} */
34
+ ESBUILD_BROWSER_OPTIONS: () => ({
35
+ target: ["chrome130", "edge130", "firefox130", "safari18"]
36
+ })
37
+ }
38
+ ```
39
+
40
+ The existing configuration options for Fastify (such as `FASTIFY_SERVER_OPTIONS`, `FASTIFY_COOKIE_OPTIONS`, `FASTIFY_MULTIPART_OPTIONS`, `FASTIFY_STATIC_OPTIONS`) now require a minor change: they must be defined as functions instead of plain objects.
41
+
42
+ Additionally, you can now customize the fastify server instance using the optional `FASTIFY_SERVER` function. This function receives the created server instance and should return the modified version. This feature is especially useful when integrating existing Fastify plugins like `@fastify/compress`, as demonstrated below.
43
+
44
+ ```jsx
45
+ import fastifyCompress from "@fastify/compress";
46
+
47
+ const NODE_ENV_IS_DEVELOPMENT = process.env.NODE_ENV === "development";
48
+
49
+ export default {
50
+ /** @type {(fastify: import("fastify").FastifyInstance) => import("fastify").FastifyInstance} */
51
+ FASTIFY_SERVER: (fastify) => fastify.register(fastifyCompress),
52
+
53
+ /** @type {() => import("fastify").FastifyServerOptions} */
54
+ FASTIFY_SERVER_OPTIONS: () => ({
55
+ disableRequestLogging: NODE_ENV_IS_DEVELOPMENT,
56
+ bodyLimit: 1024 * 1024
57
+ }),
58
+
59
+ /** @type {() => import("@fastify/static").FastifyStaticOptions} */
60
+ FASTIFY_STATIC_OPTIONS: () => ({
61
+ immutable: !NODE_ENV_IS_DEVELOPMENT,
62
+ maxAge: NODE_ENV_IS_DEVELOPMENT ? 0 : "365d"
63
+ })
64
+ };
65
+ ```
66
+
67
+ Another notable change is that the fallback content-type (`text/html`) for routes is now set as late as possible. This means you can return plain JavaScript objects from routes, which will be automatically sent as `application/json` by default - without needing to explicitly specify the content-type in your code. This update brings Jeasx in line with Fastify’s default behavior.
68
+
69
+ Additionally, you can now define routes directly from simple `*.json` or `*.txt` files - perfect for creating static endpoints like a health check or a `robots.txt` file right in your routes folder.
70
+
71
+ Dependency updates: `@types/node@25.3.0`
72
+
73
+ ## 2026-02-12 - Jeasx 2.3.2 released
74
+
75
+ πŸŽ‰ Upgraded to @types/node@25, enabling seamless development with Node 25 while maintaining compatibility for Node 24 users.
76
+
77
+ Dependency updates: `esbuild@0.27.3`, `@types/node@25.2.3`
78
+
3
79
  ## 2026-02-04 - Jeasx 2.3.1 released
4
80
 
5
81
  πŸŽ‰ Just a patch release to update Fastify to fix [CVE-2026-25224](https://github.com/fastify/fastify/security/advisories/GHSA-mrq3-vjjr-p77c).
@@ -406,7 +482,7 @@ Added two new environment variables (`FASTIFY_DISABLE_REQUEST_LOGGING` and `FAST
406
482
 
407
483
  ## 2024-12-01 - Jeasx 1.1.0 released
408
484
 
409
- πŸŽ‰ Migrated from dotenv to dotenv-flow, so you can use NODE_ENV-specific .env\* files (like `.env.development`) to configure different environments for production and development. This is useful to disable caching headers (e.g. via `FASTIFY_STATIC_HEADERS`) in development, as Jeasx applies `FASTIFY_STATIC_HEADERS` in development from now on for a more consistent developer expierence. See updated .env-files in the quickstart-project for an example how to disable caching in development. This is only needed if you have configured `FASTIFY_STATIC_HEADERS` for your existing projects.
485
+ πŸŽ‰ Migrated from dotenv to dotenv-flow, so you can use NODE_ENV-specific .env\* files (like `.env.development`) to configure different environments for production and development. This is useful to disable caching headers (e.g. via `FASTIFY_STATIC_HEADERS`) in development, as Jeasx applies `FASTIFY_STATIC_HEADERS` in development from now on for a more consistent developer experience. See updated .env-files in the quickstart-project for an example how to disable caching in development. This is only needed if you have configured `FASTIFY_STATIC_HEADERS` for your existing projects.
410
486
 
411
487
  Bumped default environment variable `ESBUILD_BROWSER_TARGET` to more recent browser versions (e.g. `chrome126, edge126, firefox128, safari17`). If you want to stick with older versions, you can override it via the environment. Learn more about possible values at the esbuild website.
412
488
 
package/env.js CHANGED
@@ -31,7 +31,17 @@ export default async function env() {
31
31
  const envObject = (await import(envFile)).default;
32
32
  Object.entries(envObject).forEach(([key, value]) => {
33
33
  try {
34
- process.env[key] = typeof value === "string" ? value : JSON.stringify(value);
34
+ switch (typeof value) {
35
+ case "string":
36
+ process.env[key] = value;
37
+ break;
38
+ case "function":
39
+ process.env[key] = value.toString();
40
+ break;
41
+ default:
42
+ process.env[key] = JSON.stringify(value);
43
+ break;
44
+ }
35
45
  } catch (error) {
36
46
  // JSON.stringify throws TypeError for circular references or BigInts.
37
47
  console.error("❌", `"${key}" in .env.js throws`, error);
package/esbuild.config.js CHANGED
@@ -1,4 +1,3 @@
1
- import mdx from "@mdx-js/esbuild";
2
1
  import * as esbuild from "esbuild";
3
2
  import env from "./env.js";
4
3
 
@@ -16,33 +15,15 @@ const BROWSER_PUBLIC_ENV = Object.keys(ENV)
16
15
  { "process.env.BROWSER_PUBLIC_BUILD_TIME": BUILD_TIME },
17
16
  );
18
17
 
19
- const ESBUILD_BROWSER_TARGET = ENV.ESBUILD_BROWSER_TARGET || [
20
- "chrome130",
21
- "edge130",
22
- "firefox130",
23
- "safari18",
24
- ];
25
-
26
- const ESBUILD_MDX_PLUGIN = mdx({
27
- development: process.env.NODE_ENV === "development",
28
- jsxImportSource: "jsx-async-runtime",
29
- elementAttributeNameCase: "html",
30
- stylePropertyNameCase: "css",
31
- ...ENV.ESBUILD_MDX_OPTIONS,
32
- });
33
-
34
18
  /** @type esbuild.BuildOptions[] */
35
19
  const buildOptions = [
36
20
  {
37
- entryPoints: ["js", "ts", "jsx", "tsx", "mdx"].map((ext) => `src/**/[*].${ext}`),
21
+ entryPoints: ["src/**/[*].*"],
38
22
  define: {
39
23
  "process.env.BUILD_TIME": BUILD_TIME,
40
24
  },
41
25
  minify: process.env.NODE_ENV !== "development",
42
26
  logLevel: "info",
43
- logOverride: {
44
- "empty-glob": "silent",
45
- },
46
27
  color: true,
47
28
  bundle: true,
48
29
  sourcemap: process.sourceMapsEnabled,
@@ -50,16 +31,13 @@ const buildOptions = [
50
31
  outdir: "dist/server",
51
32
  platform: "neutral",
52
33
  packages: "external",
53
- plugins: [ESBUILD_MDX_PLUGIN],
34
+ ...ENV.ESBUILD_SERVER_OPTIONS?.(),
54
35
  },
55
36
  {
56
- entryPoints: ["js", "ts", "jsx", "tsx", "css"].map((ext) => `src/**/index.${ext}`),
37
+ entryPoints: ["src/**/index.*"],
57
38
  define: BROWSER_PUBLIC_ENV,
58
39
  minify: process.env.NODE_ENV !== "development",
59
40
  logLevel: "info",
60
- logOverride: {
61
- "empty-glob": "silent",
62
- },
63
41
  color: true,
64
42
  bundle: true,
65
43
  sourcemap: process.sourceMapsEnabled,
@@ -67,7 +45,7 @@ const buildOptions = [
67
45
  outdir: "dist/browser",
68
46
  platform: "browser",
69
47
  format: "esm",
70
- target: ESBUILD_BROWSER_TARGET,
48
+ target: ["chrome130", "edge130", "firefox130", "safari18"],
71
49
  external: [
72
50
  "*.avif",
73
51
  "*.gif",
@@ -82,7 +60,7 @@ const buildOptions = [
82
60
  "*.woff",
83
61
  "*.woff2",
84
62
  ],
85
- plugins: [ESBUILD_MDX_PLUGIN],
63
+ ...ENV.ESBUILD_BROWSER_OPTIONS?.(),
86
64
  },
87
65
  ];
88
66
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jeasx",
3
- "version": "2.3.1",
3
+ "version": "2.4.0",
4
4
  "description": "Jeasx - the ease of JSX with the power of SSR",
5
5
  "keywords": [
6
6
  "fastify",
@@ -31,9 +31,8 @@
31
31
  "@fastify/formbody": "8.0.2",
32
32
  "@fastify/multipart": "9.4.0",
33
33
  "@fastify/static": "9.0.0",
34
- "@mdx-js/esbuild": "3.1.1",
35
- "@types/node": "24.10.10",
36
- "esbuild": "0.27.2",
34
+ "@types/node": "25.3.0",
35
+ "esbuild": "0.27.3",
37
36
  "fastify": "5.7.4",
38
37
  "jsx-async-runtime": "2.0.2"
39
38
  }
package/serverless.js CHANGED
@@ -2,7 +2,7 @@ import fastifyCookie from "@fastify/cookie";
2
2
  import fastifyFormbody from "@fastify/formbody";
3
3
  import fastifyMultipart from "@fastify/multipart";
4
4
  import fastifyStatic from "@fastify/static";
5
- import Fastify from "fastify";
5
+ import fastify from "fastify";
6
6
  import { jsxToString } from "jsx-async-runtime";
7
7
  import { stat } from "node:fs/promises";
8
8
  import { freemem } from "node:os";
@@ -12,33 +12,40 @@ const ENV = await env();
12
12
  const CWD = process.cwd();
13
13
  const NODE_ENV_IS_DEVELOPMENT = process.env.NODE_ENV === "development";
14
14
  const JEASX_ROUTE_CACHE_LIMIT = Math.floor(freemem() / 1024 / 1024);
15
- var serverless_default = Fastify({
16
- logger: true,
17
- ...ENV.FASTIFY_SERVER_OPTIONS
18
- }).register(fastifyCookie, {
19
- ...ENV.FASTIFY_COOKIE_OPTIONS
20
- }).register(fastifyFormbody, {
21
- ...ENV.FASTIFY_FORMBODY_OPTIONS
22
- }).register(fastifyMultipart, {
23
- attachFieldsToBody: "keyValues",
24
- ...ENV.FASTIFY_MULTIPART_OPTIONS
25
- }).register(fastifyStatic, {
26
- root: [["public"], ["dist", "browser"]].map((dir) => join(CWD, ...dir)),
27
- prefix: "/",
28
- wildcard: false,
29
- preCompressed: true,
30
- ...ENV.FASTIFY_STATIC_OPTIONS
31
- }).decorateRequest("route", "").decorateRequest("path", "").addHook("onRequest", async (request, reply) => {
32
- reply.header("Content-Type", "text/html; charset=utf-8");
33
- const index = request.url.indexOf("?");
34
- request.path = index === -1 ? request.url : request.url.slice(0, index);
35
- }).all("*", async (request, reply) => {
36
- try {
37
- return await handler(request, reply);
38
- } catch (error) {
39
- console.error("\u274C", error);
40
- throw error;
41
- }
15
+ const FASTIFY_SERVER = ENV.FASTIFY_SERVER ?? ((fastify2) => fastify2);
16
+ var serverless_default = FASTIFY_SERVER(
17
+ fastify({
18
+ logger: true,
19
+ ...ENV.FASTIFY_SERVER_OPTIONS?.()
20
+ })
21
+ ).register((fastify2) => {
22
+ fastify2.register(fastifyCookie, {
23
+ ...ENV.FASTIFY_COOKIE_OPTIONS?.()
24
+ }).register(fastifyFormbody, {
25
+ ...ENV.FASTIFY_FORMBODY_OPTIONS?.()
26
+ }).register(fastifyMultipart, {
27
+ attachFieldsToBody: "keyValues",
28
+ ...ENV.FASTIFY_MULTIPART_OPTIONS?.()
29
+ }).register(fastifyStatic, {
30
+ root: [["public"], ["dist", "browser"]].map((dir) => join(CWD, ...dir)),
31
+ prefix: "/",
32
+ wildcard: false,
33
+ ...ENV.FASTIFY_STATIC_OPTIONS?.()
34
+ }).decorateRequest("route", "").decorateRequest("path", "").addHook("onRequest", async (request) => {
35
+ const index = request.url.indexOf("?");
36
+ request.path = index === -1 ? request.url : request.url.slice(0, index);
37
+ }).all("*", async (request, reply) => {
38
+ try {
39
+ const payload = await handler(request, reply);
40
+ if (reply.getHeader("content-type") === void 0 && (typeof payload === "string" || Buffer.isBuffer(payload))) {
41
+ reply.type("text/html; charset=utf-8");
42
+ }
43
+ return payload;
44
+ } catch (error) {
45
+ console.error("\u274C", error);
46
+ throw error;
47
+ }
48
+ });
42
49
  });
43
50
  const modules = /* @__PURE__ */ new Map();
44
51
  async function handler(request, reply) {
@@ -79,11 +86,12 @@ async function handler(request, reply) {
79
86
  }
80
87
  }
81
88
  request.route = route;
82
- response = await module.default.call(context, {
89
+ response = // Call functions with request, reply and optional props
90
+ typeof module.default === "function" ? await module.default.call(context, {
83
91
  request,
84
92
  reply,
85
93
  ...typeof response === "object" ? response : {}
86
- });
94
+ }) : module.default;
87
95
  if (reply.sent) {
88
96
  return;
89
97
  } else if (route.endsWith("/[404]")) {
package/serverless.js.map CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["serverless.ts"],
4
- "mappings": "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",
5
- "names": []
4
+ "mappings": "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",
5
+ "names": ["fastify"]
6
6
  }
package/serverless.ts CHANGED
@@ -2,7 +2,12 @@ import fastifyCookie, { FastifyCookieOptions } from "@fastify/cookie";
2
2
  import fastifyFormbody, { FastifyFormbodyOptions } from "@fastify/formbody";
3
3
  import fastifyMultipart, { FastifyMultipartOptions } from "@fastify/multipart";
4
4
  import fastifyStatic, { FastifyStaticOptions } from "@fastify/static";
5
- import Fastify, { FastifyReply, FastifyRequest, FastifyServerOptions } from "fastify";
5
+ import fastify, {
6
+ FastifyInstance,
7
+ FastifyReply,
8
+ FastifyRequest,
9
+ FastifyServerOptions,
10
+ } from "fastify";
6
11
  import { jsxToString } from "jsx-async-runtime";
7
12
  import { stat } from "node:fs/promises";
8
13
  import { freemem } from "node:os";
@@ -22,44 +27,59 @@ declare module "fastify" {
22
27
  }
23
28
  }
24
29
 
25
- // Create and export a Fastify app instance
26
- export default Fastify({
27
- logger: true,
28
- ...(ENV.FASTIFY_SERVER_OPTIONS as FastifyServerOptions),
29
- })
30
- .register(fastifyCookie, {
31
- ...(ENV.FASTIFY_COOKIE_OPTIONS as FastifyCookieOptions),
32
- })
33
- .register(fastifyFormbody, {
34
- ...(ENV.FASTIFY_FORMBODY_OPTIONS as FastifyFormbodyOptions),
35
- })
36
- .register(fastifyMultipart, {
37
- attachFieldsToBody: "keyValues",
38
- ...(ENV.FASTIFY_MULTIPART_OPTIONS as FastifyMultipartOptions),
39
- })
40
- .register(fastifyStatic, {
41
- root: [["public"], ["dist", "browser"]].map((dir) => join(CWD, ...dir)),
42
- prefix: "/",
43
- wildcard: false,
44
- preCompressed: true,
45
- ...(ENV.FASTIFY_STATIC_OPTIONS as FastifyStaticOptions),
46
- })
47
- .decorateRequest("route", "")
48
- .decorateRequest("path", "")
49
- .addHook("onRequest", async (request, reply) => {
50
- // Set default content type to text/html
51
- reply.header("Content-Type", "text/html; charset=utf-8");
52
- // Extract path from url
53
- const index = request.url.indexOf("?");
54
- request.path = index === -1 ? request.url : request.url.slice(0, index);
55
- })
56
- .all("*", async (request: FastifyRequest, reply: FastifyReply) => {
57
- try {
58
- return await handler(request, reply);
59
- } catch (error) {
60
- console.error("❌", error);
61
- throw error;
62
- }
30
+ // Enhance Fastify server from userland
31
+ const FASTIFY_SERVER = (ENV.FASTIFY_SERVER ?? ((fastify) => fastify)) as (
32
+ fastify: FastifyInstance,
33
+ ) => FastifyInstance;
34
+
35
+ // Create and export a Fastify instance
36
+ export default FASTIFY_SERVER(
37
+ fastify({
38
+ logger: true,
39
+ ...(ENV.FASTIFY_SERVER_OPTIONS?.() as FastifyServerOptions),
40
+ }),
41
+ )
42
+ // Create encapsulation context
43
+ .register((fastify) => {
44
+ fastify
45
+ .register(fastifyCookie, {
46
+ ...(ENV.FASTIFY_COOKIE_OPTIONS?.() as FastifyCookieOptions),
47
+ })
48
+ .register(fastifyFormbody, {
49
+ ...(ENV.FASTIFY_FORMBODY_OPTIONS?.() as FastifyFormbodyOptions),
50
+ })
51
+ .register(fastifyMultipart, {
52
+ attachFieldsToBody: "keyValues",
53
+ ...(ENV.FASTIFY_MULTIPART_OPTIONS?.() as FastifyMultipartOptions),
54
+ })
55
+ .register(fastifyStatic, {
56
+ root: [["public"], ["dist", "browser"]].map((dir) => join(CWD, ...dir)),
57
+ prefix: "/",
58
+ wildcard: false,
59
+ ...(ENV.FASTIFY_STATIC_OPTIONS?.() as FastifyStaticOptions),
60
+ })
61
+ .decorateRequest("route", "")
62
+ .decorateRequest("path", "")
63
+ .addHook("onRequest", async (request) => {
64
+ // Extract path from url
65
+ const index = request.url.indexOf("?");
66
+ request.path = index === -1 ? request.url : request.url.slice(0, index);
67
+ })
68
+ .all("*", async (request: FastifyRequest, reply: FastifyReply) => {
69
+ try {
70
+ const payload = await handler(request, reply);
71
+ if (
72
+ reply.getHeader("content-type") === undefined &&
73
+ (typeof payload === "string" || Buffer.isBuffer(payload))
74
+ ) {
75
+ reply.type("text/html; charset=utf-8");
76
+ }
77
+ return payload;
78
+ } catch (error) {
79
+ console.error("❌", error);
80
+ throw error;
81
+ }
82
+ });
63
83
  });
64
84
 
65
85
  // Cache for resolved route modules, 'null' means no module exists.
@@ -124,12 +144,15 @@ async function handler(request: FastifyRequest, reply: FastifyReply) {
124
144
  // Store current route in request
125
145
  request.route = route;
126
146
 
127
- // Call the handler with request, reply and optional props
128
- response = await module.default.call(context, {
129
- request,
130
- reply,
131
- ...(typeof response === "object" ? response : {}),
132
- });
147
+ response =
148
+ // Call functions with request, reply and optional props
149
+ typeof module.default === "function"
150
+ ? await module.default.call(context, {
151
+ request,
152
+ reply,
153
+ ...(typeof response === "object" ? response : {}),
154
+ })
155
+ : module.default; // otherwise return default export
133
156
 
134
157
  if (reply.sent) {
135
158
  return;