@netlify/vite-plugin-react-router 2.0.1 → 2.1.1

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,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.1.1](https://github.com/netlify/remix-compute/compare/vite-plugin-react-router-v2.1.0...vite-plugin-react-router-v2.1.1) (2025-11-06)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **@netlify/vite-plugin-react-router:** fix local dev with `edge: true` ([#572](https://github.com/netlify/remix-compute/issues/572)) ([dfb27c1](https://github.com/netlify/remix-compute/commit/dfb27c1cb52d253063b2c19dd52b05fb5ec8f4ce))
9
+
10
+ ## [2.1.0](https://github.com/netlify/remix-compute/compare/vite-plugin-react-router-v2.0.1...vite-plugin-react-router-v2.1.0) (2025-11-05)
11
+
12
+
13
+ ### Features
14
+
15
+ * **@netlify/vite-plugin-react-router:** add edge support ([#562](https://github.com/netlify/remix-compute/issues/562)) ([bbcb41e](https://github.com/netlify/remix-compute/commit/bbcb41e9d6ffdb5483759fbb94fb5258092adf87))
16
+
3
17
  ## [2.0.1](https://github.com/netlify/remix-compute/compare/vite-plugin-react-router-v2.0.0...vite-plugin-react-router-v2.0.1) (2025-10-20)
4
18
 
5
19
 
package/README.md CHANGED
@@ -1,14 +1,13 @@
1
1
  # React Router Adapter for Netlify
2
2
 
3
- The React Router Adapter for Netlify allows you to deploy your [React Router](https://reactrouter.com) app to
4
- [Netlify Functions](https://docs.netlify.com/functions/overview/).
3
+ The React Router Adapter for Netlify allows you to deploy your [React Router](https://reactrouter.com) app to Netlify.
5
4
 
6
5
  ## How to use
7
6
 
8
7
  To deploy a React Router 7+ site to Netlify, install this package:
9
8
 
10
9
  ```sh
11
- npm install --save-dev @netlify/vite-plugin-react-router
10
+ npm install @netlify/vite-plugin-react-router
12
11
  ```
13
12
 
14
13
  It's also recommended (but not required) to use the
@@ -38,6 +37,79 @@ export default defineConfig({
38
37
  })
39
38
  ```
40
39
 
40
+ Your app is ready to [deploy to Netlify](https://docs.netlify.com/deploy/create-deploys/).
41
+
42
+ ### Deploying to Edge Functions
43
+
44
+ By default, this plugin deploys your React Router app to
45
+ [Netlify Functions](https://docs.netlify.com/functions/overview/) (Node.js runtime). You can optionally deploy to
46
+ [Netlify Edge Functions](https://docs.netlify.com/edge-functions/overview/) (Deno runtime) instead.
47
+
48
+ First, toggle the `edge` option:
49
+
50
+ ```typescript
51
+ export default defineConfig({
52
+ plugins: [
53
+ reactRouter(),
54
+ tsconfigPaths(),
55
+ netlifyReactRouter({ edge: true }), // <- deploy to Edge Functions
56
+ netlify(),
57
+ ],
58
+ })
59
+ ```
60
+
61
+ Second, you **must** provide an `app/entry.server.tsx` (or `.jsx`) file. Create a file with the following content:
62
+
63
+ ```tsx
64
+ export { default } from 'virtual:netlify-server-entry'
65
+ ```
66
+
67
+ > [!TIP]
68
+ >
69
+ > If you prefer to avoid a `@ts-ignore` here, add this to `vite-env.d.ts` in your project root (or anywhere you prefer):
70
+ >
71
+ > ```typescript
72
+ > declare module 'virtual:netlify-server-entry' {
73
+ > import type { ServerEntryModule } from 'react-router'
74
+ > const entry: ServerEntryModule
75
+ > export default entry
76
+ > }
77
+ > ```
78
+
79
+ Finally, if you have your own Netlify Functions (typically in `netlify/functions`) for which you've configured a `path`,
80
+ you must exclude those paths to avoid conflicts with the generated React Router SSR handler:
81
+
82
+ ```typescript
83
+ export default defineConfig({
84
+ plugins: [
85
+ reactRouter(),
86
+ tsconfigPaths(),
87
+ netlifyReactRouter({
88
+ edge: true,
89
+ excludedPaths: ['/ping', '/api/*', '/webhooks/*'],
90
+ }),
91
+ netlify(),
92
+ ],
93
+ })
94
+ ```
95
+
96
+ #### Moving back from Edge Functions to Functions
97
+
98
+ To switch from Edge Functions back to Functions, you must:
99
+
100
+ 1. Remove the `edge: true` option from your `vite.config.ts`
101
+ 2. **Delete the `app/entry.server.tsx` file** (React Router will use its default Node.js-compatible entry)
102
+
103
+ #### Edge runtime
104
+
105
+ Before deploying to Edge Functions, review the Netlify Edge Functions documentation for important details:
106
+
107
+ - [Runtime environment](https://docs.netlify.com/build/edge-functions/api/#runtime-environment) - Understand the Deno
108
+ runtime
109
+ - [Supported Web APIs](https://docs.netlify.com/build/edge-functions/api/#supported-web-apis) - Check which APIs are
110
+ available
111
+ - [Limitations](https://docs.netlify.com/build/edge-functions/limits/) - Be aware of resource limits and constraints
112
+
41
113
  ### Load context
42
114
 
43
115
  This plugin automatically includes all
@@ -71,7 +143,8 @@ type-safe `RouterContextProvider`. Note that this requires requires v2.0.0+ of `
71
143
  For example:
72
144
 
73
145
  ```tsx
74
- import { netlifyRouterContext } from '@netlify/vite-plugin-react-router'
146
+ import { netlifyRouterContext } from '@netlify/vite-plugin-react-router/serverless'
147
+ // NOTE: if setting `edge: true`, import from /edge ^ instead here
75
148
  import { useLoaderData } from 'react-router'
76
149
  import type { Route } from './+types/example'
77
150
 
@@ -101,10 +174,11 @@ To use middleware,
101
174
  that this requires requires v2.0.0+ of `@netlify/vite-plugin-react-router`.
102
175
 
103
176
  To access the [Netlify context](https://docs.netlify.com/build/functions/api/#netlify-specific-context-object)
104
- specifically, you must import our `RouterContextProvider` instance:
177
+ specifically, you must import our `RouterContext` instance:
105
178
 
106
179
  ```tsx
107
- import { netlifyRouterContext } from '@netlify/vite-plugin-react-router'
180
+ import { netlifyRouterContext } from '@netlify/vite-plugin-react-router/serverless'
181
+ // NOTE: if setting `edge: true`, import from /edge ^ instead here
108
182
 
109
183
  import type { Route } from './+types/home'
110
184
 
@@ -0,0 +1,25 @@
1
+ import {
2
+ createNetlifyRequestHandler,
3
+ createNetlifyRouterContext
4
+ } from "./chunk-J5PMA2AP.mjs";
5
+
6
+ // src/runtimes/netlify-functions.ts
7
+ var netlifyRouterContext = createNetlifyRouterContext();
8
+ function createRequestHandler({
9
+ build,
10
+ mode,
11
+ getLoadContext
12
+ }) {
13
+ return createNetlifyRequestHandler({
14
+ build,
15
+ mode,
16
+ getLoadContext,
17
+ netlifyRouterContext,
18
+ runtimeName: "Node"
19
+ });
20
+ }
21
+
22
+ export {
23
+ netlifyRouterContext,
24
+ createRequestHandler
25
+ };
@@ -0,0 +1,70 @@
1
+ // src/lib/handler.ts
2
+ import {
3
+ RouterContextProvider,
4
+ createRequestHandler as createReactRouterRequestHandler
5
+ } from "react-router";
6
+ function createNetlifyRequestHandler({
7
+ build,
8
+ mode,
9
+ getLoadContext,
10
+ netlifyRouterContext,
11
+ runtimeName
12
+ }) {
13
+ const reactRouterHandler = createReactRouterRequestHandler(build, mode);
14
+ return async (request, netlifyContext) => {
15
+ const start = Date.now();
16
+ console.log(`[${request.method}] ${request.url}`);
17
+ try {
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);
26
+ response.headers.set("x-nf-runtime", runtimeName);
27
+ console.log(`[${response.status}] ${request.url} (${Date.now() - start}ms)`);
28
+ return response;
29
+ } catch (error) {
30
+ console.error(error);
31
+ return new Response("Internal Error", { status: 500 });
32
+ }
33
+ };
34
+ }
35
+
36
+ // src/lib/context.ts
37
+ import { createContext } from "react-router";
38
+ function createNetlifyRouterContext() {
39
+ return createContext(
40
+ new Proxy(
41
+ // Can't reference `Netlify.context` here because it isn't set outside of a request lifecycle
42
+ {},
43
+ {
44
+ get(_target, prop, receiver) {
45
+ return Reflect.get(Netlify.context ?? {}, prop, receiver);
46
+ },
47
+ set(_target, prop, value, receiver) {
48
+ return Reflect.set(Netlify.context ?? {}, prop, value, receiver);
49
+ },
50
+ has(_target, prop) {
51
+ return Reflect.has(Netlify.context ?? {}, prop);
52
+ },
53
+ deleteProperty(_target, prop) {
54
+ return Reflect.deleteProperty(Netlify.context ?? {}, prop);
55
+ },
56
+ ownKeys(_target) {
57
+ return Reflect.ownKeys(Netlify.context ?? {});
58
+ },
59
+ getOwnPropertyDescriptor(_target, prop) {
60
+ return Reflect.getOwnPropertyDescriptor(Netlify.context ?? {}, prop);
61
+ }
62
+ }
63
+ )
64
+ );
65
+ }
66
+
67
+ export {
68
+ createNetlifyRequestHandler,
69
+ createNetlifyRouterContext
70
+ };
@@ -0,0 +1,29 @@
1
+ import * as react_router from 'react-router';
2
+ import { ServerBuild } from 'react-router';
3
+ import { Context } from '@netlify/edge-functions';
4
+ import { G as GetLoadContextFunction, R as RequestHandler } from './handler-4e_lz5jw.mjs';
5
+
6
+ declare module 'react-router' {
7
+ interface AppLoadContext extends Context {
8
+ }
9
+ }
10
+ /**
11
+ * An instance of `RouterContext` providing access to
12
+ * [Netlify request context]{@link https://docs.netlify.com/build/edge-functions/api/#netlify-specific-context-object}
13
+ *
14
+ * @example context.get(netlifyRouterContext).geo?.country?.name
15
+ */
16
+ declare const netlifyRouterContext: react_router.RouterContext<Partial<Context>>;
17
+ /**
18
+ * Given a build and a callback to get the base loader context, this returns
19
+ * a Netlify Edge Function handler (https://docs.netlify.com/edge-functions/overview/) which renders the
20
+ * requested path. The loader context in this lifecycle will contain the Netlify Edge Functions context
21
+ * fields merged in.
22
+ */
23
+ declare function createRequestHandler({ build, mode, getLoadContext, }: {
24
+ build: ServerBuild;
25
+ mode?: string;
26
+ getLoadContext?: GetLoadContextFunction<Context>;
27
+ }): RequestHandler<Context>;
28
+
29
+ export { createRequestHandler, netlifyRouterContext };
package/dist/edge.mjs ADDED
@@ -0,0 +1,24 @@
1
+ import {
2
+ createNetlifyRequestHandler,
3
+ createNetlifyRouterContext
4
+ } from "./chunk-J5PMA2AP.mjs";
5
+
6
+ // src/runtimes/netlify-edge-functions.ts
7
+ var netlifyRouterContext = createNetlifyRouterContext();
8
+ function createRequestHandler({
9
+ build,
10
+ mode,
11
+ getLoadContext
12
+ }) {
13
+ return createNetlifyRequestHandler({
14
+ build,
15
+ mode,
16
+ getLoadContext,
17
+ netlifyRouterContext,
18
+ runtimeName: "edge"
19
+ });
20
+ }
21
+ export {
22
+ createRequestHandler,
23
+ netlifyRouterContext
24
+ };
@@ -0,0 +1,20 @@
1
+ import { EntryContext, AppLoadContext } from 'react-router';
2
+
3
+ /**
4
+ * Edge-compatible server entry using Web Streams instead of Node.js Streams.
5
+ * @see {@link https://reactrouter.com/api/framework-conventions/entry.server.tsx}
6
+ *
7
+ * This file was copied as-is from the React Router repository.
8
+ * @see {@link
9
+ * https://github.com/remix-run/react-router/blob/cb9a090316003988ff367bb2f2d1ef5bd03bd3af/integration/helpers/vite-plugin-cloudflare-template/app/entry.server.tsx}
10
+ *
11
+ *
12
+ * @example Export this from your `app/entry.server.tsx` when using `edge: true`:
13
+ *
14
+ * ```tsx
15
+ * export { default } from 'virtual:netlify-server-entry'
16
+ * ```
17
+ */
18
+ declare function handleRequest(request: Request, responseStatusCode: number, responseHeaders: Headers, routerContext: EntryContext, _loadContext: AppLoadContext): Promise<Response>;
19
+
20
+ export { handleRequest as default };
@@ -0,0 +1,29 @@
1
+ // src/entry.server.edge.tsx
2
+ import { ServerRouter } from "react-router";
3
+ import { isbot } from "isbot";
4
+ import { renderToReadableStream } from "react-dom/server";
5
+ import { jsx } from "react/jsx-runtime";
6
+ async function handleRequest(request, responseStatusCode, responseHeaders, routerContext, _loadContext) {
7
+ let shellRendered = false;
8
+ const userAgent = request.headers.get("user-agent");
9
+ const body = await renderToReadableStream(/* @__PURE__ */ jsx(ServerRouter, { context: routerContext, url: request.url }), {
10
+ onError(error) {
11
+ responseStatusCode = 500;
12
+ if (shellRendered) {
13
+ console.error(error);
14
+ }
15
+ }
16
+ });
17
+ shellRendered = true;
18
+ if (userAgent && isbot(userAgent) || routerContext.isSpaMode) {
19
+ await body.allReady;
20
+ }
21
+ responseHeaders.set("Content-Type", "text/html");
22
+ return new Response(body, {
23
+ headers: responseHeaders,
24
+ status: responseStatusCode
25
+ });
26
+ }
27
+ export {
28
+ handleRequest as default
29
+ };
@@ -0,0 +1,18 @@
1
+ import { RouterContextProvider, AppLoadContext } from 'react-router';
2
+
3
+ /**
4
+ * A function that returns the value to use as `context` in route `loader` and `action` functions.
5
+ *
6
+ * You can think of this as an escape hatch that allows you to pass environment/platform-specific
7
+ * values through to your loader/action.
8
+ *
9
+ * NOTE: v7.9.0 introduced a breaking change when the user opts in to `future.v8_middleware`. This
10
+ * requires returning an instance of `RouterContextProvider` instead of a plain object. We have a
11
+ * peer dependency on >=7.9.0 so we can safely *import* these, but we cannot assume the user has
12
+ * opted in to the flag.
13
+ */
14
+ type GetLoadContextFunction<TNetlifyContext> = ((request: Request, context: TNetlifyContext) => Promise<RouterContextProvider> | RouterContextProvider) | ((request: Request, context: TNetlifyContext) => Promise<AppLoadContext> | AppLoadContext);
15
+
16
+ type RequestHandler<TNetlifyContext> = (request: Request, context: TNetlifyContext) => Promise<Response>;
17
+
18
+ export type { GetLoadContextFunction as G, RequestHandler as R };
package/dist/index.d.mts CHANGED
@@ -1,46 +1,26 @@
1
- import * as react_router from 'react-router';
2
- import { AppLoadContext, RouterContextProvider, ServerBuild } from 'react-router';
3
- import { Context } from '@netlify/functions';
1
+ export { GetLoadContextFunction, RequestHandler, createRequestHandler, netlifyRouterContext } from './serverless.mjs';
4
2
  import { Plugin } from 'vite';
3
+ import 'react-router';
4
+ import '@netlify/functions';
5
+ import './handler-4e_lz5jw.mjs';
5
6
 
6
- declare module 'react-router' {
7
- interface AppLoadContext extends Context {
8
- }
7
+ interface NetlifyPluginOptions {
8
+ /**
9
+ * Deploy to Netlify Edge Functions instead of Netlify Functions.
10
+ * @default false
11
+ */
12
+ edge?: boolean;
13
+ /**
14
+ * Paths to exclude from being handled by the React Router handler.
15
+ *
16
+ * @IMPORTANT If you have opted in to edge rendering with `edge: true` and you have your own Netlify
17
+ * Functions running on custom `path`s, you must exclude those paths here to avoid conflicts.
18
+ *
19
+ * @type {URLPattern[]}
20
+ * @default []
21
+ */
22
+ excludedPaths?: string[];
9
23
  }
10
- /**
11
- * A function that returns the value to use as `context` in route `loader` and `action` functions.
12
- *
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
30
- */
31
- declare const netlifyRouterContext: react_router.RouterContext<Partial<Context>>;
32
- /**
33
- * Given a build and a callback to get the base loader context, this returns
34
- * a Netlify Function handler (https://docs.netlify.com/functions/overview/) which renders the
35
- * requested path. The loader context in this lifecycle will contain the Netlify Functions context
36
- * fields merged in.
37
- */
38
- declare function createRequestHandler({ build, mode, getLoadContext, }: {
39
- build: ServerBuild;
40
- mode?: string;
41
- getLoadContext?: GetLoadContextFunction;
42
- }): RequestHandler;
24
+ declare function netlifyPlugin(options?: NetlifyPluginOptions): Plugin;
43
25
 
44
- declare function netlifyPlugin(): Plugin;
45
-
46
- export { type GetLoadContextFunction, type RequestHandler, createRequestHandler, netlifyPlugin as default, netlifyRouterContext };
26
+ export { netlifyPlugin as default };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,8 @@
1
1
  import * as react_router from 'react-router';
2
- import { AppLoadContext, RouterContextProvider, ServerBuild } from 'react-router';
2
+ import { RouterContextProvider, AppLoadContext, ServerBuild } from 'react-router';
3
3
  import { Context } from '@netlify/functions';
4
4
  import { Plugin } from 'vite';
5
5
 
6
- declare module 'react-router' {
7
- interface AppLoadContext extends Context {
8
- }
9
- }
10
6
  /**
11
7
  * A function that returns the value to use as `context` in route `loader` and `action` functions.
12
8
  *
@@ -18,12 +14,18 @@ declare module 'react-router' {
18
14
  * peer dependency on >=7.9.0 so we can safely *import* these, but we cannot assume the user has
19
15
  * opted in to the flag.
20
16
  */
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>;
17
+ type GetLoadContextFunction$1<TNetlifyContext> = ((request: Request, context: TNetlifyContext) => Promise<RouterContextProvider> | RouterContextProvider) | ((request: Request, context: TNetlifyContext) => Promise<AppLoadContext> | AppLoadContext);
18
+
19
+ type RequestHandler$1<TNetlifyContext> = (request: Request, context: TNetlifyContext) => Promise<Response>;
20
+
21
+ declare module 'react-router' {
22
+ interface AppLoadContext extends Context {
23
+ }
24
+ }
25
+ type GetLoadContextFunction = GetLoadContextFunction$1<Context>;
26
+ type RequestHandler = RequestHandler$1<Context>;
25
27
  /**
26
- * An instance of `ReactContextProvider` providing access to
28
+ * An instance of `RouterContext` providing access to
27
29
  * [Netlify request context]{@link https://docs.netlify.com/build/functions/api/#netlify-specific-context-object}
28
30
  *
29
31
  * @example context.get(netlifyRouterContext).geo?.country?.name
@@ -41,6 +43,23 @@ declare function createRequestHandler({ build, mode, getLoadContext, }: {
41
43
  getLoadContext?: GetLoadContextFunction;
42
44
  }): RequestHandler;
43
45
 
44
- declare function netlifyPlugin(): Plugin;
46
+ interface NetlifyPluginOptions {
47
+ /**
48
+ * Deploy to Netlify Edge Functions instead of Netlify Functions.
49
+ * @default false
50
+ */
51
+ edge?: boolean;
52
+ /**
53
+ * Paths to exclude from being handled by the React Router handler.
54
+ *
55
+ * @IMPORTANT If you have opted in to edge rendering with `edge: true` and you have your own Netlify
56
+ * Functions running on custom `path`s, you must exclude those paths here to avoid conflicts.
57
+ *
58
+ * @type {URLPattern[]}
59
+ * @default []
60
+ */
61
+ excludedPaths?: string[];
62
+ }
63
+ declare function netlifyPlugin(options?: NetlifyPluginOptions): Plugin;
45
64
 
46
65
  export { type GetLoadContextFunction, type RequestHandler, createRequestHandler, netlifyPlugin as default, netlifyRouterContext };
package/dist/index.js CHANGED
@@ -26,13 +26,42 @@ __export(index_exports, {
26
26
  });
27
27
  module.exports = __toCommonJS(index_exports);
28
28
 
29
- // src/server.ts
29
+ // src/lib/handler.ts
30
30
  var import_react_router = require("react-router");
31
- var netlifyRouterContext = (
32
- // We must use a singleton because Remix contexts rely on referential equality.
33
- // We can't hook into the request lifecycle in dev mode, so we use a Proxy to always read from the
34
- // current `Netlify.context` value, which is always contextual to the in-flight request.
35
- (0, import_react_router.createContext)(
31
+ function createNetlifyRequestHandler({
32
+ build,
33
+ mode,
34
+ getLoadContext,
35
+ netlifyRouterContext: netlifyRouterContext2,
36
+ runtimeName
37
+ }) {
38
+ const reactRouterHandler = (0, import_react_router.createRequestHandler)(build, mode);
39
+ return async (request, netlifyContext) => {
40
+ const start = Date.now();
41
+ console.log(`[${request.method}] ${request.url}`);
42
+ try {
43
+ const getDefaultReactRouterContext = () => {
44
+ const ctx = new import_react_router.RouterContextProvider();
45
+ ctx.set(netlifyRouterContext2, netlifyContext);
46
+ Object.assign(ctx, netlifyContext);
47
+ return ctx;
48
+ };
49
+ const reactRouterContext = await getLoadContext?.(request, netlifyContext) ?? getDefaultReactRouterContext();
50
+ const response = await reactRouterHandler(request, reactRouterContext);
51
+ response.headers.set("x-nf-runtime", runtimeName);
52
+ console.log(`[${response.status}] ${request.url} (${Date.now() - start}ms)`);
53
+ return response;
54
+ } catch (error) {
55
+ console.error(error);
56
+ return new Response("Internal Error", { status: 500 });
57
+ }
58
+ };
59
+ }
60
+
61
+ // src/lib/context.ts
62
+ var import_react_router2 = require("react-router");
63
+ function createNetlifyRouterContext() {
64
+ return (0, import_react_router2.createContext)(
36
65
  new Proxy(
37
66
  // Can't reference `Netlify.context` here because it isn't set outside of a request lifecycle
38
67
  {},
@@ -57,34 +86,23 @@ var netlifyRouterContext = (
57
86
  }
58
87
  }
59
88
  )
60
- )
61
- );
89
+ );
90
+ }
91
+
92
+ // src/runtimes/netlify-functions.ts
93
+ var netlifyRouterContext = createNetlifyRouterContext();
62
94
  function createRequestHandler({
63
95
  build,
64
96
  mode,
65
97
  getLoadContext
66
98
  }) {
67
- const reactRouterHandler = (0, import_react_router.createRequestHandler)(build, mode);
68
- return async (request, netlifyContext) => {
69
- const start = Date.now();
70
- console.log(`[${request.method}] ${request.url}`);
71
- try {
72
- const getDefaultReactRouterContext = () => {
73
- const ctx = new import_react_router.RouterContextProvider();
74
- ctx.set(netlifyRouterContext, netlifyContext);
75
- Object.assign(ctx, netlifyContext);
76
- return ctx;
77
- };
78
- const reactRouterContext = await getLoadContext?.(request, netlifyContext) ?? getDefaultReactRouterContext();
79
- const response = await reactRouterHandler(request, reactRouterContext);
80
- response.headers.set("x-nf-runtime", "Node");
81
- console.log(`[${response.status}] ${request.url} (${Date.now() - start}ms)`);
82
- return response;
83
- } catch (error) {
84
- console.error(error);
85
- return new Response("Internal Error", { status: 500 });
86
- }
87
- };
99
+ return createNetlifyRequestHandler({
100
+ build,
101
+ mode,
102
+ getLoadContext,
103
+ netlifyRouterContext,
104
+ runtimeName: "Node"
105
+ });
88
106
  }
89
107
 
90
108
  // src/plugin.ts
@@ -94,26 +112,38 @@ var import_posix = require("path/posix");
94
112
 
95
113
  // package.json
96
114
  var name = "@netlify/vite-plugin-react-router";
97
- var version = "2.0.1";
115
+ var version = "2.1.1";
98
116
 
99
117
  // src/plugin.ts
100
118
  var NETLIFY_FUNCTIONS_DIR = ".netlify/v1/functions";
119
+ var NETLIFY_EDGE_FUNCTIONS_DIR = ".netlify/v1/edge-functions";
101
120
  var FUNCTION_FILENAME = "react-router-server.mjs";
102
121
  var FUNCTION_HANDLER_CHUNK = "server";
103
122
  var FUNCTION_HANDLER_MODULE_ID = "virtual:netlify-server";
104
123
  var RESOLVED_FUNCTION_HANDLER_MODULE_ID = `\0${FUNCTION_HANDLER_MODULE_ID}`;
124
+ var SERVER_ENTRY_MODULE_ID = "virtual:netlify-server-entry";
105
125
  var toPosixPath = (path) => path.split(import_node_path.sep).join(import_posix.sep);
106
126
  var FUNCTION_HANDLER = (
107
127
  /* js */
108
128
  `
109
- import { createRequestHandler } from "@netlify/vite-plugin-react-router";
129
+ import { createRequestHandler } from "@netlify/vite-plugin-react-router/serverless";
110
130
  import * as build from "virtual:react-router/server-build";
111
131
  export default createRequestHandler({
112
132
  build,
113
133
  });
114
134
  `
115
135
  );
116
- function generateNetlifyFunction(handlerPath) {
136
+ var EDGE_FUNCTION_HANDLER = (
137
+ /* js */
138
+ `
139
+ import { createRequestHandler } from "@netlify/vite-plugin-react-router/edge";
140
+ import * as build from "virtual:react-router/server-build";
141
+ export default createRequestHandler({
142
+ build,
143
+ });
144
+ `
145
+ );
146
+ function generateNetlifyFunction(handlerPath, excludedPath) {
117
147
  return (
118
148
  /* js */
119
149
  `
@@ -123,17 +153,38 @@ function generateNetlifyFunction(handlerPath) {
123
153
  name: "React Router server handler",
124
154
  generator: "${name}@${version}",
125
155
  path: "/*",
156
+ excludedPath: ${JSON.stringify(excludedPath)},
126
157
  preferStatic: true,
127
158
  };
128
159
  `
129
160
  );
130
161
  }
131
- function netlifyPlugin() {
162
+ function generateEdgeFunction(handlerPath, excludedPath) {
163
+ return (
164
+ /* js */
165
+ `
166
+ export { default } from "${handlerPath}";
167
+
168
+ export const config = {
169
+ name: "React Router server handler",
170
+ generator: "${name}@${version}",
171
+ cache: "manual",
172
+ path: "/*",
173
+ excludedPath: ${JSON.stringify(excludedPath)},
174
+ };
175
+ `
176
+ );
177
+ }
178
+ function netlifyPlugin(options = {}) {
179
+ const edge = options.edge ?? false;
180
+ const additionalExcludedPaths = options.excludedPaths ?? [];
132
181
  let resolvedConfig;
133
182
  let isProductionSsrBuild = false;
183
+ let currentCommand;
134
184
  return {
135
185
  name: "vite-plugin-netlify-react-router",
136
186
  config(config, { command, isSsrBuild }) {
187
+ currentCommand = command;
137
188
  isProductionSsrBuild = isSsrBuild === true && command === "build";
138
189
  if (isProductionSsrBuild) {
139
190
  config.build ??= {};
@@ -149,17 +200,40 @@ function netlifyPlugin() {
149
200
  config.build.rollupOptions.output = {};
150
201
  }
151
202
  config.build.rollupOptions.output.entryFileNames = "[name].js";
203
+ if (edge) {
204
+ config.ssr = {
205
+ ...config.ssr,
206
+ target: "webworker",
207
+ // Bundle everything except Node.js built-ins (which are supported but must use the `node:` prefix):
208
+ // https://docs.netlify.com/build/edge-functions/api/#runtime-environment
209
+ noExternal: /^(?!node:).*$/,
210
+ resolve: {
211
+ ...config.resolve,
212
+ conditions: ["worker", "deno", "browser"]
213
+ }
214
+ };
215
+ }
152
216
  }
153
217
  },
154
- async resolveId(source) {
218
+ async resolveId(source, importer, options2) {
155
219
  if (source === FUNCTION_HANDLER_MODULE_ID) {
156
220
  return RESOLVED_FUNCTION_HANDLER_MODULE_ID;
157
221
  }
222
+ if (source === SERVER_ENTRY_MODULE_ID && edge) {
223
+ if (currentCommand === "serve") {
224
+ const reactRouterDev = await this.resolve("@react-router/dev/config", importer, options2);
225
+ if (!reactRouterDev) {
226
+ throw new Error("The @react-router/dev package is required for local development. Please install it.");
227
+ }
228
+ return (0, import_node_path.resolve)((0, import_node_path.dirname)(reactRouterDev.id), "config/defaults/entry.server.node.tsx");
229
+ }
230
+ return this.resolve("@netlify/vite-plugin-react-router/entry.server.edge", importer, options2);
231
+ }
158
232
  },
159
233
  // See https://vitejs.dev/guide/api-plugin#virtual-modules-convention.
160
234
  load(id) {
161
235
  if (id === RESOLVED_FUNCTION_HANDLER_MODULE_ID) {
162
- return FUNCTION_HANDLER;
236
+ return edge ? EDGE_FUNCTION_HANDLER : FUNCTION_HANDLER;
163
237
  }
164
238
  },
165
239
  async configResolved(config) {
@@ -168,11 +242,32 @@ function netlifyPlugin() {
168
242
  // See https://rollupjs.org/plugin-development/#writebundle.
169
243
  async writeBundle() {
170
244
  if (isProductionSsrBuild) {
171
- const functionsDirectory = (0, import_node_path.join)(resolvedConfig.root, NETLIFY_FUNCTIONS_DIR);
172
- await (0, import_promises.mkdir)(functionsDirectory, { recursive: true });
173
245
  const handlerPath = (0, import_node_path.join)(resolvedConfig.build.outDir, `${FUNCTION_HANDLER_CHUNK}.js`);
174
- const relativeHandlerPath = toPosixPath((0, import_node_path.relative)(functionsDirectory, handlerPath));
175
- await (0, import_promises.writeFile)((0, import_node_path.join)(functionsDirectory, FUNCTION_FILENAME), generateNetlifyFunction(relativeHandlerPath));
246
+ if (edge) {
247
+ const clientDir = (0, import_node_path.join)(resolvedConfig.build.outDir, "..", "client");
248
+ const entries = await (0, import_promises.readdir)(clientDir, { withFileTypes: true });
249
+ const excludedPath = [
250
+ "/.netlify/*",
251
+ ...entries.map((entry) => entry.isDirectory() ? `/${entry.name}/*` : `/${entry.name}`),
252
+ ...additionalExcludedPaths
253
+ ];
254
+ const edgeFunctionsDir = (0, import_node_path.join)(resolvedConfig.root, NETLIFY_EDGE_FUNCTIONS_DIR);
255
+ await (0, import_promises.mkdir)(edgeFunctionsDir, { recursive: true });
256
+ const relativeHandlerPath = toPosixPath((0, import_node_path.relative)(edgeFunctionsDir, handlerPath));
257
+ await (0, import_promises.writeFile)(
258
+ (0, import_node_path.join)(edgeFunctionsDir, FUNCTION_FILENAME),
259
+ generateEdgeFunction(relativeHandlerPath, excludedPath)
260
+ );
261
+ } else {
262
+ const functionsDir = (0, import_node_path.join)(resolvedConfig.root, NETLIFY_FUNCTIONS_DIR);
263
+ await (0, import_promises.mkdir)(functionsDir, { recursive: true });
264
+ const relativeHandlerPath = toPosixPath((0, import_node_path.relative)(functionsDir, handlerPath));
265
+ const excludedPath = ["/.netlify/*", ...additionalExcludedPaths];
266
+ await (0, import_promises.writeFile)(
267
+ (0, import_node_path.join)(functionsDir, FUNCTION_FILENAME),
268
+ generateNetlifyFunction(relativeHandlerPath, excludedPath)
269
+ );
270
+ }
176
271
  }
177
272
  }
178
273
  };
package/dist/index.mjs CHANGED
@@ -1,95 +1,48 @@
1
- // src/server.ts
2
1
  import {
3
- createContext,
4
- RouterContextProvider,
5
- createRequestHandler as createReactRouterRequestHandler
6
- } from "react-router";
7
- var netlifyRouterContext = (
8
- // We must use a singleton because Remix contexts rely on referential equality.
9
- // We can't hook into the request lifecycle in dev mode, so we use a Proxy to always read from the
10
- // current `Netlify.context` value, which is always contextual to the in-flight request.
11
- createContext(
12
- new Proxy(
13
- // Can't reference `Netlify.context` here because it isn't set outside of a request lifecycle
14
- {},
15
- {
16
- get(_target, prop, receiver) {
17
- return Reflect.get(Netlify.context ?? {}, prop, receiver);
18
- },
19
- set(_target, prop, value, receiver) {
20
- return Reflect.set(Netlify.context ?? {}, prop, value, receiver);
21
- },
22
- has(_target, prop) {
23
- return Reflect.has(Netlify.context ?? {}, prop);
24
- },
25
- deleteProperty(_target, prop) {
26
- return Reflect.deleteProperty(Netlify.context ?? {}, prop);
27
- },
28
- ownKeys(_target) {
29
- return Reflect.ownKeys(Netlify.context ?? {});
30
- },
31
- getOwnPropertyDescriptor(_target, prop) {
32
- return Reflect.getOwnPropertyDescriptor(Netlify.context ?? {}, prop);
33
- }
34
- }
35
- )
36
- )
37
- );
38
- function createRequestHandler({
39
- build,
40
- mode,
41
- getLoadContext
42
- }) {
43
- const reactRouterHandler = createReactRouterRequestHandler(build, mode);
44
- return async (request, netlifyContext) => {
45
- const start = Date.now();
46
- console.log(`[${request.method}] ${request.url}`);
47
- try {
48
- const getDefaultReactRouterContext = () => {
49
- const ctx = new RouterContextProvider();
50
- ctx.set(netlifyRouterContext, netlifyContext);
51
- Object.assign(ctx, netlifyContext);
52
- return ctx;
53
- };
54
- const reactRouterContext = await getLoadContext?.(request, netlifyContext) ?? getDefaultReactRouterContext();
55
- const response = await reactRouterHandler(request, reactRouterContext);
56
- response.headers.set("x-nf-runtime", "Node");
57
- console.log(`[${response.status}] ${request.url} (${Date.now() - start}ms)`);
58
- return response;
59
- } catch (error) {
60
- console.error(error);
61
- return new Response("Internal Error", { status: 500 });
62
- }
63
- };
64
- }
2
+ createRequestHandler,
3
+ netlifyRouterContext
4
+ } from "./chunk-3EFABROO.mjs";
5
+ import "./chunk-J5PMA2AP.mjs";
65
6
 
66
7
  // src/plugin.ts
67
- import { mkdir, writeFile } from "node:fs/promises";
68
- import { join, relative, sep } from "node:path";
8
+ import { mkdir, writeFile, readdir } from "node:fs/promises";
9
+ import { dirname, join, relative, resolve, sep } from "node:path";
69
10
  import { sep as posixSep } from "node:path/posix";
70
11
 
71
12
  // package.json
72
13
  var name = "@netlify/vite-plugin-react-router";
73
- var version = "2.0.1";
14
+ var version = "2.1.1";
74
15
 
75
16
  // src/plugin.ts
76
17
  var NETLIFY_FUNCTIONS_DIR = ".netlify/v1/functions";
18
+ var NETLIFY_EDGE_FUNCTIONS_DIR = ".netlify/v1/edge-functions";
77
19
  var FUNCTION_FILENAME = "react-router-server.mjs";
78
20
  var FUNCTION_HANDLER_CHUNK = "server";
79
21
  var FUNCTION_HANDLER_MODULE_ID = "virtual:netlify-server";
80
22
  var RESOLVED_FUNCTION_HANDLER_MODULE_ID = `\0${FUNCTION_HANDLER_MODULE_ID}`;
23
+ var SERVER_ENTRY_MODULE_ID = "virtual:netlify-server-entry";
81
24
  var toPosixPath = (path) => path.split(sep).join(posixSep);
82
25
  var FUNCTION_HANDLER = (
83
26
  /* js */
84
27
  `
85
- import { createRequestHandler } from "@netlify/vite-plugin-react-router";
28
+ import { createRequestHandler } from "@netlify/vite-plugin-react-router/serverless";
86
29
  import * as build from "virtual:react-router/server-build";
87
30
  export default createRequestHandler({
88
31
  build,
89
32
  });
90
33
  `
91
34
  );
92
- function generateNetlifyFunction(handlerPath) {
35
+ var EDGE_FUNCTION_HANDLER = (
36
+ /* js */
37
+ `
38
+ import { createRequestHandler } from "@netlify/vite-plugin-react-router/edge";
39
+ import * as build from "virtual:react-router/server-build";
40
+ export default createRequestHandler({
41
+ build,
42
+ });
43
+ `
44
+ );
45
+ function generateNetlifyFunction(handlerPath, excludedPath) {
93
46
  return (
94
47
  /* js */
95
48
  `
@@ -99,17 +52,38 @@ function generateNetlifyFunction(handlerPath) {
99
52
  name: "React Router server handler",
100
53
  generator: "${name}@${version}",
101
54
  path: "/*",
55
+ excludedPath: ${JSON.stringify(excludedPath)},
102
56
  preferStatic: true,
103
57
  };
104
58
  `
105
59
  );
106
60
  }
107
- function netlifyPlugin() {
61
+ function generateEdgeFunction(handlerPath, excludedPath) {
62
+ return (
63
+ /* js */
64
+ `
65
+ export { default } from "${handlerPath}";
66
+
67
+ export const config = {
68
+ name: "React Router server handler",
69
+ generator: "${name}@${version}",
70
+ cache: "manual",
71
+ path: "/*",
72
+ excludedPath: ${JSON.stringify(excludedPath)},
73
+ };
74
+ `
75
+ );
76
+ }
77
+ function netlifyPlugin(options = {}) {
78
+ const edge = options.edge ?? false;
79
+ const additionalExcludedPaths = options.excludedPaths ?? [];
108
80
  let resolvedConfig;
109
81
  let isProductionSsrBuild = false;
82
+ let currentCommand;
110
83
  return {
111
84
  name: "vite-plugin-netlify-react-router",
112
85
  config(config, { command, isSsrBuild }) {
86
+ currentCommand = command;
113
87
  isProductionSsrBuild = isSsrBuild === true && command === "build";
114
88
  if (isProductionSsrBuild) {
115
89
  config.build ??= {};
@@ -125,17 +99,40 @@ function netlifyPlugin() {
125
99
  config.build.rollupOptions.output = {};
126
100
  }
127
101
  config.build.rollupOptions.output.entryFileNames = "[name].js";
102
+ if (edge) {
103
+ config.ssr = {
104
+ ...config.ssr,
105
+ target: "webworker",
106
+ // Bundle everything except Node.js built-ins (which are supported but must use the `node:` prefix):
107
+ // https://docs.netlify.com/build/edge-functions/api/#runtime-environment
108
+ noExternal: /^(?!node:).*$/,
109
+ resolve: {
110
+ ...config.resolve,
111
+ conditions: ["worker", "deno", "browser"]
112
+ }
113
+ };
114
+ }
128
115
  }
129
116
  },
130
- async resolveId(source) {
117
+ async resolveId(source, importer, options2) {
131
118
  if (source === FUNCTION_HANDLER_MODULE_ID) {
132
119
  return RESOLVED_FUNCTION_HANDLER_MODULE_ID;
133
120
  }
121
+ if (source === SERVER_ENTRY_MODULE_ID && edge) {
122
+ if (currentCommand === "serve") {
123
+ const reactRouterDev = await this.resolve("@react-router/dev/config", importer, options2);
124
+ if (!reactRouterDev) {
125
+ throw new Error("The @react-router/dev package is required for local development. Please install it.");
126
+ }
127
+ return resolve(dirname(reactRouterDev.id), "config/defaults/entry.server.node.tsx");
128
+ }
129
+ return this.resolve("@netlify/vite-plugin-react-router/entry.server.edge", importer, options2);
130
+ }
134
131
  },
135
132
  // See https://vitejs.dev/guide/api-plugin#virtual-modules-convention.
136
133
  load(id) {
137
134
  if (id === RESOLVED_FUNCTION_HANDLER_MODULE_ID) {
138
- return FUNCTION_HANDLER;
135
+ return edge ? EDGE_FUNCTION_HANDLER : FUNCTION_HANDLER;
139
136
  }
140
137
  },
141
138
  async configResolved(config) {
@@ -144,11 +141,32 @@ function netlifyPlugin() {
144
141
  // See https://rollupjs.org/plugin-development/#writebundle.
145
142
  async writeBundle() {
146
143
  if (isProductionSsrBuild) {
147
- const functionsDirectory = join(resolvedConfig.root, NETLIFY_FUNCTIONS_DIR);
148
- await mkdir(functionsDirectory, { recursive: true });
149
144
  const handlerPath = join(resolvedConfig.build.outDir, `${FUNCTION_HANDLER_CHUNK}.js`);
150
- const relativeHandlerPath = toPosixPath(relative(functionsDirectory, handlerPath));
151
- await writeFile(join(functionsDirectory, FUNCTION_FILENAME), generateNetlifyFunction(relativeHandlerPath));
145
+ if (edge) {
146
+ const clientDir = join(resolvedConfig.build.outDir, "..", "client");
147
+ const entries = await readdir(clientDir, { withFileTypes: true });
148
+ const excludedPath = [
149
+ "/.netlify/*",
150
+ ...entries.map((entry) => entry.isDirectory() ? `/${entry.name}/*` : `/${entry.name}`),
151
+ ...additionalExcludedPaths
152
+ ];
153
+ const edgeFunctionsDir = join(resolvedConfig.root, NETLIFY_EDGE_FUNCTIONS_DIR);
154
+ await mkdir(edgeFunctionsDir, { recursive: true });
155
+ const relativeHandlerPath = toPosixPath(relative(edgeFunctionsDir, handlerPath));
156
+ await writeFile(
157
+ join(edgeFunctionsDir, FUNCTION_FILENAME),
158
+ generateEdgeFunction(relativeHandlerPath, excludedPath)
159
+ );
160
+ } else {
161
+ const functionsDir = join(resolvedConfig.root, NETLIFY_FUNCTIONS_DIR);
162
+ await mkdir(functionsDir, { recursive: true });
163
+ const relativeHandlerPath = toPosixPath(relative(functionsDir, handlerPath));
164
+ const excludedPath = ["/.netlify/*", ...additionalExcludedPaths];
165
+ await writeFile(
166
+ join(functionsDir, FUNCTION_FILENAME),
167
+ generateNetlifyFunction(relativeHandlerPath, excludedPath)
168
+ );
169
+ }
152
170
  }
153
171
  }
154
172
  };
@@ -0,0 +1,31 @@
1
+ import * as react_router from 'react-router';
2
+ import { ServerBuild } from 'react-router';
3
+ import { Context } from '@netlify/functions';
4
+ import { G as GetLoadContextFunction$1, R as RequestHandler$1 } from './handler-4e_lz5jw.mjs';
5
+
6
+ declare module 'react-router' {
7
+ interface AppLoadContext extends Context {
8
+ }
9
+ }
10
+ type GetLoadContextFunction = GetLoadContextFunction$1<Context>;
11
+ type RequestHandler = RequestHandler$1<Context>;
12
+ /**
13
+ * An instance of `RouterContext` providing access to
14
+ * [Netlify request context]{@link https://docs.netlify.com/build/functions/api/#netlify-specific-context-object}
15
+ *
16
+ * @example context.get(netlifyRouterContext).geo?.country?.name
17
+ */
18
+ declare const netlifyRouterContext: react_router.RouterContext<Partial<Context>>;
19
+ /**
20
+ * Given a build and a callback to get the base loader context, this returns
21
+ * a Netlify Function handler (https://docs.netlify.com/functions/overview/) which renders the
22
+ * requested path. The loader context in this lifecycle will contain the Netlify Functions context
23
+ * fields merged in.
24
+ */
25
+ declare function createRequestHandler({ build, mode, getLoadContext, }: {
26
+ build: ServerBuild;
27
+ mode?: string;
28
+ getLoadContext?: GetLoadContextFunction;
29
+ }): RequestHandler;
30
+
31
+ export { type GetLoadContextFunction, type RequestHandler, createRequestHandler, netlifyRouterContext };
@@ -0,0 +1,9 @@
1
+ import {
2
+ createRequestHandler,
3
+ netlifyRouterContext
4
+ } from "./chunk-3EFABROO.mjs";
5
+ import "./chunk-J5PMA2AP.mjs";
6
+ export {
7
+ createRequestHandler,
8
+ netlifyRouterContext
9
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/vite-plugin-react-router",
3
- "version": "2.0.1",
3
+ "version": "2.1.1",
4
4
  "description": "React Router 7+ Vite plugin for Netlify",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",
@@ -16,6 +16,18 @@
16
16
  "types": "./dist/index.d.mts",
17
17
  "default": "./dist/index.mjs"
18
18
  }
19
+ },
20
+ "./serverless": {
21
+ "types": "./dist/serverless.d.mts",
22
+ "default": "./dist/serverless.mjs"
23
+ },
24
+ "./edge": {
25
+ "types": "./dist/edge.d.mts",
26
+ "default": "./dist/edge.mjs"
27
+ },
28
+ "./entry.server.edge": {
29
+ "types": "./dist/entry.server.edge.d.mts",
30
+ "default": "./dist/entry.server.edge.mjs"
19
31
  }
20
32
  },
21
33
  "files": [
@@ -40,10 +52,11 @@
40
52
  },
41
53
  "homepage": "https://github.com/netlify/remix-compute#readme",
42
54
  "dependencies": {
43
- "isbot": "^5.0.0"
55
+ "@netlify/edge-functions": "^3.0.2",
56
+ "@netlify/functions": "^5.1.0",
57
+ "isbot": "^5.1.25"
44
58
  },
45
59
  "devDependencies": {
46
- "@netlify/functions": "^3.1.9",
47
60
  "@types/react": "^18.0.27",
48
61
  "@types/react-dom": "^18.0.10",
49
62
  "react": "^18.2.0",
@@ -63,7 +76,8 @@
63
76
  "access": "public"
64
77
  },
65
78
  "scripts": {
66
- "build": "tsup-node src/index.ts --format esm,cjs --dts --target node18 --clean",
67
- "build:watch": "pnpm run build --watch"
79
+ "build": "rm -rf dist && tsup-node",
80
+ "build:watch": "pnpm run build --watch",
81
+ "publint": "publint --strict"
68
82
  }
69
83
  }