From 442d95442a04ccb49c661dfba26331c493b9b46f Mon Sep 17 00:00:00 2001 From: Pedro Cattori Date: Fri, 6 May 2022 14:31:28 -0400 Subject: [PATCH] feat(templates/deno): use npm-managed dependencies --- packages/remix-dev/cli/create.ts | 9 +- templates/deno/.eslintignore | 1 + .../deno/.vscode/resolve_npm_imports.json | 15 +++ templates/deno/.vscode/settings.json | 5 +- templates/deno/README.md | 81 +++++++------ templates/deno/app/deps/@remix-run/react.ts | 10 -- templates/deno/app/deps/README.md | 7 -- templates/deno/app/deps/react-dom-server.ts | 4 - templates/deno/app/deps/react-dom.ts | 1 - templates/deno/app/deps/react.ts | 1 - templates/deno/app/entry.client.tsx | 6 +- templates/deno/app/entry.server.tsx | 12 +- templates/deno/app/root.tsx | 6 +- templates/deno/app/routes/index.tsx | 2 +- templates/deno/package.json | 10 +- templates/deno/remix-deno/README.md | 4 - templates/deno/remix-deno/crypto.ts | 55 --------- .../deps/@remix-run/server-runtime.ts | 14 --- templates/deno/remix-deno/implementations.ts | 15 --- templates/deno/remix-deno/index.ts | 56 --------- templates/deno/remix-deno/server.ts | 104 ---------------- .../deno/remix-deno/sessions/fileStorage.ts | 112 ------------------ templates/deno/remix.config.js | 8 ++ templates/deno/server.ts | 4 +- 24 files changed, 98 insertions(+), 444 deletions(-) create mode 100644 templates/deno/.eslintignore create mode 100644 templates/deno/.vscode/resolve_npm_imports.json delete mode 100644 templates/deno/app/deps/@remix-run/react.ts delete mode 100644 templates/deno/app/deps/README.md delete mode 100644 templates/deno/app/deps/react-dom-server.ts delete mode 100644 templates/deno/app/deps/react-dom.ts delete mode 100644 templates/deno/app/deps/react.ts delete mode 100644 templates/deno/remix-deno/README.md delete mode 100644 templates/deno/remix-deno/crypto.ts delete mode 100644 templates/deno/remix-deno/deps/@remix-run/server-runtime.ts delete mode 100644 templates/deno/remix-deno/implementations.ts delete mode 100644 templates/deno/remix-deno/index.ts delete mode 100644 templates/deno/remix-deno/server.ts delete mode 100644 templates/deno/remix-deno/sessions/fileStorage.ts diff --git a/packages/remix-dev/cli/create.ts b/packages/remix-dev/cli/create.ts index c75a8f27659..d5637a106dd 100644 --- a/packages/remix-dev/cli/create.ts +++ b/packages/remix-dev/cli/create.ts @@ -452,14 +452,15 @@ function isRemixStack(input: string) { function isRemixTemplate(input: string) { return [ - "remix", - "express", "arc", + "cloudflare-pages", + "cloudflare-workers", + "deno", + "express", "fly", "netlify", + "remix", "vercel", - "cloudflare-pages", - "cloudflare-workers", ].includes(input); } diff --git a/templates/deno/.eslintignore b/templates/deno/.eslintignore new file mode 100644 index 00000000000..f59ec20aabf --- /dev/null +++ b/templates/deno/.eslintignore @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/templates/deno/.vscode/resolve_npm_imports.json b/templates/deno/.vscode/resolve_npm_imports.json new file mode 100644 index 00000000000..2a7dcfdd408 --- /dev/null +++ b/templates/deno/.vscode/resolve_npm_imports.json @@ -0,0 +1,15 @@ +{ + "// This import map is used solely for the denoland.vscode-deno extension.": "", + "// Remix does not support import maps.": "", + "// Dependency management is done through `npm` and `node_modules/` instead.": "", + "// Deno-only dependencies may be imported via URL imports (without using import maps).": "", + + "imports": { + "react": "https://esm.sh/react@18.0.0", + "react-dom": "https://esm.sh/react-dom@18.0.0", + "react-dom/server": "https://esm.sh/react-dom@18.0.0/server", + "@remix-run/dev/server-build": "https://esm.sh/@remix-run/dev@1.4.3/server-build", + "@remix-run/deno": "https://esm.sh/@remix-run/deno@1.4.3", + "@remix-run/react": "https://esm.sh/@remix-run/react@1.4.3" + } +} diff --git a/templates/deno/.vscode/settings.json b/templates/deno/.vscode/settings.json index 3dfe427e466..c58c9450882 100644 --- a/templates/deno/.vscode/settings.json +++ b/templates/deno/.vscode/settings.json @@ -1,4 +1,5 @@ { "deno.enable": true, - "deno.lint": true -} \ No newline at end of file + "deno.lint": true, + "deno.importMap": "./.vscode/resolve_npm_imports.json" +} diff --git a/templates/deno/README.md b/templates/deno/README.md index 2647b6e964c..726327cf00a 100644 --- a/templates/deno/README.md +++ b/templates/deno/README.md @@ -1,69 +1,74 @@ -# Remix Deno Template +# Remix + Deno -⚠️ EXPERIMENTAL ⚠️ +Welcome to the Deno template for Remix! + +For more, check out the [Remix docs](https://remix.run/docs). ## Install ```sh -npx create-remix@latest --template +npx create-remix@latest --template deno ``` -## Scripts +## Managing dependencies -```sh -npm run build -``` +### Deno modules -```sh -npm run start -``` +Import Deno modules via URL imports: -```sh -npm run dev +```ts +import { copy } from "https://deno.land/std@0.138.0/streams/conversion.ts"; ``` -## 🚧 Under construction 🚧 +### Don't use Deno-friendly CDNs, use `npm` -This section details temporary scaffolding for the Remix Deno template. -All of this scaffolding is planned for removal at a later date. +For other dependencies, simply use `npm` to install them. -### `package.json` +```sh +npm install react react-dom +``` -A `package.json` is included for now so that `remix` CLI (from `@remix-run/dev`) can run the Remix compiler. +```tsx +import { useEffect } from "react"; +``` -In the future, we could provide a stand-alone executable for the Remix compiler OR `npx remix`, and we would remove the `package.json` file from this Deno template. +Do not use Deno-friendly CDNs like https://esm.sh as those CDNs +do not have good support for peer dependencies nor for specifying +dev/prod environments via `NODE_ENV`. -### Local `remix-deno` package +### Don't use import maps -For now, we are inlining Remix's `@remix-run/deno` package into `remix-deno` to enable faster experimentation and development. +Remix does not support [import maps](https://deno.land/manual/linking_to_external_code/import_maps) for Deno. -In the future, this template would not include the `remix-deno` directory at all. -Instead, users could import from `@remix-run/deno` (exact URL TBD). +## Development -## 🐞 Known issues 🐞 +From your terminal: -### `dev` does not live reload +```sh +npm run dev +``` -Deno server is not currently configured to live reload when `--watch` detects changes, requiring a manual refresh in the browser for non-server changes (e.g. changing JSX content). +This starts your app in development mode, rebuilding assets on file changes. -To enable live reload, `@remix-run/react` must be built with `NODE_ENV=development`. -To do so with `esm.sh`, `?dev` must be added to all imports that depend on React. -However, bundling the React development build for `esm.sh` (`https://esm.sh/react@17.0.2?dev`) runs into an [esbuild bug](https://github.com/evanw/esbuild/issues/2099). +## Production -Need a better way to switch from development to production mode than adding/removing `?dev` for all React-dependent imports. -Also, need esbuild bug to be resolved. +First, build your app for production: -### Pinned React imports +```sh +npm run build +``` -For all React-related imports (including `@remix-run/*` imports), we append `?pin=v68` to the URL. -This is the only reliable way we were able to guarantee that only one copy of React would be present in the browser. +Then run the app in production mode: -No plans on how to address this yet. +```sh +npm start +``` -### @remix-run/dev/server-build +## Deployment -The `@remix-run/dev/server-build` import within `server.ts` (`import * as build from '@remix-run/dev/server-build'`) is a special import for the Remix compiler that points to the built server entry point (typically within `./build`). +Building the Deno app (`npm run build`) results in two outputs: -The `vscode_deno` plugin complains about this import with a red squiggly underline as Deno cannot resolve this special import. +- `build/` (server bundle) +- `public/build/` (browser bundle) -No plans on how to address this yet. +You can deploy these bundles to a host of your choice, just make sure it runs Deno! diff --git a/templates/deno/app/deps/@remix-run/react.ts b/templates/deno/app/deps/@remix-run/react.ts deleted file mode 100644 index 209ac677660..00000000000 --- a/templates/deno/app/deps/@remix-run/react.ts +++ /dev/null @@ -1,10 +0,0 @@ -export { - Links, - LiveReload, - Meta, - Outlet, - RemixBrowser, - RemixServer, - Scripts, - ScrollRestoration, -} from "https://esm.sh/@remix-run/react@1.4.0?pin=v77&dev"; diff --git a/templates/deno/app/deps/README.md b/templates/deno/app/deps/README.md deleted file mode 100644 index fc0f00c0819..00000000000 --- a/templates/deno/app/deps/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Splitting up client and server dependencies so that `react-dom` is only bundled on the client and `react-dom-server` is only bundled on the server. - -## React and other singletons - -Singletons like `react` will cause errors if more than one copy is present. - -To ensure only one copy of each singleton is loaded, use [`deps` files](https://deno.land/manual@v1.19.3/examples/manage_dependencies) to centrally defined a single version of each singleton. \ No newline at end of file diff --git a/templates/deno/app/deps/react-dom-server.ts b/templates/deno/app/deps/react-dom-server.ts deleted file mode 100644 index 6edfec42340..00000000000 --- a/templates/deno/app/deps/react-dom-server.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { - default, - renderToString, -} from "https://esm.sh/react-dom@18.0.0/server?pin=v77&dev"; diff --git a/templates/deno/app/deps/react-dom.ts b/templates/deno/app/deps/react-dom.ts deleted file mode 100644 index 0fc6d10f56e..00000000000 --- a/templates/deno/app/deps/react-dom.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "https://esm.sh/react-dom@18.0.0?pin=v77&dev"; diff --git a/templates/deno/app/deps/react.ts b/templates/deno/app/deps/react.ts deleted file mode 100644 index 1bf522b9381..00000000000 --- a/templates/deno/app/deps/react.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "https://esm.sh/react@18.0.0?pin=v77&dev"; diff --git a/templates/deno/app/entry.client.tsx b/templates/deno/app/entry.client.tsx index 8d7f2b5aa9d..62a6a81634d 100644 --- a/templates/deno/app/entry.client.tsx +++ b/templates/deno/app/entry.client.tsx @@ -1,5 +1,5 @@ -import React from "./deps/react.ts"; -import ReactDOM from "./deps/react-dom.ts"; -import { RemixBrowser } from "./deps/@remix-run/react.ts"; +import React from "react"; +import ReactDOM from "react-dom"; +import { RemixBrowser } from "@remix-run/react"; ReactDOM.hydrate(, document); diff --git a/templates/deno/app/entry.server.tsx b/templates/deno/app/entry.server.tsx index 044cc6ad9df..5aff7ec014f 100644 --- a/templates/deno/app/entry.server.tsx +++ b/templates/deno/app/entry.server.tsx @@ -1,16 +1,16 @@ -import React from "./deps/react.ts"; -import { renderToString } from "./deps/react-dom-server.ts"; -import { RemixServer } from "./deps/@remix-run/react.ts"; -import type { EntryContext } from "../remix-deno/index.ts"; +import React from "react"; +import { renderToString } from "react-dom/server"; +import { RemixServer } from "@remix-run/react"; +import type { EntryContext } from "@remix-run/deno"; export default function handleRequest( request: Request, responseStatusCode: number, responseHeaders: Headers, - remixContext: EntryContext + remixContext: EntryContext, ) { const markup = renderToString( - + , ); responseHeaders.set("Content-Type", "text/html"); diff --git a/templates/deno/app/root.tsx b/templates/deno/app/root.tsx index e1e633406bc..a74cc0195c0 100644 --- a/templates/deno/app/root.tsx +++ b/templates/deno/app/root.tsx @@ -1,4 +1,4 @@ -import React from "./deps/react.ts"; +import React from "react"; import { Links, LiveReload, @@ -6,8 +6,8 @@ import { Outlet, Scripts, ScrollRestoration, -} from "./deps/@remix-run/react.ts"; -import type { MetaFunction } from "../remix-deno/index.ts"; +} from "@remix-run/react"; +import type { MetaFunction } from "@remix-run/deno"; export const meta: MetaFunction = () => ({ charset: "utf-8", diff --git a/templates/deno/app/routes/index.tsx b/templates/deno/app/routes/index.tsx index dd83272f72a..f2280e0a045 100644 --- a/templates/deno/app/routes/index.tsx +++ b/templates/deno/app/routes/index.tsx @@ -1,4 +1,4 @@ -import React from "../deps/react.ts"; +import React from "react"; export default function Index() { return ( diff --git a/templates/deno/package.json b/templates/deno/package.json index 0e9f358ac74..abf42ce9135 100644 --- a/templates/deno/package.json +++ b/templates/deno/package.json @@ -7,7 +7,9 @@ "dev": "remix build && run-p dev:*", "dev:remix": "remix watch", "dev:deno": "cross-env NODE_ENV=development deno run --unstable --watch --allow-net --allow-read --allow-env ./build/index.js", - "start": "cross-env NODE_ENV=production deno run --unstable --allow-net --allow-read --allow-env ./build/index.js" + "start": "cross-env NODE_ENV=production deno run --unstable --allow-net --allow-read --allow-env ./build/index.js", + "lint": "deno lint --ignore=node_modules", + "fmt": "deno fmt --ignore=node_modules" }, "devDependencies": { "@remix-run/dev": "*", @@ -16,5 +18,11 @@ }, "engines": { "node": ">=14" + }, + "dependencies": { + "@remix-run/deno": "*", + "@remix-run/react": "*", + "react": "^18.1.0", + "react-dom": "^18.1.0" } } diff --git a/templates/deno/remix-deno/README.md b/templates/deno/remix-deno/README.md deleted file mode 100644 index a591d709a98..00000000000 --- a/templates/deno/remix-deno/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# @remix-run/deno - -`@remix-run/deno` package is temporarily inlined within this directory while Deno support is experimental. -In the future, this directory would be removed and Remix + Deno apps would import `@remix-run/deno` from some URL. \ No newline at end of file diff --git a/templates/deno/remix-deno/crypto.ts b/templates/deno/remix-deno/crypto.ts deleted file mode 100644 index afe93093e36..00000000000 --- a/templates/deno/remix-deno/crypto.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { - SignFunction, - UnsignFunction, -} from "./deps/@remix-run/server-runtime.ts"; - -const encoder = new TextEncoder(); - -export const sign: SignFunction = async (value, secret) => { - let data = encoder.encode(value); - let key = await createKey(secret, ["sign"]); - let signature = await crypto.subtle.sign("HMAC", key, data); - let hash = btoa(String.fromCharCode(...new Uint8Array(signature))).replace( - /=+$/, - "" - ); - - return value + "." + hash; -}; - -export const unsign: UnsignFunction = async (cookie, secret) => { - let value = cookie.slice(0, cookie.lastIndexOf(".")); - let hash = cookie.slice(cookie.lastIndexOf(".") + 1); - - let data = encoder.encode(value); - let key = await createKey(secret, ["verify"]); - let signature = byteStringToUint8Array(atob(hash)); - let valid = await crypto.subtle.verify("HMAC", key, signature, data); - - return valid ? value : false; -}; - -async function createKey( - secret: string, - usages: CryptoKey["usages"] -): Promise { - let key = await crypto.subtle.importKey( - "raw", - encoder.encode(secret), - { name: "HMAC", hash: "SHA-256" }, - false, - usages - ); - - return key; -} - -function byteStringToUint8Array(byteString: string): Uint8Array { - let array = new Uint8Array(byteString.length); - - for (let i = 0; i < byteString.length; i++) { - array[i] = byteString.charCodeAt(i); - } - - return array; -} diff --git a/templates/deno/remix-deno/deps/@remix-run/server-runtime.ts b/templates/deno/remix-deno/deps/@remix-run/server-runtime.ts deleted file mode 100644 index 1ca2c9ba9e2..00000000000 --- a/templates/deno/remix-deno/deps/@remix-run/server-runtime.ts +++ /dev/null @@ -1,14 +0,0 @@ -export type { - ServerBuild, - SessionIdStorageStrategy, - SessionStorage, - SignFunction, - UnsignFunction, -} from "https://esm.sh/@remix-run/server-runtime@1.4.0?pin=v77"; -export { - createCookieFactory, - createCookieSessionStorageFactory, - createMemorySessionStorageFactory, - createSessionStorageFactory, - createRequestHandler, -} from "https://esm.sh/@remix-run/server-runtime@1.4.0?pin=v77"; diff --git a/templates/deno/remix-deno/implementations.ts b/templates/deno/remix-deno/implementations.ts deleted file mode 100644 index a915cc5dc7a..00000000000 --- a/templates/deno/remix-deno/implementations.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { - createCookieFactory, - createCookieSessionStorageFactory, - createMemorySessionStorageFactory, - createSessionStorageFactory, -} from "./deps/@remix-run/server-runtime.ts"; - -import { sign, unsign } from "./crypto.ts"; - -export const createCookie = createCookieFactory({ sign, unsign }); -export const createCookieSessionStorage = - createCookieSessionStorageFactory(createCookie); -export const createSessionStorage = createSessionStorageFactory(createCookie); -export const createMemorySessionStorage = - createMemorySessionStorageFactory(createSessionStorage); diff --git a/templates/deno/remix-deno/index.ts b/templates/deno/remix-deno/index.ts deleted file mode 100644 index 05e54ae13ff..00000000000 --- a/templates/deno/remix-deno/index.ts +++ /dev/null @@ -1,56 +0,0 @@ -export { createFileSessionStorage } from "./sessions/fileStorage.ts"; -export { - createRequestHandler, - createRequestHandlerWithStaticFiles, - serveStaticFiles, -} from "./server.ts"; - -export { - createCookie, - createCookieSessionStorage, - createMemorySessionStorage, - createSessionStorage, -} from "./implementations.ts"; - -export { - createSession, - isCookie, - isSession, - json, - redirect, -} from "https://esm.sh/@remix-run/server-runtime?pin=v68"; - -export type { - ActionFunction, - AppData, - AppLoadContext, - CreateRequestHandlerFunction, - Cookie, - CookieOptions, - CookieParseOptions, - CookieSerializeOptions, - CookieSignatureOptions, - DataFunctionArgs, - EntryContext, - ErrorBoundaryComponent, - HandleDataRequestFunction, - HandleDocumentRequestFunction, - HeadersFunction, - HtmlLinkDescriptor, - HtmlMetaDescriptor, - LinkDescriptor, - LinksFunction, - LoaderFunction, - MetaDescriptor, - MetaFunction, - PageLinkDescriptor, - RequestHandler, - RouteComponent, - RouteHandle, - ServerBuild, - ServerEntryModule, - Session, - SessionData, - SessionIdStorageStrategy, - SessionStorage, -} from "https://esm.sh/@remix-run/server-runtime?pin=v68"; diff --git a/templates/deno/remix-deno/server.ts b/templates/deno/remix-deno/server.ts deleted file mode 100644 index e458ca5fc40..00000000000 --- a/templates/deno/remix-deno/server.ts +++ /dev/null @@ -1,104 +0,0 @@ -import * as path from "https://deno.land/std@0.128.0/path/mod.ts"; -import mime from "https://esm.sh/mime"; - -import { createRequestHandler as createRemixRequestHandler } from "./deps/@remix-run/server-runtime.ts"; -import type { ServerBuild } from "./deps/@remix-run/server-runtime.ts"; - -function defaultCacheControl(url: URL, assetsPublicPath = "/build/") { - if (url.pathname.startsWith(assetsPublicPath)) { - return "public, max-age=31536000, immutable"; - } else { - return "public, max-age=600"; - } -} - -export function createRequestHandler({ - build, - mode, - getLoadContext, -}: { - build: ServerBuild; - mode?: string; - getLoadContext?: (request: Request) => Promise | Context; -}) { - const remixHandler = createRemixRequestHandler(build, mode); - return async (request: Request) => { - try { - const loadContext = getLoadContext - ? await getLoadContext(request) - : undefined; - - return await remixHandler(request, loadContext); - } catch (e) { - console.error(e); - - return new Response("Internal Error", { status: 500 }); - } - }; -} - -export async function serveStaticFiles( - request: Request, - { - cacheControl, - publicDir = "./public", - assetsPublicPath = "/build/", - }: { - cacheControl?: string | ((url: URL) => string); - publicDir?: string; - assetsPublicPath?: string; - } -) { - const url = new URL(request.url); - - const headers = new Headers(); - const contentType = mime.getType(url.pathname); - if (contentType) { - headers.set("Content-Type", contentType); - } - - if (typeof cacheControl === "function") { - headers.set("Cache-Control", cacheControl(url)); - } else if (cacheControl) { - headers.set("Cache-Control", cacheControl); - } else { - headers.set("Cache-Control", defaultCacheControl(url, assetsPublicPath)); - } - - const file = await Deno.readFile(path.join(publicDir, url.pathname)); - - return new Response(file, { headers }); -} - -export function createRequestHandlerWithStaticFiles({ - build, - mode, - getLoadContext, - staticFiles = { - publicDir: "./public", - assetsPublicPath: "/build/", - }, -}: { - build: ServerBuild; - mode?: string; - getLoadContext?: (request: Request) => Promise | Context; - staticFiles?: { - cacheControl?: string | ((url: URL) => string); - publicDir?: string; - assetsPublicPath?: string; - }; -}) { - const remixHandler = createRequestHandler({ build, mode, getLoadContext }); - - return async (request: Request) => { - try { - return await serveStaticFiles(request, staticFiles); - } catch (error) { - if (error.code !== "EISDIR" && error.code !== "ENOENT") { - throw error; - } - } - - return remixHandler(request); - }; -} diff --git a/templates/deno/remix-deno/sessions/fileStorage.ts b/templates/deno/remix-deno/sessions/fileStorage.ts deleted file mode 100644 index e34909e5fba..00000000000 --- a/templates/deno/remix-deno/sessions/fileStorage.ts +++ /dev/null @@ -1,112 +0,0 @@ -import * as path from "https://deno.land/std@0.128.0/path/mod.ts"; - -import type { - SessionStorage, - SessionIdStorageStrategy, -} from "../deps/@remix-run/server-runtime.ts"; -import { createSessionStorage } from "../implementations.ts"; - -interface FileSessionStorageOptions { - /** - * The Cookie used to store the session id on the client, or options used - * to automatically create one. - */ - cookie?: SessionIdStorageStrategy["cookie"]; - - /** - * The directory to use to store session files. - */ - dir: string; -} - -/** - * Creates a SessionStorage that stores session data on a filesystem. - * - * The advantage of using this instead of cookie session storage is that - * files may contain much more data than cookies. - */ -export function createFileSessionStorage({ - cookie, - dir, -}: FileSessionStorageOptions): SessionStorage { - return createSessionStorage({ - cookie, - async createData(data, expires) { - const content = JSON.stringify({ data, expires }); - - while (true) { - const randomBytes = crypto.getRandomValues(new Uint8Array(8)); - - // This storage manages an id space of 2^64 ids, which is far greater - // than the maximum number of files allowed on an NTFS or ext4 volume - // (2^32). However, the larger id space should help to avoid collisions - // with existing ids when creating new sessions, which speeds things up. - let id = ""; - for (let i = 0; i < randomBytes.length; ++i) { - id += ("0" + randomBytes[i].toString(16)).slice(-2); - } - - try { - const file = getFile(dir, id); - const exists = await Deno.stat(file) - .then((s) => s.isFile) - .catch(() => false); - if (exists) continue; - - await Deno.mkdir(path.dirname(file), { recursive: true }).catch( - () => {} - ); - await Deno.writeFile(file, new TextEncoder().encode(content)); - - return id; - } catch (error) { - if (error.code !== "EEXIST") throw error; - } - } - }, - async readData(id) { - try { - const file = getFile(dir, id); - const content = JSON.parse(await Deno.readTextFile(file)); - const data = content.data; - const expires = - typeof content.expires === "string" - ? new Date(content.expires) - : null; - - if (!expires || expires > new Date()) { - return data; - } - - // Remove expired session data. - if (expires) await Deno.remove(file); - - return null; - } catch (error) { - if (error.code !== "ENOENT") throw error; - return null; - } - }, - async updateData(id, data, expires) { - const content = JSON.stringify({ data, expires }); - const file = getFile(dir, id); - await Deno.mkdir(path.dirname(file), { recursive: true }).catch(() => {}); - await Deno.writeTextFile(file, content); - }, - async deleteData(id) { - try { - await Deno.remove(getFile(dir, id)); - } catch (error) { - if (error.code !== "ENOENT") throw error; - } - }, - }); -} - -function getFile(dir: string, id: string): string { - // Divide the session id up into a directory (first 2 bytes) and filename - // (remaining 6 bytes) to reduce the chance of having very large directories, - // which should speed up file access. This is a maximum of 2^16 directories, - // each with 2^48 files. - return path.join(dir, id.slice(0, 4), id.slice(4)); -} diff --git a/templates/deno/remix.config.js b/templates/deno/remix.config.js index 165a13b8001..625a152107a 100644 --- a/templates/deno/remix.config.js +++ b/templates/deno/remix.config.js @@ -1,4 +1,12 @@ module.exports = { serverBuildTarget: "deno", server: "./server.ts", + + /* + If live reload causes page to re-render without changes (live reload is too fast), + increase the dev server broadcast delay. + + If live reload seems slow, try to decrease the dev server broadcast delay. + */ + devServerBroadcastDelay: 300, }; diff --git a/templates/deno/server.ts b/templates/deno/server.ts index 187e6cd27d1..87e95bf7b18 100644 --- a/templates/deno/server.ts +++ b/templates/deno/server.ts @@ -1,12 +1,10 @@ import { serve } from "https://deno.land/std@0.128.0/http/server.ts"; -// Temporary: in the future, import from `@remix-run/deno` at some URL -import { createRequestHandlerWithStaticFiles } from "./remix-deno/index.ts"; +import { createRequestHandlerWithStaticFiles } from "@remix-run/deno"; // Import path interpreted by the Remix compiler import * as build from "@remix-run/dev/server-build"; const remixHandler = createRequestHandlerWithStaticFiles({ build, - // process.env.NODE_ENV is provided by Remix at compile time mode: process.env.NODE_ENV, getLoadContext: () => ({}), });