@netlify/vite-plugin-react-router 1.0.0 → 2.0.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,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.0](https://github.com/netlify/remix-compute/compare/vite-plugin-react-router-v1.0.1...vite-plugin-react-router-v2.0.0) (2025-10-16)
4
+
5
+ ### ⚠ BREAKING CHANGES
6
+
7
+ * **@netlify/vite-plugin-react-router:** require React Router 7.9.0+ ([#546](https://github.com/netlify/remix-compute/issues/546))
8
+
9
+ Please make sure to upgrade `react-router` and other `@react-router/*` dependencies to 7.9.0 or later. Older versions are no longer supported.
10
+
11
+ ### Features
12
+
13
+ * **@netlify/vite-plugin-react-router:** support React Router middleware ([#546](https://github.com/netlify/remix-compute/issues/546)) ([435fa15](https://github.com/netlify/remix-compute/commit/435fa158d80d78e86b0259c3a668c774ef70c565))
14
+
15
+ ## [1.0.1](https://github.com/netlify/remix-compute/compare/vite-plugin-react-router-v1.0.0...vite-plugin-react-router-v1.0.1) (2025-04-04)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **deps:** support and test against Vite 6 ([#507](https://github.com/netlify/remix-compute/issues/507)) ([58c378a](https://github.com/netlify/remix-compute/commit/58c378ac6e1a723300f240756c1e26e577b00d44))
21
+
3
22
  ## 1.0.0 (2024-12-13)
4
23
 
5
24
 
package/README.md CHANGED
@@ -8,7 +8,7 @@ To deploy a React Router 7+ site to Netlify, install this package:
8
8
  ## How to use
9
9
 
10
10
  ```sh
11
- npm --save-dev install @netlify/vite-plugin-react-router
11
+ npm install --save-dev @netlify/vite-plugin-react-router
12
12
  ```
13
13
 
14
14
  and include the Netlify plugin in your `vite.config.ts`:
@@ -27,3 +27,79 @@ export default defineConfig({
27
27
  ],
28
28
  })
29
29
  ```
30
+
31
+ ### Load context
32
+
33
+ This plugin automatically includes all
34
+ [Netlify context](https://docs.netlify.com/build/functions/api/#netlify-specific-context-object) fields on loader and
35
+ action context.
36
+
37
+ If you're using TypeScript, `AppLoadContext` is automatically aware of these fields
38
+ ([via module augmentation](https://reactrouter.com/upgrading/remix#9-update-types-for-apploadcontext)).
39
+
40
+ For example:
41
+
42
+ ```tsx
43
+ import { useLoaderData } from 'react-router'
44
+ import type { Route } from './+types/example'
45
+
46
+ export async function loader({ context }: Route.LoaderArgs) {
47
+ return {
48
+ country: context.geo?.country?.name ?? 'an unknown country',
49
+ }
50
+ }
51
+ export default function Example() {
52
+ const { country } = useLoaderData<typeof loader>()
53
+ return <div>You are visiting from {country}</div>
54
+ }
55
+ ```
56
+
57
+ If you've [opted in to the `future.v8_middleware` flag](https://reactrouter.com/how-to/middleware), you can still use
58
+ the above access pattern for backwards compatibility, but loader and action context will now be an instance of the
59
+ type-safe `RouterContextProvider`. Note that this requires requires v2.0.0+ of `@netlify/vite-plugin-react-router`.
60
+
61
+ For example:
62
+
63
+ ```tsx
64
+ import { netlifyRouterContext } from '@netlify/vite-plugin-react-router'
65
+ import { useLoaderData } from 'react-router'
66
+ import type { Route } from './+types/example'
67
+
68
+ export async function loader({ context }: Route.LoaderArgs) {
69
+ return {
70
+ country: context.get(netlifyRouterContext).geo?.country?.name ?? 'an unknown country',
71
+ }
72
+ }
73
+ export default function Example() {
74
+ const { country } = useLoaderData<typeof loader>()
75
+ return <div>You are visiting from {country}</div>
76
+ }
77
+ ```
78
+
79
+ ### Middleware context
80
+
81
+ React Router introduced a stable middleware feature in 7.9.0.
82
+
83
+ To use middleware,
84
+ [opt in to the feature via `future.v8_middleware` and follow the docs](https://reactrouter.com/how-to/middleware). Note
85
+ that this requires requires v2.0.0+ of `@netlify/vite-plugin-react-router`.
86
+
87
+ To access the [Netlify context](https://docs.netlify.com/build/functions/api/#netlify-specific-context-object)
88
+ specifically, you must import our `RouterContextProvider` instance:
89
+
90
+ ```tsx
91
+ import { netlifyRouterContext } from '@netlify/vite-plugin-react-router'
92
+
93
+ import type { Route } from './+types/home'
94
+
95
+ const logMiddleware: Route.MiddlewareFunction = async ({ request, context }) => {
96
+ const country = context.get(netlifyRouterContext).geo?.country?.name ?? 'unknown'
97
+ console.log(`Handling ${request.method} request to ${request.url} from ${country}`)
98
+ }
99
+
100
+ export const middleware: Route.MiddlewareFunction[] = [logMiddleware]
101
+
102
+ export default function Home() {
103
+ return <h1>Hello world</h1>
104
+ }
105
+ ```
package/dist/index.d.mts CHANGED
@@ -1,17 +1,34 @@
1
- import { ServerBuild, AppLoadContext } from 'react-router';
1
+ import * as react_router from 'react-router';
2
+ import { AppLoadContext, RouterContextProvider, ServerBuild } from 'react-router';
2
3
  import { Context } from '@netlify/functions';
3
4
  import { Plugin } from 'vite';
4
5
 
5
- type LoadContext = AppLoadContext & Context;
6
+ declare module 'react-router' {
7
+ interface AppLoadContext extends Context {
8
+ }
9
+ }
6
10
  /**
7
- * A function that returns the value to use as `context` in route `loader` and
8
- * `action` functions.
11
+ * A function that returns the value to use as `context` in route `loader` and `action` functions.
9
12
  *
10
- * You can think of this as an escape hatch that allows you to pass
11
- * environment/platform-specific values through to your loader/action.
13
+ * You can think of this as an escape hatch that allows you to pass environment/platform-specific
14
+ * values through to your loader/action.
15
+ *
16
+ * NOTE: v7.9.0 introduced a breaking change when the user opts in to `future.v8_middleware`. This
17
+ * requires returning an instance of `RouterContextProvider` instead of a plain object. We have a
18
+ * peer dependency on >=7.9.0 so we can safely *import* these, but we cannot assume the user has
19
+ * opted in to the flag.
20
+ */
21
+ type GetLoadContextFunction = GetLoadContextFunction_V7 | GetLoadContextFunction_V8;
22
+ type GetLoadContextFunction_V7 = (request: Request, context: Context) => Promise<AppLoadContext> | AppLoadContext;
23
+ type GetLoadContextFunction_V8 = (request: Request, context: Context) => Promise<RouterContextProvider> | RouterContextProvider;
24
+ type RequestHandler = (request: Request, context: Context) => Promise<Response>;
25
+ /**
26
+ * An instance of `ReactContextProvider` providing access to
27
+ * [Netlify request context]{@link https://docs.netlify.com/build/functions/api/#netlify-specific-context-object}
28
+ *
29
+ * @example context.get(netlifyRouterContext).geo?.country?.name
12
30
  */
13
- type GetLoadContextFunction = (request: Request, context: Context) => Promise<LoadContext> | LoadContext;
14
- type RequestHandler = (request: Request, context: LoadContext) => Promise<Response | void>;
31
+ declare const netlifyRouterContext: react_router.RouterContext<Context>;
15
32
  /**
16
33
  * Given a build and a callback to get the base loader context, this returns
17
34
  * a Netlify Function handler (https://docs.netlify.com/functions/overview/) which renders the
@@ -26,4 +43,4 @@ declare function createRequestHandler({ build, mode, getLoadContext, }: {
26
43
 
27
44
  declare function netlifyPlugin(): Plugin;
28
45
 
29
- export { type GetLoadContextFunction, type RequestHandler, createRequestHandler, netlifyPlugin as default };
46
+ export { type GetLoadContextFunction, type RequestHandler, createRequestHandler, netlifyPlugin as default, netlifyRouterContext };
package/dist/index.d.ts CHANGED
@@ -1,17 +1,34 @@
1
- import { ServerBuild, AppLoadContext } from 'react-router';
1
+ import * as react_router from 'react-router';
2
+ import { AppLoadContext, RouterContextProvider, ServerBuild } from 'react-router';
2
3
  import { Context } from '@netlify/functions';
3
4
  import { Plugin } from 'vite';
4
5
 
5
- type LoadContext = AppLoadContext & Context;
6
+ declare module 'react-router' {
7
+ interface AppLoadContext extends Context {
8
+ }
9
+ }
6
10
  /**
7
- * A function that returns the value to use as `context` in route `loader` and
8
- * `action` functions.
11
+ * A function that returns the value to use as `context` in route `loader` and `action` functions.
9
12
  *
10
- * You can think of this as an escape hatch that allows you to pass
11
- * environment/platform-specific values through to your loader/action.
13
+ * You can think of this as an escape hatch that allows you to pass environment/platform-specific
14
+ * values through to your loader/action.
15
+ *
16
+ * NOTE: v7.9.0 introduced a breaking change when the user opts in to `future.v8_middleware`. This
17
+ * requires returning an instance of `RouterContextProvider` instead of a plain object. We have a
18
+ * peer dependency on >=7.9.0 so we can safely *import* these, but we cannot assume the user has
19
+ * opted in to the flag.
20
+ */
21
+ type GetLoadContextFunction = GetLoadContextFunction_V7 | GetLoadContextFunction_V8;
22
+ type GetLoadContextFunction_V7 = (request: Request, context: Context) => Promise<AppLoadContext> | AppLoadContext;
23
+ type GetLoadContextFunction_V8 = (request: Request, context: Context) => Promise<RouterContextProvider> | RouterContextProvider;
24
+ type RequestHandler = (request: Request, context: Context) => Promise<Response>;
25
+ /**
26
+ * An instance of `ReactContextProvider` providing access to
27
+ * [Netlify request context]{@link https://docs.netlify.com/build/functions/api/#netlify-specific-context-object}
28
+ *
29
+ * @example context.get(netlifyRouterContext).geo?.country?.name
12
30
  */
13
- type GetLoadContextFunction = (request: Request, context: Context) => Promise<LoadContext> | LoadContext;
14
- type RequestHandler = (request: Request, context: LoadContext) => Promise<Response | void>;
31
+ declare const netlifyRouterContext: react_router.RouterContext<Context>;
15
32
  /**
16
33
  * Given a build and a callback to get the base loader context, this returns
17
34
  * a Netlify Function handler (https://docs.netlify.com/functions/overview/) which renders the
@@ -26,4 +43,4 @@ declare function createRequestHandler({ build, mode, getLoadContext, }: {
26
43
 
27
44
  declare function netlifyPlugin(): Plugin;
28
45
 
29
- export { type GetLoadContextFunction, type RequestHandler, createRequestHandler, netlifyPlugin as default };
46
+ export { type GetLoadContextFunction, type RequestHandler, createRequestHandler, netlifyPlugin as default, netlifyRouterContext };
package/dist/index.js CHANGED
@@ -18,15 +18,17 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
 
20
20
  // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
23
  createRequestHandler: () => createRequestHandler,
24
- default: () => netlifyPlugin
24
+ default: () => netlifyPlugin,
25
+ netlifyRouterContext: () => netlifyRouterContext
25
26
  });
26
- module.exports = __toCommonJS(src_exports);
27
+ module.exports = __toCommonJS(index_exports);
27
28
 
28
29
  // src/server.ts
29
30
  var import_react_router = require("react-router");
31
+ var netlifyRouterContext = (0, import_react_router.createContext)();
30
32
  function createRequestHandler({
31
33
  build,
32
34
  mode,
@@ -37,8 +39,14 @@ function createRequestHandler({
37
39
  const start = Date.now();
38
40
  console.log(`[${request.method}] ${request.url}`);
39
41
  try {
40
- const mergedLoadContext = await getLoadContext?.(request, netlifyContext) || netlifyContext;
41
- const response = await reactRouterHandler(request, mergedLoadContext);
42
+ const getDefaultReactRouterContext = () => {
43
+ const ctx = new import_react_router.RouterContextProvider();
44
+ ctx.set(netlifyRouterContext, netlifyContext);
45
+ Object.assign(ctx, netlifyContext);
46
+ return ctx;
47
+ };
48
+ const reactRouterContext = await getLoadContext?.(request, netlifyContext) ?? getDefaultReactRouterContext();
49
+ const response = await reactRouterHandler(request, reactRouterContext);
42
50
  response.headers.set("x-nf-runtime", "Node");
43
51
  console.log(`[${response.status}] ${request.url} (${Date.now() - start}ms)`);
44
52
  return response;
@@ -56,7 +64,7 @@ var import_posix = require("path/posix");
56
64
 
57
65
  // package.json
58
66
  var name = "@netlify/vite-plugin-react-router";
59
- var version = "1.0.0";
67
+ var version = "2.0.0";
60
68
 
61
69
  // src/plugin.ts
62
70
  var NETLIFY_FUNCTIONS_DIR = ".netlify/v1/functions";
@@ -72,7 +80,6 @@ import { createRequestHandler } from "@netlify/vite-plugin-react-router";
72
80
  import * as build from "virtual:react-router/server-build";
73
81
  export default createRequestHandler({
74
82
  build,
75
- getLoadContext: async (_req, ctx) => ctx,
76
83
  });
77
84
  `
78
85
  );
@@ -142,5 +149,6 @@ function netlifyPlugin() {
142
149
  }
143
150
  // Annotate the CommonJS export names for ESM import in node:
144
151
  0 && (module.exports = {
145
- createRequestHandler
152
+ createRequestHandler,
153
+ netlifyRouterContext
146
154
  });
package/dist/index.mjs CHANGED
@@ -1,5 +1,10 @@
1
1
  // src/server.ts
2
- import { createRequestHandler as createReactRouterRequestHandler } from "react-router";
2
+ import {
3
+ createContext,
4
+ RouterContextProvider,
5
+ createRequestHandler as createReactRouterRequestHandler
6
+ } from "react-router";
7
+ var netlifyRouterContext = createContext();
3
8
  function createRequestHandler({
4
9
  build,
5
10
  mode,
@@ -10,8 +15,14 @@ function createRequestHandler({
10
15
  const start = Date.now();
11
16
  console.log(`[${request.method}] ${request.url}`);
12
17
  try {
13
- const mergedLoadContext = await getLoadContext?.(request, netlifyContext) || netlifyContext;
14
- const response = await reactRouterHandler(request, mergedLoadContext);
18
+ const getDefaultReactRouterContext = () => {
19
+ const ctx = new RouterContextProvider();
20
+ ctx.set(netlifyRouterContext, netlifyContext);
21
+ Object.assign(ctx, netlifyContext);
22
+ return ctx;
23
+ };
24
+ const reactRouterContext = await getLoadContext?.(request, netlifyContext) ?? getDefaultReactRouterContext();
25
+ const response = await reactRouterHandler(request, reactRouterContext);
15
26
  response.headers.set("x-nf-runtime", "Node");
16
27
  console.log(`[${response.status}] ${request.url} (${Date.now() - start}ms)`);
17
28
  return response;
@@ -29,7 +40,7 @@ import { sep as posixSep } from "node:path/posix";
29
40
 
30
41
  // package.json
31
42
  var name = "@netlify/vite-plugin-react-router";
32
- var version = "1.0.0";
43
+ var version = "2.0.0";
33
44
 
34
45
  // src/plugin.ts
35
46
  var NETLIFY_FUNCTIONS_DIR = ".netlify/v1/functions";
@@ -45,7 +56,6 @@ import { createRequestHandler } from "@netlify/vite-plugin-react-router";
45
56
  import * as build from "virtual:react-router/server-build";
46
57
  export default createRequestHandler({
47
58
  build,
48
- getLoadContext: async (_req, ctx) => ctx,
49
59
  });
50
60
  `
51
61
  );
@@ -115,5 +125,6 @@ function netlifyPlugin() {
115
125
  }
116
126
  export {
117
127
  createRequestHandler,
118
- netlifyPlugin as default
128
+ netlifyPlugin as default,
129
+ netlifyRouterContext
119
130
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/vite-plugin-react-router",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "React Router 7+ Vite plugin for Netlify",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",
@@ -40,20 +40,20 @@
40
40
  },
41
41
  "homepage": "https://github.com/netlify/remix-compute#readme",
42
42
  "dependencies": {
43
- "@react-router/node": "^7.0.1",
44
- "isbot": "^5.0.0",
45
- "react-router": "^7.0.1"
43
+ "isbot": "^5.0.0"
46
44
  },
47
45
  "devDependencies": {
48
- "@netlify/functions": "^2.8.1",
46
+ "@netlify/functions": "^3.1.9",
49
47
  "@types/react": "^18.0.27",
50
48
  "@types/react-dom": "^18.0.10",
51
49
  "react": "^18.2.0",
52
50
  "react-dom": "^18.2.0",
51
+ "react-router": "^7.9.4",
53
52
  "tsup": "^8.0.2",
54
- "vite": "^5.4.11"
53
+ "vite": "^6.2.5"
55
54
  },
56
55
  "peerDependencies": {
56
+ "react-router": ">=7.9.0",
57
57
  "vite": ">=5.0.0"
58
58
  },
59
59
  "engines": {