react-router-effect 2.0.0 → 2.1.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/README.md +548 -173
- package/dist/index.d.mts +2 -342
- package/dist/index.mjs +118 -30
- package/dist/rolldown-runtime-D8jQpDG7.mjs +12 -0
- package/dist/route-data-MgSnnR33.d.mts +543 -0
- package/dist/server.d.mts +218 -0
- package/dist/server.mjs +337 -0
- package/dist/vite.d.mts +27 -0
- package/dist/vite.mjs +46 -0
- package/package.json +19 -8
- package/src/action-meta.ts +58 -0
- package/src/check.ts +205 -0
- package/src/errors.ts +3 -3
- package/src/factory.ts +282 -82
- package/src/index.ts +22 -1
- package/src/route-data.ts +151 -0
- package/src/server-entry.ts +10 -0
- package/src/server.ts +647 -0
- package/src/vite-entry.ts +2 -0
- package/src/vite.ts +92 -0
package/src/vite.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs React Router's development server, Vite, in front of the Effect HTTP
|
|
3
|
+
* app on Node.
|
|
4
|
+
*
|
|
5
|
+
* In framework mode React Router builds with Vite, and in development Vite
|
|
6
|
+
* serves the client: route modules, `/@vite/client`, the files of `public/`,
|
|
7
|
+
* and its error overlay. A custom server runs Vite in middleware mode and passes
|
|
8
|
+
* it each request first. Vite's middleware is a Connect stack of Node
|
|
9
|
+
* requests and responses, so this middleware needs Effect's Node HTTP server.
|
|
10
|
+
*
|
|
11
|
+
* @since 2.1.0
|
|
12
|
+
*/
|
|
13
|
+
import type * as Http from "node:http";
|
|
14
|
+
|
|
15
|
+
import * as NodeHttpServerRequest from "@effect/platform-node/NodeHttpServerRequest";
|
|
16
|
+
import { Effect } from "effect";
|
|
17
|
+
import { HttpServerRequest, HttpServerResponse } from "effect/http";
|
|
18
|
+
|
|
19
|
+
/** The part of a Vite dev server the middleware uses: its Connect middleware stack. */
|
|
20
|
+
export interface ViteDevServer {
|
|
21
|
+
readonly middlewares: (
|
|
22
|
+
request: Http.IncomingMessage,
|
|
23
|
+
response: Http.ServerResponse,
|
|
24
|
+
next: (error?: unknown) => void,
|
|
25
|
+
) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Runs Vite's middleware on the Node request. Succeeds with `true` when Vite
|
|
30
|
+
* passes the request on, and `false` when Vite answered it, or the client left
|
|
31
|
+
* while Vite answered.
|
|
32
|
+
*/
|
|
33
|
+
const passThroughVite = (
|
|
34
|
+
vite: ViteDevServer,
|
|
35
|
+
request: Http.IncomingMessage,
|
|
36
|
+
response: Http.ServerResponse,
|
|
37
|
+
): Effect.Effect<boolean> =>
|
|
38
|
+
Effect.callback<boolean>((resume) => {
|
|
39
|
+
let settled = false;
|
|
40
|
+
const settle = (result: Effect.Effect<boolean>) => {
|
|
41
|
+
if (settled) return;
|
|
42
|
+
settled = true;
|
|
43
|
+
response.off("finish", answered);
|
|
44
|
+
response.off("close", answered);
|
|
45
|
+
resume(result);
|
|
46
|
+
};
|
|
47
|
+
const answered = () => settle(Effect.succeed(false));
|
|
48
|
+
response.once("finish", answered);
|
|
49
|
+
response.once("close", answered);
|
|
50
|
+
try {
|
|
51
|
+
vite.middlewares(request, response, (error) =>
|
|
52
|
+
settle(error === undefined ? Effect.succeed(true) : Effect.die(error)),
|
|
53
|
+
);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
settle(Effect.die(error));
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Passes each request to Vite first, and the requests Vite passes on to the
|
|
61
|
+
* app. Use it in development only, with Vite in middleware mode:
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* import { ReactRouterVite } from "react-router-effect/vite";
|
|
65
|
+
*
|
|
66
|
+
* const vite = await createServer({ server: { middlewareMode: true } });
|
|
67
|
+
* HttpServer.serve(Effect.flatten(reactRouterApp).pipe(ReactRouterVite.devMiddleware(vite)));
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* A request Vite answers gets an empty `HttpServerResponse`, which Effect's
|
|
71
|
+
* Node server does not write, since Vite has ended the Node response. A Vite
|
|
72
|
+
* error fails the request as a defect.
|
|
73
|
+
*/
|
|
74
|
+
export const devMiddleware =
|
|
75
|
+
(vite: ViteDevServer) =>
|
|
76
|
+
<E, R>(
|
|
77
|
+
app: Effect.Effect<HttpServerResponse.HttpServerResponse, E, R>,
|
|
78
|
+
): Effect.Effect<
|
|
79
|
+
HttpServerResponse.HttpServerResponse,
|
|
80
|
+
E,
|
|
81
|
+
R | HttpServerRequest.HttpServerRequest
|
|
82
|
+
> =>
|
|
83
|
+
HttpServerRequest.HttpServerRequest.use((request) =>
|
|
84
|
+
passThroughVite(
|
|
85
|
+
vite,
|
|
86
|
+
// Vite takes HTTP/1 requests; Effect's Node server serves HTTP/1.
|
|
87
|
+
NodeHttpServerRequest.toIncomingMessage(request) as Http.IncomingMessage,
|
|
88
|
+
NodeHttpServerRequest.toServerResponse(request) as Http.ServerResponse,
|
|
89
|
+
).pipe(
|
|
90
|
+
Effect.flatMap((passed) => (passed ? app : Effect.succeed(HttpServerResponse.empty()))),
|
|
91
|
+
),
|
|
92
|
+
);
|