Skip to content

Releases: rphlmr/react-router-hono-server

v2.7.1

14 Jan 20:13
89bc37c
Compare
Choose a tag to compare

What's Changed

  • refactor: deprecate reactRouterRedirect in favor of redirect helper. … by @rphlmr in #62

Check: https://github.com/rphlmr/react-router-hono-server?tab=readme-ov-file#middleware

import { redirect } from "react-router-hono-server/http";

Full Changelog: v2.6.4...v2.7.0

v2.6.4

05 Jan 12:02
21a930c
Compare
Choose a tag to compare

What's Changed

Full Changelog: v2.5.0...v2.6.0

Fixes #49 #44 #47

  • Add Vite 6 as a peer dependency (keeping Vite 5 too).
  • Fix build loader for cloudflare
  • Fix missing AppLoadContext in dev (dev server issue)
  • Add support for React Router basename
  • Handle React Router app as a Hono sub app
  • [Cloudflare]: setting experimental_serve_directly in wrangler config will now use your Hono server to serve assets
  • Remove deprecated honoOptions in favor of app option (createHonoServer)
  • Temporary handle React Router issue (remix-run/react-router#12295)

Basename and Hono sub apps

Note

By default, the React Router app is mounted at / (default basename value).

You may not need to use this option. It's for advanced use cases.

Tip

Check this example to see how to use it.

You can use the basename option in your React Router config (react-router.config.ts) to mount your React Router app on a subpath.

It will automatically mount the app on the subpath.

// react-router.config.ts
import type { Config } from "@react-router/dev/config";

export default {
  basename: "/app", // Now the React Router app will be mounted on /app
} satisfies Config;

Then, you can use the app option in createHonoServer to pass your "root" Hono app. This will be used to mount the React Router app on the basename path.

import { Hono } from "hono";
import { createHonoServer } from "react-router-hono-server/node";
import { API_BASENAME, api } from "./api";
import { getLoadContext } from "./context";

// Create a root Hono app
const app = new Hono();

// Mount the API app at /api
app.route(API_BASENAME, api);

export default await createHonoServer({
  // Pass the root Hono app to the server.
  // It will be used to mount the React Router app on the `basename` defined in react-router.config.ts
  app,
  getLoadContext,
});

Note

You now have two entry points!

  • /api - for your API
  • /app - for your React Router app

Cloudflare custom assets serving

You can set Cloudflare experimental_serve_directly and delegate assets serving to Hono, like for Node and Bun.

Tip

Check this example to see how to use it.

[assets]
directory = "./build/client/"
binding = "ASSETS"
experimental_serve_directly = false

v2.5.0

03 Jan 17:12
170396d
Compare
Choose a tag to compare

New

new helper: reactRouterRedirect

Redirect to a new location in a way that React Router can handle (Single fetch protocol).

🚨 Redirecting from a middleware

Important

You have to use the reactRouterRedirect helper to redirect from a middleware.

It returns a single-fetch-like response.

If you use c.redirect, it will not work as expected and you will get a Unable to decode turbo-stream response error.

import { reactRouterRedirect } from "react-router-hono-server/http";

new createHonoServer option: beforeAll

You can use the beforeAll option to add middleware that runs before any built-in middleware, including assets serving.

You can use it to add protection middleware, for example.

Tip

When you check the path to protect, don't forget to use c.req.path.includes("") to handle .data requests (loader)!

import { reactRouterRedirect } from "react-router-hono-server/http";
import { createHonoServer } from "react-router-hono-server/node";

export default await createHonoServer({
  beforeAll(app) {
    app.use(async (c, next) => {
      if (c.req.path.includes("/protected") && !c.req.header("Authorization")) {
        return reactRouterRedirect("/login");
      }

      return next();
    });
  },
});

new createHonoServer option: overrideGlobalObjects

https://github.com/honojs/node-server?tab=readme-ov-file#overrideglobalobjects

It is now set to false by default to prevent some issues with 3rd party libs like remix-hook-form.

Enabling this makes request.clone() not an instanceof Request.

export default await createHonoServer({
  overrideGlobalObjects: true,
});

Fixes

What's Changed

New Contributors

Full Changelog: v2.4.0...v2.5.0

v2.4.0

29 Dec 12:37
6c5dcdc
Compare
Choose a tag to compare

What's Changed

Full Changelog: v2.3.0...v2.4.0

v2.3.0

20 Dec 08:21
2e45d45
Compare
Choose a tag to compare

What's Changed

Pre-rendering

You should be able to use pre-rendering with this package.

Tip

Check this example to see how to use it.

Important

You need to add the serverBuildFile option to your react-router.config.ts file.

The file path is fixed to assets/server-build.js.

Add the prerender option to your react-router.config.ts

import type { Config } from "@react-router/dev/config";

export default {
  serverBuildFile: "assets/server-build.js", // 🚨 Dont forget this
  prerender: ["/"],
} satisfies Config;

Full Changelog: v2.2.1...v2.3.0

v2.2.1

09 Dec 20:52
7998b7d
Compare
Choose a tag to compare

What's Changed

  • fix: listeningListener not called by @rphlmr in #31

Full Changelog: v2.2.0...v2.2.1

v2.2.0

08 Dec 15:57
aeebbb7
Compare
Choose a tag to compare

What's Changed

  • Extended API to support WebSocket by @rphlmr in #24

You can now enable WebSocket with the useWebSocket option.

It works for node and bun. Cloudflare requires a custom implementation.

Take a look at all the examples.

import type { WSContext } from "hono/ws";
import { createHonoServer } from "react-router-hono-server/node";

// Store connected clients
const clients = new Set<WSContext>();

export default await createHonoServer({
  useWebSocket: true,
  // 👆 Unlock this 👇 from @hono/node-ws
  configure: (app, { upgradeWebSocket }) => {
    app.get(
      "/ws",
      upgradeWebSocket((c) => ({
        // https://hono.dev/helpers/websocket
        onOpen(_, ws) {
          console.log("New connection ⬆️");
          clients.add(ws);
        },
        onMessage(event, ws) {
          console.log("Context", c.req.header("Cookie"));
          console.log("Event", event);
          console.log(`Message from client: ${event.data}`);
          // Broadcast to all clients except sender
          clients.forEach((client) => {
            if (client.readyState === 1) {
              client.send(`${event.data}`);
            }
          });
        },
        onClose(_, ws) {
          console.log("Connection closed");
          clients.delete(ws);
        },
      }))
    );
  },
});

Full Changelog: v2.1.2...v2.2.0

v2.1.2

28 Nov 11:20
7f57050
Compare
Choose a tag to compare

What's Changed

Breaking change for Cloudflare

You need to install these packages too:

npm install -D miniflare wrangler

2.1.0

Bun

Tip

Check this example to see how to use it.

// vite.config.ts
import { reactRouter } from "@react-router/dev/vite";
import { reactRouterHonoServer } from "react-router-hono-server/dev"; // add this
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
  plugins: [
    reactRouterHonoServer({ runtime: "bun"} ), // add this
    reactRouter(),
    tsconfigPaths()
  ],
});

