diff --git a/.eslintrc.json b/.eslintrc.json
index 4ffeeca..38b2f49 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,3 +1,3 @@
{
- "extends": ["@remix-run", "prettier"]
+ "extends": ["@remix-run", "prettier"]
}
diff --git a/.prettierrc b/.prettierrc
index 8e3601c..bb9ca71 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,3 +1,4 @@
# Prettier Configuration
# All supported options are listed here: https://prettier.io/docs/en/options.html
singleQuote: true
+useTabs: true
diff --git a/README.md b/README.md
index ae07b54..648d68c 100644
--- a/README.md
+++ b/README.md
@@ -1,65 +1,41 @@
-# remix-worker-template
+# remix-cloudflare-template
Learn more about [Remix Stacks](https://remix.run/stacks).
```
-npx create-remix --template edmundhung/remix-worker-template
+npx create-remix --template edmundhung/remix-cloudflare-template
```
What's included?
-- Deploying to [Cloudflare Workers](https://workers.cloudflare.com/)
-- Supporting [Durable objects](https://developers.cloudflare.com/workers/learning/using-durable-objects) with [module workers](https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/)
-- CI/CD through [Github Actions](https://github.com/features/actions)
+- Deploying to [Cloudflare Page](https://workers.cloudflare.com/)
+- CI on [Github Actions](https://github.com/features/actions)
- Styling with [Tailwind](https://tailwindcss.com/)
-- Testing with [Playwright](playwright.dev/) with _undici_ mocking support
+- Testing using [Playwright](playwright.dev/) with _undici_ mocking support
- Code formatting with [Prettier](https://prettier.io)
- Linting with [ESLint](https://eslint.org)
- Static Types with [TypeScript](https://typescriptlang.org)
## Node Version
-Please make sure the node version is **>= 16.7**. If you are using `nvm`, just run:
-
-```sh
-nvm use
-```
-
-This allows [miniflare](https://github.com/cloudflare/miniflare) to serve a development environment as close to the actual worker runtime as possibile.
+Please make sure the node version is **>= 18**.
## Development
-To starts your app in development mode, rebuilding assets on file changes, the recommended approach is:
+To starts your app with the vite dev server, run the following command:
```sh
npm run dev
```
-This will run your remix app in dev mode using miniflare.
-
## Testing
-Before running the tests, please ensure the worker is built:
+Before running the tests, please ensure the app is built:
```sh
npm run build && npm run test
```
-## Deployment
-
-To deploy your Remix app, simply do it with Wrangler using:
-
-```sh
-npx wrangler publish
-```
-
## CI/CD
-The template ships a [development workflow](./.github/workflows/development.yml) which is triggered whenever new changes are pushed.
-
-To allow GitHub deploying the worker for you, following variables are required:
-
-- CF_API_TOKEN
-- CF_ACCOUNT_ID
-
-These values could be found / created on your Cloudflare Dashboard
+The template ships a [CI workflow](./.github/workflows/ci.yml) which is triggered whenever new changes are pushed.
diff --git a/app/components.tsx b/app/components.tsx
new file mode 100644
index 0000000..3de3d41
--- /dev/null
+++ b/app/components.tsx
@@ -0,0 +1,30 @@
+import * as React from 'react';
+import markdoc, { type RenderableTreeNodes } from '@markdoc/markdoc';
+
+export function RemixLogo(props: React.ComponentPropsWithoutRef<'svg'>) {
+ return (
+
+ Remix Logo
+
+
+
+
+
+
+ );
+}
+
+export function Markdown({ content }: { content: RenderableTreeNodes }) {
+ return
{markdoc.renderers.react(content, React)}
;
+}
diff --git a/app/root.tsx b/app/root.tsx
index e52b68d..7118f7a 100644
--- a/app/root.tsx
+++ b/app/root.tsx
@@ -1,16 +1,20 @@
-import type { MetaFunction, LoaderFunction } from '@remix-run/cloudflare';
+import type { MetaFunction } from '@remix-run/cloudflare';
import * as React from 'react';
import {
- Link,
- Links,
- Meta,
- Outlet,
- Scripts,
- ScrollRestoration,
- isRouteErrorResponse,
- useRouteError,
+ Link,
+ Links,
+ Meta,
+ Outlet,
+ Scripts,
+ ScrollRestoration,
+ isRouteErrorResponse,
+ json,
+ useLoaderData,
+ useRouteError,
} from '@remix-run/react';
import '~/styles.css';
+import { metadata } from './services/github.server';
+import { RemixLogo } from './components';
// We will rollback to loading CSS through links when `.css?url` is supported
// export const links: LinksFunction = () => {
@@ -18,153 +22,149 @@ import '~/styles.css';
// };
export const meta: MetaFunction = () => {
- return [
- {
- charset: 'utf-8',
- // title: 'Conform Playground',
- viewport: 'width=device-width,initial-scale=1',
- },
- ];
+ return [
+ {
+ charset: 'utf-8',
+ title: 'remix-cloudlfare-template',
+ viewport: 'width=device-width,initial-scale=1',
+ },
+ ];
};
-export const loader: LoaderFunction = async () => {
- return { date: new Date() };
-};
+export function loader() {
+ return json({
+ repo: metadata.repo,
+ owner: metadata.owner,
+ description: '📜 All-in-one remix starter template for Cloudflare Pages',
+ });
+}
export default function App() {
- return (
-
-
-
-
-
- );
+ const { repo, owner, description } = useLoaderData();
+ return (
+
+
+
+
+
+ );
}
function Document({
- children,
- title,
+ children,
+ title,
}: {
- children: React.ReactNode;
- title?: string;
+ children: React.ReactNode;
+ title?: string;
}) {
- return (
-
-
-
- {title ? {title} : null}
-
-
-
-
- {children}
-
-
-
-
- );
+ return (
+
+
+
+ {title ? {title} : null}
+
+
+
+
+ {children}
+
+
+
+
+ );
}
-function Layout({ children }: React.PropsWithChildren<{}>) {
- return (
-
- );
+function Layout({
+ children,
+ title,
+ description,
+ actionText,
+ actionLink,
+}: {
+ children?: React.ReactNode;
+ title?: string;
+ description?: string;
+ actionText?: string;
+ actionLink?: string;
+}) {
+ return (
+
+ );
}
export function ErrorBoundary() {
- const error = useRouteError();
-
- // Log the error to the console
- console.error(error);
+ const error = useRouteError();
- if (isRouteErrorResponse(error)) {
- let message;
- switch (error.status) {
- case 401:
- message = (
-
- Oops! Looks like you tried to visit a page that you do not have
- access to.
-
- );
- break;
- case 404:
- message = (
- Oops! Looks like you tried to visit a page that does not exist.
- );
- break;
+ // Log the error to the console
+ console.error(error);
- default:
- throw new Error(error.data || error.statusText);
- }
+ if (isRouteErrorResponse(error)) {
+ const title = `${error.status} ${error.statusText}`;
- return (
-
-
-
- {error.status}: {error.statusText}
-
- {message}
-
-
- );
- }
+ let message;
+ switch (error.status) {
+ case 401:
+ message =
+ 'Oops! Looks like you tried to visit a page that you do not have access to.';
+ break;
+ case 404:
+ message =
+ 'Oops! Looks like you tried to visit a page that does not exist.';
+ break;
+ default:
+ throw new Error(error.data || error.statusText);
+ }
- return (
-
-
-
-
There was an error
-
{`${error}`}
-
-
- Hey, developer, you should replace this with what you want your
- users to see.
-
-
-
-
- );
-}
+ return (
+
+
+
+ );
+ }
-function RemixLogo(props: React.ComponentPropsWithoutRef<'svg'>) {
- return (
-
- Remix Logo
-
-
-
-
-
-
- );
+ return (
+
+
+
+ );
}
diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx
index 42ac1ea..f0e477e 100644
--- a/app/routes/_index.tsx
+++ b/app/routes/_index.tsx
@@ -1,39 +1,26 @@
-import type { MetaFunction, LoaderFunctionArgs } from '@remix-run/cloudflare';
-import { useLoaderData } from '@remix-run/react';
+import type { LoaderFunctionArgs } from '@remix-run/cloudflare';
+import { json, useLoaderData } from '@remix-run/react';
+import { Markdown } from '~/components';
+import { getFileContentWithCache } from '~/services/github.server';
+import { parse } from '~/services/markdoc.server';
-export const meta: MetaFunction = () => {
- return [
- { title: 'remix-worker-template' },
- { description: 'All-in-one remix starter template for Cloudflare Workers' },
- ];
-};
+export async function loader({ context }: LoaderFunctionArgs) {
+ const content = await getFileContentWithCache(context, 'README.md');
-export function loader({ request }: LoaderFunctionArgs) {
- return {
- title: 'remix-worker-template',
- };
+ return json(
+ {
+ content: parse(content),
+ },
+ {
+ headers: {
+ 'Cache-Control': 'public, max-age=3600',
+ },
+ },
+ );
}
export default function Index() {
- const { title } = useLoaderData();
+ const { content } = useLoaderData();
- return (
-
- );
+ return ;
}
diff --git a/app/services/github.server.ts b/app/services/github.server.ts
new file mode 100644
index 0000000..51d87b5
--- /dev/null
+++ b/app/services/github.server.ts
@@ -0,0 +1,77 @@
+import type { Endpoints } from '@octokit/types';
+import type { AppLoadContext } from '@remix-run/cloudflare';
+
+export const metadata = {
+ repo: 'remix-cloudflare-template',
+ owner: 'edmundhung',
+};
+
+export function getHeaders(auth: string | undefined) {
+ const headers = new Headers({
+ Accept: 'application/vnd.github+json',
+ 'User-Agent': 'Conform Guide',
+ });
+
+ if (auth) {
+ headers.set('Authorization', `Bearer ${auth}`);
+ }
+
+ return headers;
+}
+
+export async function getFileContent(options: {
+ auth?: string;
+ ref?: string;
+ path: string;
+ owner: string;
+ repo: string;
+}): Promise {
+ const searchParams = new URLSearchParams();
+
+ if (options.ref) {
+ searchParams.set('ref', options.ref);
+ }
+
+ const url = `https://api.github.com/repos/${options.owner}/${options.repo}/contents/${options.path}?${searchParams}`;
+ const resposne = await fetch(url, {
+ headers: getHeaders(options.auth),
+ });
+
+ if (resposne.status === 404) {
+ throw resposne;
+ }
+
+ const file: Endpoints['GET /repos/{owner}/{repo}/contents/{path}']['response']['data'] =
+ await resposne.json();
+
+ if (Array.isArray(file) || file.type !== 'file') {
+ throw new Response('Not found', { status: 404 });
+ }
+
+ return atob(file.content);
+}
+
+export async function getFileContentWithCache(
+ context: AppLoadContext,
+ path: string,
+): Promise {
+ const key = `github/${path}`;
+ const cache = await context.env.CACHE.get(key);
+
+ if (cache) {
+ return cache;
+ }
+
+ const content = await getFileContent({
+ auth: context.env.GITHUB_TOKEN,
+ owner: metadata.owner,
+ repo: metadata.repo,
+ path,
+ });
+
+ // Update the cache
+ // TODO: Use `waitUntil` to update the cache in the background
+ await context.env.CACHE.put(key, content, { expirationTtl: 60 * 60 });
+
+ return content;
+}
diff --git a/app/services/markdoc.server.tsx b/app/services/markdoc.server.tsx
new file mode 100644
index 0000000..85a6526
--- /dev/null
+++ b/app/services/markdoc.server.tsx
@@ -0,0 +1,8 @@
+import markdoc from '@markdoc/markdoc';
+
+export function parse(markdown: string) {
+ const ast = markdoc.parse(markdown);
+ const node = markdoc.transform(ast);
+
+ return node;
+}
diff --git a/env.d.ts b/env.d.ts
index 009c0ed..973e98e 100644
--- a/env.d.ts
+++ b/env.d.ts
@@ -3,12 +3,14 @@ import '@remix-run/cloudflare';
import '@cloudflare/workers-types';
interface Env {
- ENVIRONMENT?: 'development';
+ ENVIRONMENT?: 'development';
+ GITHUB_TOKEN?: string;
+ CACHE: KVNamespace;
}
declare module '@remix-run/cloudflare' {
- export interface AppLoadContext {
- env: Env;
- waitUntil(promise: Promise): void;
- }
+ export interface AppLoadContext {
+ env: Env;
+ waitUntil(promise: Promise): void;
+ }
}
diff --git a/functions/[[path]].ts b/functions/[[path]].ts
index d7db3b9..38c4358 100644
--- a/functions/[[path]].ts
+++ b/functions/[[path]].ts
@@ -6,11 +6,11 @@ import { createPagesFunctionHandler } from '@remix-run/cloudflare-pages';
import * as build from '../build/server';
export const onRequest = createPagesFunctionHandler({
- build,
- getLoadContext: (context) => ({
- env: context.env,
- waitUntil(promise: Promise) {
- context.waitUntil(promise);
- },
- }),
+ build,
+ getLoadContext: (context) => ({
+ env: context.env,
+ waitUntil(promise: Promise) {
+ context.waitUntil(promise);
+ },
+ }),
});
diff --git a/package.json b/package.json
index 6b00570..91d0dbc 100644
--- a/package.json
+++ b/package.json
@@ -1,55 +1,58 @@
{
- "private": true,
- "name": "remix-worker-template",
- "description": "All-in-one remix starter template for Cloudflare Pages",
- "module": "./dist/worker.mjs",
- "scripts": {
- "dev": "remix vite:dev",
- "test": "NODE_OPTIONS=\"--experimental-vm-modules --no-warnings\" playwright test",
- "start": "wrangler pages dev ./build/client",
- "build": "remix vite:build",
- "cleanup": "rimraf .cache ./build ./public/build",
- "lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .",
- "typecheck": "tsc",
- "prepare": "husky install"
- },
- "dependencies": {
- "@remix-run/cloudflare": "*",
- "@remix-run/cloudflare-pages": "*",
- "@remix-run/react": "*",
- "isbot": "^3.6.5",
- "react": "^18.2.0",
- "react-dom": "^18.2.0"
- },
- "devDependencies": {
- "@cloudflare/workers-types": "^4.20240208.0",
- "@playwright/test": "^1.41.2",
- "@remix-run/dev": "*",
- "@remix-run/eslint-config": "*",
- "@types/react": "^18.2.55",
- "@types/react-dom": "^18.2.19",
- "autoprefixer": "^10.4.17",
- "concurrently": "^8.2.2",
- "cross-env": "^7.0.3",
- "eslint": "^8.56.0",
- "eslint-config-prettier": "^9.1.0",
- "husky": "^9.0.10",
- "lint-staged": "^15.2.2",
- "miniflare": "^3.20240129.1",
- "postcss": "^8.4.35",
- "prettier": "^3.2.5",
- "rimraf": "^5.0.5",
- "tailwindcss": "^3.4.1",
- "typescript": "^5.3.3",
- "vite": "^5.1.1",
- "vite-tsconfig-paths": "^4.3.1",
- "wrangler": "^3.28.1"
- },
- "engines": {
- "node": ">=18"
- },
- "sideEffects": false,
- "lint-staged": {
- "*.{js,mjs,ts,tsx,css,md,yml}": "prettier --write"
- }
+ "private": true,
+ "name": "remix-worker-template",
+ "description": "All-in-one remix starter template for Cloudflare Pages",
+ "module": "./dist/worker.mjs",
+ "scripts": {
+ "dev": "remix vite:dev",
+ "test": "NODE_OPTIONS=\"--experimental-vm-modules --no-warnings\" playwright test",
+ "start": "wrangler pages dev ./build/client",
+ "build": "remix vite:build",
+ "cleanup": "rimraf .cache ./build ./public/build",
+ "lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .",
+ "typecheck": "tsc",
+ "prepare": "husky install"
+ },
+ "dependencies": {
+ "@markdoc/markdoc": "^0.4.0",
+ "@remix-run/cloudflare": "*",
+ "@remix-run/cloudflare-pages": "*",
+ "@remix-run/react": "*",
+ "isbot": "^3.6.5",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@cloudflare/workers-types": "^4.20240208.0",
+ "@octokit/types": "^12.4.0",
+ "@playwright/test": "^1.41.2",
+ "@remix-run/dev": "*",
+ "@remix-run/eslint-config": "*",
+ "@tailwindcss/typography": "^0.5.10",
+ "@types/react": "^18.2.55",
+ "@types/react-dom": "^18.2.19",
+ "autoprefixer": "^10.4.17",
+ "concurrently": "^8.2.2",
+ "cross-env": "^7.0.3",
+ "eslint": "^8.56.0",
+ "eslint-config-prettier": "^9.1.0",
+ "husky": "^9.0.10",
+ "lint-staged": "^15.2.2",
+ "miniflare": "^3.20240129.1",
+ "postcss": "^8.4.35",
+ "prettier": "^3.2.5",
+ "rimraf": "^5.0.5",
+ "tailwindcss": "^3.4.1",
+ "typescript": "^5.3.3",
+ "vite": "^5.1.1",
+ "vite-tsconfig-paths": "^4.3.1",
+ "wrangler": "^3.28.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "sideEffects": false,
+ "lint-staged": {
+ "*.{js,mjs,ts,tsx,css,md,yml}": "prettier --write"
+ }
}
diff --git a/playwright.config.ts b/playwright.config.ts
index 03f685b..a74c062 100644
--- a/playwright.config.ts
+++ b/playwright.config.ts
@@ -1,24 +1,24 @@
import { type PlaywrightTestConfig, devices } from '@playwright/test';
const config: PlaywrightTestConfig = {
- forbidOnly: !!process.env.CI,
- retries: process.env.CI ? 2 : 0,
- use: {
- trace: 'on-first-retry',
- },
- projects: [
- {
- name: 'chromium',
- use: { ...devices['Desktop Chrome'] },
- },
- {
- name: 'firefox',
- use: { ...devices['Desktop Firefox'] },
- },
- {
- name: 'webkit',
- use: { ...devices['Desktop Safari'] },
- },
- ],
+ forbidOnly: !!process.env.CI,
+ retries: process.env.CI ? 2 : 0,
+ use: {
+ trace: 'on-first-retry',
+ },
+ projects: [
+ {
+ name: 'chromium',
+ use: { ...devices['Desktop Chrome'] },
+ },
+ {
+ name: 'firefox',
+ use: { ...devices['Desktop Firefox'] },
+ },
+ {
+ name: 'webkit',
+ use: { ...devices['Desktop Safari'] },
+ },
+ ],
};
export default config;
diff --git a/postcss.config.js b/postcss.config.js
index 12a703d..e873f1a 100644
--- a/postcss.config.js
+++ b/postcss.config.js
@@ -1,6 +1,6 @@
module.exports = {
- plugins: {
- tailwindcss: {},
- autoprefixer: {},
- },
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
};
diff --git a/scripts/build.mjs b/scripts/build.mjs
deleted file mode 100644
index b146989..0000000
--- a/scripts/build.mjs
+++ /dev/null
@@ -1,34 +0,0 @@
-import * as esbuild from 'esbuild';
-
-async function build() {
- // eslint-disable-next-line no-undef
- const mode = process.env.NODE_ENV?.toLowerCase() ?? 'development';
-
- console.log(`Building Worker in ${mode} mode`);
-
- const outfile = './dist/worker.mjs';
- const startTime = Date.now();
- const result = await esbuild.build({
- entryPoints: ['./worker/index.ts'],
- bundle: true,
- minify: mode === 'production',
- sourcemap: mode !== 'production',
- format: 'esm',
- metafile: true,
- external: ['__STATIC_CONTENT_MANIFEST'],
- define: {
- 'process.env.NODE_ENV': `"${mode}"`,
- 'process.env.REMIX_DEV_SERVER_WS_PORT': `"8002"`,
- },
- outfile,
- });
- const endTime = Date.now();
-
- console.log(`Built in ${endTime - startTime}ms`);
-
- if (mode === 'production') {
- console.log(await esbuild.analyzeMetafile(result.metafile));
- }
-}
-
-build().catch((e) => console.error('Unknown error caught during build:', e));
diff --git a/tailwind.config.js b/tailwind.config.js
index e2cd1f2..91f1831 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,5 +1,5 @@
module.exports = {
- content: ['./app/**/*.tsx', './app/**/*.ts'],
- theme: {},
- plugins: [],
+ content: ['./app/**/*.tsx', './app/**/*.ts'],
+ theme: {},
+ plugins: [require('@tailwindcss/typography')],
};
diff --git a/tests/index.spec.ts b/tests/index.spec.ts
index 1c46169..30e90a3 100644
--- a/tests/index.spec.ts
+++ b/tests/index.spec.ts
@@ -1,18 +1,18 @@
import { test, expect } from './setup';
test.beforeEach(async ({ page }) => {
- await page.goto('/');
+ await page.goto('/');
});
/**
* You can interact with the page or browser through the page / queries
*/
test('if the page shows the package name', async ({ page }) => {
- const title = page.getByText('remix-worker-template', {
- exact: false,
- });
+ const title = page.getByText('remix-worker-template', {
+ exact: false,
+ });
- await expect(title).toBeVisible();
+ await expect(title).toBeVisible();
});
/**
@@ -21,12 +21,12 @@ test('if the page shows the package name', async ({ page }) => {
* Or even interacting with the DO by `mf.getDurableObjectNamespace(...)`
*/
test('if the binding are set properly', async ({ mf }) => {
- const bindings = await mf.getBindings();
+ const bindings = await mf.getBindings();
- expect(bindings).toEqual({
- __STATIC_CONTENT: expect.anything(),
- __STATIC_CONTENT_MANIFEST: expect.anything(),
- });
+ expect(bindings).toEqual({
+ __STATIC_CONTENT: expect.anything(),
+ __STATIC_CONTENT_MANIFEST: expect.anything(),
+ });
});
/**
@@ -34,16 +34,16 @@ test('if the binding are set properly', async ({ mf }) => {
* @see https://github.com/nodejs/undici/blob/main/docs/api/MockAgent.md
*/
test('if the request is sent', async ({ mockAgent }) => {
- const client = mockAgent.get('http://example.com');
-
- client
- .intercept({
- method: 'GET',
- path: '/hello-world',
- })
- .reply(200, {
- foo: 'bar',
- });
-
- // expect() something happens
+ const client = mockAgent.get('http://example.com');
+
+ client
+ .intercept({
+ method: 'GET',
+ path: '/hello-world',
+ })
+ .reply(200, {
+ foo: 'bar',
+ });
+
+ // expect() something happens
});
diff --git a/tests/setup.ts b/tests/setup.ts
index 842b295..e0dd087 100644
--- a/tests/setup.ts
+++ b/tests/setup.ts
@@ -4,66 +4,66 @@ import { MockAgent, setGlobalDispatcher } from 'undici';
import packageJson from '../package.json';
interface TestFixtures {
- mockAgent: MockAgent;
+ mockAgent: MockAgent;
}
interface WorkerFixtures {
- mf: Miniflare;
- port: number;
+ mf: Miniflare;
+ port: number;
}
export { expect };
export const test = base.extend({
- // Assign a unique "port" for each worker process
- port: [
- // eslint-disable-next-line no-empty-pattern
- async ({}, use, workerInfo) => {
- await use(3001 + workerInfo.workerIndex);
- },
- { scope: 'worker' },
- ],
+ // Assign a unique "port" for each worker process
+ port: [
+ // eslint-disable-next-line no-empty-pattern
+ async ({}, use, workerInfo) => {
+ await use(3001 + workerInfo.workerIndex);
+ },
+ { scope: 'worker' },
+ ],
- // Ensure visits works with relative path
- baseURL: ({ port }, use) => {
- use(`http://localhost:${port}`);
- },
+ // Ensure visits works with relative path
+ baseURL: ({ port }, use) => {
+ use(`http://localhost:${port}`);
+ },
- // Setup mock client for requests initiated by the Worker
- mockAgent:
- // eslint-disable-next-line no-empty-pattern
- async ({}, use) => {
- const mockAgent = new MockAgent();
+ // Setup mock client for requests initiated by the Worker
+ mockAgent:
+ // eslint-disable-next-line no-empty-pattern
+ async ({}, use) => {
+ const mockAgent = new MockAgent();
- // Optional: This makes all the request fails if no matching mock is found
- // mockAgent.disableNetConnect();
+ // Optional: This makes all the request fails if no matching mock is found
+ // mockAgent.disableNetConnect();
- setGlobalDispatcher(mockAgent);
+ setGlobalDispatcher(mockAgent);
- await use(mockAgent);
- },
+ await use(mockAgent);
+ },
- // Miniflare instance
- mf: [
- async ({ port }, use) => {
- const mf = new Miniflare({
- scriptPath: packageJson.module,
- modules: true,
- wranglerConfigPath: true,
- port,
- });
+ // Miniflare instance
+ mf: [
+ async ({ port }, use) => {
+ const mf = new Miniflare({
+ scriptPath: packageJson.module,
+ modules: true,
+ wranglerConfigPath: true,
+ port,
+ });
- // Start the server.
- let server = await mf.startServer();
+ // Start the server.
+ let server = await mf.startServer();
- // Use the server in the tests.
- await use(mf);
+ // Use the server in the tests.
+ await use(mf);
- // Cleanup.
- await new Promise((resolve, reject) => {
- server.close((error) => (error ? reject(error) : resolve()));
- });
- },
- { scope: 'worker', auto: true },
- ],
+ // Cleanup.
+ await new Promise((resolve, reject) => {
+ server.close((error) => (error ? reject(error) : resolve()));
+ });
+ },
+ { scope: 'worker', auto: true },
+ ],
});
diff --git a/vite.config.ts b/vite.config.ts
index 68aa6c4..c79c48f 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,26 +1,26 @@
import {
- unstable_vitePlugin as remix,
- unstable_cloudflarePreset as cloudflare,
+ unstable_vitePlugin as remix,
+ unstable_cloudflarePreset as cloudflare,
} from '@remix-run/dev';
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
- plugins: [
- remix({
- presets: [
- cloudflare({
- getRemixDevLoadContext(context) {
- return context;
- },
- }),
- ],
- }),
- tsconfigPaths(),
- ],
- ssr: {
- resolve: {
- externalConditions: ['workerd', 'worker'],
- },
- },
+ plugins: [
+ remix({
+ presets: [
+ cloudflare({
+ getRemixDevLoadContext(context) {
+ return context;
+ },
+ }),
+ ],
+ }),
+ tsconfigPaths(),
+ ],
+ ssr: {
+ resolve: {
+ externalConditions: ['workerd', 'worker'],
+ },
+ },
});
diff --git a/wrangler.toml b/wrangler.toml
index 7ebe8ae..d829a1f 100644
--- a/wrangler.toml
+++ b/wrangler.toml
@@ -1,8 +1,4 @@
-name = "template"
-main = "./dist/worker.mjs"
-# route = "example.com/*"
-compatibility_date = "2022-11-25"
-compatibility_flags = ["streams_enable_constructors"]
-
-[site]
-bucket = "./public"
\ No newline at end of file
+name = "remix-cloudflare-template"
+kv_namespaces = [
+ { id = "CACHE", binding="CACHE" }
+]
\ No newline at end of file