diff --git a/contributors.yml b/contributors.yml index 57082791773..2931be59d05 100644 --- a/contributors.yml +++ b/contributors.yml @@ -713,3 +713,4 @@ - zayenz - zhe - zwhitchcox +- zwily diff --git a/templates/classic-remix-compiler/cloudflare-workers/.gitignore b/templates/classic-remix-compiler/cloudflare-workers/.gitignore index a6978e55559..d30462277aa 100644 --- a/templates/classic-remix-compiler/cloudflare-workers/.gitignore +++ b/templates/classic-remix-compiler/cloudflare-workers/.gitignore @@ -5,3 +5,4 @@ node_modules /build /public/build .env +.dev.vars \ No newline at end of file diff --git a/templates/classic-remix-compiler/cloudflare-workers/app/root.tsx b/templates/classic-remix-compiler/cloudflare-workers/app/root.tsx index 68397b09d47..cdad1a5039b 100644 --- a/templates/classic-remix-compiler/cloudflare-workers/app/root.tsx +++ b/templates/classic-remix-compiler/cloudflare-workers/app/root.tsx @@ -1,5 +1,3 @@ -import type { LinksFunction } from "@remix-run/cloudflare"; -import { cssBundleHref } from "@remix-run/css-bundle"; import { Links, LiveReload, @@ -8,12 +6,25 @@ import { Scripts, ScrollRestoration, } from "@remix-run/react"; +import type { LinksFunction } from "@remix-run/cloudflare"; + +import styles from "./tailwind.css"; export const links: LinksFunction = () => [ - ...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []), + { rel: "stylesheet", href: styles }, + { rel: "preconnect", href: "https://fonts.googleapis.com" }, + { + rel: "preconnect", + href: "https://fonts.gstatic.com", + crossOrigin: "anonymous", + }, + { + rel: "stylesheet", + href: "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap", + }, ]; -export default function App() { +export function Layout({ children }: { children: React.ReactNode }) { return ( @@ -23,7 +34,7 @@ export default function App() { - + {children} @@ -31,3 +42,7 @@ export default function App() { ); } + +export default function App() { + return ; +} diff --git a/templates/classic-remix-compiler/cloudflare-workers/app/routes/_index.tsx b/templates/classic-remix-compiler/cloudflare-workers/app/routes/_index.tsx index 4aa6089f125..97083ec2074 100644 --- a/templates/classic-remix-compiler/cloudflare-workers/app/routes/_index.tsx +++ b/templates/classic-remix-compiler/cloudflare-workers/app/routes/_index.tsx @@ -9,33 +9,130 @@ export const meta: MetaFunction = () => { export default function Index() { return ( -
-

Welcome to Remix

- +
+
+
+

+ Welcome to Remix +

+
+ Remix + Remix +
+
+ +
); } + +const resources = [ + { + href: "https://remix.run/start/quickstart", + text: "Quick Start (5 min)", + icon: ( + + + + ), + }, + { + href: "https://remix.run/start/tutorial", + text: "Tutorial (30 min)", + icon: ( + + + + ), + }, + { + href: "https://remix.run/docs", + text: "Remix Docs", + icon: ( + + + + ), + }, + { + href: "https://rmx.as/discord", + text: "Join Discord", + icon: ( + + + + ), + }, +]; diff --git a/templates/classic-remix-compiler/cloudflare-workers/app/tailwind.css b/templates/classic-remix-compiler/cloudflare-workers/app/tailwind.css new file mode 100644 index 00000000000..303fe158fcf --- /dev/null +++ b/templates/classic-remix-compiler/cloudflare-workers/app/tailwind.css @@ -0,0 +1,12 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +html, +body { + @apply bg-white dark:bg-gray-950; + + @media (prefers-color-scheme: dark) { + color-scheme: dark; + } +} diff --git a/templates/classic-remix-compiler/cloudflare-workers/load-context.ts b/templates/classic-remix-compiler/cloudflare-workers/load-context.ts new file mode 100644 index 00000000000..d11eedbcb63 --- /dev/null +++ b/templates/classic-remix-compiler/cloudflare-workers/load-context.ts @@ -0,0 +1,26 @@ +import { type PlatformProxy } from "wrangler"; + +type GetLoadContextArgs = { + request: Request; + context: { + cloudflare: Omit< + PlatformProxy, + "dispose" | "caches" + > & { + caches: + | PlatformProxy["caches"] + | CacheStorage; + }; + }; +}; + +declare module "@remix-run/cloudflare" { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + interface AppLoadContext extends ReturnType { + // This will merge the result of `getLoadContext` into the `AppLoadContext` + } +} + +export function getLoadContext({ context }: GetLoadContextArgs) { + return context; +} diff --git a/templates/classic-remix-compiler/cloudflare-workers/package.json b/templates/classic-remix-compiler/cloudflare-workers/package.json index 87f765d4f8f..6b3748c8d91 100644 --- a/templates/classic-remix-compiler/cloudflare-workers/package.json +++ b/templates/classic-remix-compiler/cloudflare-workers/package.json @@ -4,14 +4,14 @@ "type": "module", "scripts": { "build": "remix build", - "deploy": "wrangler deploy", + "deploy": "npm run build && wrangler deploy", "dev": "remix dev --manual -c \"npm start\"", "lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .", "start": "wrangler dev ./build/index.js", - "typecheck": "tsc" + "typecheck": "tsc", + "typegen": "wrangler types" }, "dependencies": { - "@cloudflare/kv-asset-handler": "^0.1.3", "@remix-run/cloudflare": "*", "@remix-run/css-bundle": "*", "@remix-run/react": "*", @@ -20,7 +20,7 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20230518.0", + "@cloudflare/workers-types": "^4.20240925.0", "@remix-run/dev": "*", "@types/react": "^18.2.20", "@types/react-dom": "^18.2.7", @@ -32,8 +32,9 @@ "eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", + "tailwindcss": "^3.4.4", "typescript": "^5.1.6", - "wrangler": "^3.24.0" + "wrangler": "^3.80.1" }, "engines": { "node": ">=18.0.0" diff --git a/templates/classic-remix-compiler/cloudflare-workers/public/logo-dark.png b/templates/classic-remix-compiler/cloudflare-workers/public/logo-dark.png new file mode 100644 index 00000000000..b24c7aee3a8 Binary files /dev/null and b/templates/classic-remix-compiler/cloudflare-workers/public/logo-dark.png differ diff --git a/templates/classic-remix-compiler/cloudflare-workers/public/logo-light.png b/templates/classic-remix-compiler/cloudflare-workers/public/logo-light.png new file mode 100644 index 00000000000..4490ae79307 Binary files /dev/null and b/templates/classic-remix-compiler/cloudflare-workers/public/logo-light.png differ diff --git a/templates/classic-remix-compiler/cloudflare-workers/remix.config.js b/templates/classic-remix-compiler/cloudflare-workers/remix.config.js index fbf8e7ec39f..9ad0213a486 100644 --- a/templates/classic-remix-compiler/cloudflare-workers/remix.config.js +++ b/templates/classic-remix-compiler/cloudflare-workers/remix.config.js @@ -4,8 +4,8 @@ export default { server: "./server.ts", serverConditions: ["workerd", "worker", "browser"], serverDependenciesToBundle: [ - // bundle everything except the virtual module for the static content manifest provided by wrangler - /^(?!.*\b__STATIC_CONTENT_MANIFEST\b).*$/, + // bundle everything except the external cloudflare:workers package + /^(?!.*\bcloudflare:workers\b).*$/, ], serverMainFields: ["browser", "module", "main"], serverMinify: true, diff --git a/templates/classic-remix-compiler/cloudflare-workers/remix.env.d.ts b/templates/classic-remix-compiler/cloudflare-workers/remix.env.d.ts index b5be9ba3bbe..425870ae632 100644 --- a/templates/classic-remix-compiler/cloudflare-workers/remix.env.d.ts +++ b/templates/classic-remix-compiler/cloudflare-workers/remix.env.d.ts @@ -1,8 +1,3 @@ /// /// /// - -declare module "__STATIC_CONTENT_MANIFEST" { - const manifest: string; - export default manifest; -} diff --git a/templates/classic-remix-compiler/cloudflare-workers/server.ts b/templates/classic-remix-compiler/cloudflare-workers/server.ts index 4b6e39ef295..bee19ccb283 100644 --- a/templates/classic-remix-compiler/cloudflare-workers/server.ts +++ b/templates/classic-remix-compiler/cloudflare-workers/server.ts @@ -1,11 +1,7 @@ -import { getAssetFromKV } from "@cloudflare/kv-asset-handler"; -import type { AppLoadContext } from "@remix-run/cloudflare"; import { createRequestHandler, logDevReady } from "@remix-run/cloudflare"; import * as build from "@remix-run/dev/server-build"; -// 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); const handleRemixRequest = createRequestHandler(build, process.env.NODE_ENV); if (process.env.NODE_ENV === "development") { @@ -13,44 +9,30 @@ if (process.env.NODE_ENV === "development") { } export default { - async fetch( - request: Request, - env: { - __STATIC_CONTENT: Fetcher; - }, - ctx: ExecutionContext - ): Promise { + async fetch(request, env, ctx): Promise { try { - const url = new URL(request.url); - const ttl = url.pathname.startsWith("/build/") - ? 60 * 60 * 24 * 365 // 1 year - : 60 * 5; // 5 minutes - return await getAssetFromKV( - { - request, - waitUntil: ctx.waitUntil.bind(ctx), - } as FetchEvent, - { - 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, + ctx: { + waitUntil: ctx.waitUntil.bind(ctx), + passThroughOnException: ctx.passThroughOnException.bind(ctx), + }, + caches, + env, }, - } - ); - } catch (error) { - // No-op - } - - try { - const loadContext: AppLoadContext = { - env, - }; + }, + }); return await handleRemixRequest(request, loadContext); } catch (error) { console.log(error); return new Response("An unexpected error occurred", { status: 500 }); } }, -}; +} satisfies ExportedHandler; diff --git a/templates/classic-remix-compiler/cloudflare-workers/tailwind.config.ts b/templates/classic-remix-compiler/cloudflare-workers/tailwind.config.ts new file mode 100644 index 00000000000..14d0f00ce6a --- /dev/null +++ b/templates/classic-remix-compiler/cloudflare-workers/tailwind.config.ts @@ -0,0 +1,22 @@ +import type { Config } from "tailwindcss"; + +export default { + content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], + theme: { + extend: { + fontFamily: { + sans: [ + '"Inter"', + "ui-sans-serif", + "system-ui", + "sans-serif", + '"Apple Color Emoji"', + '"Segoe UI Emoji"', + '"Segoe UI Symbol"', + '"Noto Color Emoji"', + ], + }, + }, + }, + plugins: [], +} satisfies Config; diff --git a/templates/classic-remix-compiler/cloudflare-workers/tsconfig.json b/templates/classic-remix-compiler/cloudflare-workers/tsconfig.json index 7edc18b084a..0fdf9f1f339 100644 --- a/templates/classic-remix-compiler/cloudflare-workers/tsconfig.json +++ b/templates/classic-remix-compiler/cloudflare-workers/tsconfig.json @@ -1,7 +1,13 @@ { - "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], + "include": [ + "worker-configuration.d.ts", + "remix.env.d.ts", + "**/*.ts", + "**/*.tsx" + ], "compilerOptions": { "lib": ["DOM", "DOM.Iterable", "ES2022"], + "types": ["@remix-run/cloudflare", "@cloudflare/workers-types"], "isolatedModules": true, "esModuleInterop": true, "jsx": "react-jsx", diff --git a/templates/classic-remix-compiler/cloudflare-workers/worker-configuration.d.ts b/templates/classic-remix-compiler/cloudflare-workers/worker-configuration.d.ts new file mode 100644 index 00000000000..2a6ba0cb08c --- /dev/null +++ b/templates/classic-remix-compiler/cloudflare-workers/worker-configuration.d.ts @@ -0,0 +1,3 @@ +// Generated by Wrangler by running `wrangler types` + +interface Env {} diff --git a/templates/classic-remix-compiler/cloudflare-workers/wrangler.toml b/templates/classic-remix-compiler/cloudflare-workers/wrangler.toml index e52f6c2e546..3dba78a2865 100644 --- a/templates/classic-remix-compiler/cloudflare-workers/wrangler.toml +++ b/templates/classic-remix-compiler/cloudflare-workers/wrangler.toml @@ -1,12 +1,15 @@ +#:schema node_modules/wrangler/config-schema.json name = "remix-cloudflare-workers" workers_dev = true main = "./build/index.js" # https://developers.cloudflare.com/workers/platform/compatibility-dates -compatibility_date = "2023-04-20" +compatibility_date = "2024-09-26" -[site] - bucket = "./public" +[assets] +directory = "./public" -[build] - command = "npm run build" +[observability] +# Set this to true to enable logging. (Extra costs may apply) +# https://developers.cloudflare.com/workers/observability/logs/workers-logs +enabled = false