-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
templates(cloudflare-workers): use static assets #10034
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,21 @@ | ||
import { type PlatformProxy } from "wrangler"; | ||
|
||
// PlatformProxy’s caches property is incompatible with the caches global | ||
// https://github.com/cloudflare/workers-sdk/blob/main/packages/wrangler/src/api/integrations/platform/caches.ts | ||
type Cloudflare = Omit<PlatformProxy<Env>, "dispose" | "caches"> & { | ||
caches: CacheStorage; | ||
}; | ||
type GetLoadContextArgs = { | ||
request: Request; | ||
context: { | ||
cloudflare: Omit<PlatformProxy<Env, IncomingRequestCfProperties>, "dispose" | "caches"> & { | ||
caches: PlatformProxy<Env, IncomingRequestCfProperties>['caches'] | CacheStorage; | ||
}; | ||
}; | ||
} | ||
|
||
declare module "@remix-run/cloudflare" { | ||
interface AppLoadContext { | ||
cloudflare: Cloudflare; | ||
// eslint-disable-next-line @typescript-eslint/no-empty-interface | ||
interface AppLoadContext extends ReturnType<typeof getLoadContext> { | ||
// This will merge the result of `getLoadContext` into the `AppLoadContext` | ||
} | ||
} | ||
|
||
export function getLoadContext({ context }: GetLoadContextArgs) { | ||
return context; | ||
} | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,37 @@ | ||
import { getAssetFromKV } from "@cloudflare/kv-asset-handler"; | ||
import { createRequestHandler, type ServerBuild } from "@remix-run/cloudflare"; | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
// @ts-ignore This file won’t exist if it hasn’t yet been built | ||
import * as build from "./build/server"; // eslint-disable-line import/no-unresolved | ||
// eslint-disable-next-line import/no-unresolved | ||
import __STATIC_CONTENT_MANIFEST from "__STATIC_CONTENT_MANIFEST"; | ||
import { getLoadContext } from "./load-context"; | ||
|
||
const MANIFEST = JSON.parse(__STATIC_CONTENT_MANIFEST); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const handleRemixRequest = createRequestHandler(build as any as ServerBuild); | ||
|
||
export default { | ||
async fetch(request, env, ctx) { | ||
const waitUntil = ctx.waitUntil.bind(ctx); | ||
const passThroughOnException = ctx.passThroughOnException.bind(ctx); | ||
try { | ||
const url = new URL(request.url); | ||
const ttl = url.pathname.startsWith("/assets/") | ||
? 60 * 60 * 24 * 365 // 1 year | ||
: 60 * 5; // 5 minutes | ||
return await getAssetFromKV( | ||
{ request, waitUntil }, | ||
{ | ||
ASSET_NAMESPACE: env.__STATIC_CONTENT, | ||
ASSET_MANIFEST: MANIFEST, | ||
cacheControl: { | ||
browserTTL: ttl, | ||
edgeTTL: ttl, | ||
const loadContext = getLoadContext({ | ||
request, | ||
context: { | ||
cloudflare: { | ||
// This object matches the return value from Wrangler's | ||
// `getPlatformProxy` used during development via Remix's | ||
// `cloudflareDevProxyVitePlugin`: | ||
// https://developers.cloudflare.com/workers/wrangler/api/#getplatformproxy | ||
cf: request.cf, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This causes a type error, should it just be cast to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can just set it to cf: request.cf! Or, we can change type GetLoadContextArgs = {
request: Request;
context: {
cloudflare: Omit<PlatformProxy<Env, IncomingRequestCfProperties>, "dispose" | "caches" | "cf"> & {
caches: PlatformProxy<Env, IncomingRequestCfProperties>['caches'] | CacheStorage;
cf: Request['cf'];
};
};
} The first is simpler, but the second is better. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer correctness, I'll defer to @edmundhung |
||
ctx: { | ||
waitUntil: ctx.waitUntil.bind(ctx), | ||
passThroughOnException: ctx.passThroughOnException.bind(ctx), | ||
}, | ||
caches, | ||
env, | ||
}, | ||
} | ||
); | ||
} catch (error) { | ||
// No-op | ||
} | ||
|
||
try { | ||
const loadContext = { | ||
cloudflare: { | ||
// This object matches the return value from Wrangler's | ||
// `getPlatformProxy` used during development via Remix's | ||
// `cloudflareDevProxyVitePlugin`: | ||
// https://developers.cloudflare.com/workers/wrangler/api/#getplatformproxy | ||
cf: request.cf, | ||
ctx: { waitUntil, passThroughOnException }, | ||
caches, | ||
env, | ||
}, | ||
}; | ||
}); | ||
return await handleRemixRequest(request, loadContext); | ||
} catch (error) { | ||
console.log(error); | ||
return new Response("An unexpected error occurred", { status: 500 }); | ||
} | ||
}, | ||
} satisfies ExportedHandler<Env & { __STATIC_CONTENT: KVNamespace<string> }>; | ||
} satisfies ExportedHandler<Env>; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,10 +4,13 @@ import { | |
cloudflareDevProxyVitePlugin, | ||
} from "@remix-run/dev"; | ||
import tsconfigPaths from "vite-tsconfig-paths"; | ||
import { getLoadContext } from "./load-context"; | ||
|
||
export default defineConfig({ | ||
plugins: [ | ||
cloudflareDevProxyVitePlugin(), | ||
cloudflareDevProxyVitePlugin({ | ||
getLoadContext, | ||
}), | ||
remix({ | ||
future: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
v3_fetcherPersist: true, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,14 @@ | ||
#:schema node_modules/wrangler/config-schema.json | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where's this coming from? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you use an IDE extension that support json schema over TOML, this will give you auto completion and validation on your wrangler.toml, like this one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fabulous - perhaps add it as a comment? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's generated by the wrangler.
|
||
name = "remix-cloudflare-workers-template" | ||
|
||
main = "./server.ts" | ||
workers_dev = true | ||
# https://developers.cloudflare.com/workers/platform/compatibility-dates | ||
compatibility_date = "2023-04-20" | ||
compatibility_date = "2024-09-26" | ||
|
||
[site] | ||
bucket = "./build/client" | ||
[assets] | ||
# https://developers.cloudflare.com/workers/static-assets/binding/ | ||
directory = "./build/client" | ||
edmundhung marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we add an ASSETS binding here too? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @petebacondarwin for the majority of use cases, there’s no need for the binding. the static assets feature intercepts requests and checks if the URL matches anything in the assets |
||
|
||
[build] | ||
command = "npm run build" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.