More doc about Bun

Cloudflare Workers

Tip

Check this example to see how to use it.

Important

You need to add the cloudflareDevProxy plugin to use the Cloudflare Workers runtime on dev.

// vite.config.ts
import { reactRouter } from "@react-router/dev/vite";
import { cloudflareDevProxy } from "@react-router/dev/vite/cloudflare"; // add this
import { reactRouterHonoServer } from "react-router-hono-server/dev"; // add this
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
  plugins: [
    cloudflareDevProxy(),
    reactRouterHonoServer({ runtime: "cloudflare"} ), // add this
    reactRouter(),
    tsconfigPaths()
  ],
});

More doc about Cloudflare

Full Changelog: v2.1.0...v2.1.2

v2.1.0

28 Nov 09:41
bba9ec9
Compare
Choose a tag to compare

What's Changed

Bun

Tip

Check this example to see how to use it.

// vite.config.ts
import { reactRouter } from "@react-router/dev/vite";
import { reactRouterHonoServer } from "react-router-hono-server/dev"; // add this
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
  plugins: [
    reactRouterHonoServer({ runtime: "bun"} ), // add this
    reactRouter(),
    tsconfigPaths()
  ],
});

More doc about Bun

Cloudflare Workers

Tip

Check this example to see how to use it.

Important

You need to add the cloudflareDevProxy plugin to use the Cloudflare Workers runtime on dev.

// vite.config.ts
import { reactRouter } from "@react-router/dev/vite";
import { cloudflareDevProxy } from "@react-router/dev/vite/cloudflare"; // add this
import { reactRouterHonoServer } from "react-router-hono-server/dev"; // add this
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
  plugins: [
    cloudflareDevProxy(),
    reactRouterHonoServer({ runtime: "cloudflare"} ), // add this
    reactRouter(),
    tsconfigPaths()
  ],
});

More doc about Cloudflare

Full Changelog: v2.0.0...v2.1.0

v2.0.0

25 Nov 18:45
7a78e9c
Compare
Choose a tag to compare

What's Changed

Important

This new version is only compatible with React Router v7

You can still use the v1 with @remix-run. Previous docs

Migration guide from v1 here

It's now a Vite Plugin 🥳

Install the following npm package.

npm install react-router-hono-server@latest

Easy mode

In your vite.config.ts, add the reactRouterHonoServer plugin.

import { reactRouter } from "@react-router/dev/vite";
import { reactRouterHonoServer } from "react-router-hono-server/dev"; // add this
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
  plugins: [
    reactRouterHonoServer(), // add this
    reactRouter(),
    tsconfigPaths()
  ],
});

That's all!

How it works

This helper works differently depending on the environment.

In development, it uses @hono/vite-dev-server and loads your server and React Router app with import('virtual:react-router/server-build').
It can be configured in vite.config.ts.

When building for production, the Hono server is compiled as build/server/index.js and imports your React Router app from assets/server-build-[hash].js.

New Contributors

Full Changelog: v1.2.0...v2.0.0