-
Notifications
You must be signed in to change notification settings - Fork 2.6k
/
cloudflare-proxy-plugin.ts
87 lines (78 loc) · 2.71 KB
/
cloudflare-proxy-plugin.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import { createRequestHandler } from "@remix-run/server-runtime";
import {
type AppLoadContext,
type ServerBuild,
} from "@remix-run/server-runtime";
import { type Plugin } from "vite";
import { type GetPlatformProxyOptions, type PlatformProxy } from "wrangler";
import { fromNodeRequest, toNodeRequest } from "./node-adapter";
let serverBuildId = "virtual:remix/server-build";
type CfProperties = Record<string, unknown>;
type LoadContext<Env, Cf extends CfProperties> = {
cloudflare: Omit<PlatformProxy<Env, Cf>, "dispose">;
};
type GetLoadContext<Env, Cf extends CfProperties> = (args: {
request: Request;
context: LoadContext<Env, Cf>;
}) => AppLoadContext | Promise<AppLoadContext>;
function importWrangler() {
try {
return import("wrangler");
} catch (_) {
throw Error("Could not import `wrangler`. Do you have it installed?");
}
}
const NAME = "vite-plugin-remix-cloudflare-proxy";
export const cloudflareDevProxyVitePlugin = <Env, Cf extends CfProperties>({
getLoadContext,
...options
}: {
getLoadContext?: GetLoadContext<Env, Cf>;
} & GetPlatformProxyOptions = {}): Plugin => {
return {
name: NAME,
config: () => ({
ssr: {
resolve: {
externalConditions: ["workerd", "worker"],
},
},
}),
configResolved: (viteConfig) => {
let pluginIndex = (name: string) =>
viteConfig.plugins.findIndex((plugin) => plugin.name === name);
let remixIndex = pluginIndex("remix");
if (remixIndex >= 0 && remixIndex < pluginIndex(NAME)) {
throw new Error(
`The "${NAME}" plugin should be placed before the Remix plugin in your Vite config file`
);
}
},
configureServer: async (viteDevServer) => {
let { getPlatformProxy } = await importWrangler();
// Do not include `dispose` in Cloudflare context
let { dispose, ...cloudflare } = await getPlatformProxy<Env, Cf>(options);
let context = { cloudflare };
return () => {
if (!viteDevServer.config.server.middlewareMode) {
viteDevServer.middlewares.use(async (nodeReq, nodeRes, next) => {
try {
let build = (await viteDevServer.ssrLoadModule(
serverBuildId
)) as ServerBuild;
let handler = createRequestHandler(build, "development");
let req = fromNodeRequest(nodeReq, nodeRes);
let loadContext = getLoadContext
? await getLoadContext({ request: req, context })
: context;
let res = await handler(req, loadContext);
await toNodeRequest(res, nodeRes);
} catch (error) {
next(error);
}
});
}
};
},
};
};