Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions apps/site/cloudflare/worker-entrypoint.ts
Comment thread
ovflowd marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Note: this custom worker-entrypoint is used so that the worker can include sentry support
// and it has been written by following:
// - the official open-next docs: https://opennext.js.org/cloudflare/howtos/custom-worker
// - the official sentry docs: https://docs.sentry.io/platforms/javascript/guides/cloudflare

import { setTags, withSentry } from '@sentry/cloudflare';

import type {
ExecutionContext,
Iso3166Alpha2Code,
Request,
} from '@cloudflare/workers-types';

import { default as handler } from '../.open-next/worker.js';

export default withSentry(
(env: {
/**
* Sentry DSN, used for error monitoring
* If missing, Sentry isn't used
*/
SENTRY_DSN?: string;
}) => ({
dsn: env.SENTRY_DSN,
Comment thread
flakey5 marked this conversation as resolved.
// Enable logs to be sent to Sentry
enableLogs: true,
// Set tracesSampleRate to 0.05 to capture 5% of spans for tracing.
// Learn more at
// https://docs.sentry.io/platforms/javascript/guides/cloudflare/configuration/options/#tracesSampleRate
tracesSampleRate: 0.05,
}),
{
async fetch(
Comment thread
ovflowd marked this conversation as resolved.
request: Request,
env: Record<string, unknown>,
ctx: ExecutionContext
) {
setTags({
request_id: crypto.randomUUID(),
user_agent: request.headers.get('user-agent'),
ray_id: request.headers.get('cf-ray'),

// Type casts needed to keep lsp happy
ip_country: request.cf?.country as Iso3166Alpha2Code | undefined,
colo: request.cf?.colo as string | undefined,
});

return handler.fetch(request, env, ctx);
},
}
);

export { DOQueueHandler } from '../.open-next/worker.js';
10 changes: 9 additions & 1 deletion apps/site/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ import baseConfig from '../../eslint.config.js';

export default baseConfig.concat([
{
ignores: ['pages/en/blog/**/*.{md,mdx}/**', 'public', 'next-env.d.ts'],
ignores: [
'pages/en/blog/**/*.{md,mdx}/**',
'public',
'next-env.d.ts',
// The worker entrypoint is bundled by wrangler, not tsc. Its imports
// trigger a tsc crash (see tsconfig.json), so it is excluded from both
// type checking and ESLint's type-aware linting.
'cloudflare/worker-entrypoint.ts',
],
Comment thread
ovflowd marked this conversation as resolved.
},

eslintReact.configs['recommended-typescript'],
Expand Down
4 changes: 3 additions & 1 deletion apps/site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@
"typescript": "catalog:",
"typescript-eslint": "~8.57.2",
"user-agent-data-types": "0.4.2",
"wrangler": "^4.77.0"
"wrangler": "^4.77.0",
"@cloudflare/workers-types": "^4.20260418.1",
"@sentry/cloudflare": "^10.49.0"
Comment thread
ovflowd marked this conversation as resolved.
},
"imports": {
"#site/*": [
Expand Down
11 changes: 10 additions & 1 deletion apps/site/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,14 @@
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": ["node_modules", ".next"]
"exclude": [
"node_modules",
".next",
".open-next",
// The worker entrypoint is bundled by wrangler (not tsc). Its imports of
// @sentry/cloudflare and .open-next/worker.js trigger an infinite-recursion
// crash in the TypeScript compiler (v5.9) during type resolution of
// @cloudflare/workers-types, so we exclude it from type checking.
"cloudflare/worker-entrypoint.ts"
Comment thread
ovflowd marked this conversation as resolved.
]
}
7 changes: 6 additions & 1 deletion apps/site/wrangler.jsonc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "./node_modules/wrangler/config-schema.json",
"main": ".open-next/worker.js",
"main": "./cloudflare/worker-entrypoint.ts",
"name": "nodejs-website",
"compatibility_date": "2024-11-07",
"compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
Expand Down Expand Up @@ -59,4 +59,9 @@
"new_sqlite_classes": ["DOQueueHandler"],
},
],
"version_metadata": {
// CF_VERSION_METADATA used for sentry
// See: https://docs.sentry.io/platforms/javascript/guides/cloudflare/#release-configuration-optional
"binding": "CF_VERSION_METADATA",
},
}
21 changes: 20 additions & 1 deletion docs/cloudflare-build-and-deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ For more details, refer to the [Wrangler documentation](https://developers.cloud

Key configurations include:

- `main`: Points to the worker generated by the OpenNext adapter.
- `main`: Points to a custom worker entry point ([`site/cloudflare/worker-entrypoint.ts`](../apps/site/cloudflare/worker-entrypoint.ts)) that wraps the OpenNext-generated worker (see [Custom Worker Entry Point](#custom-worker-entry-point) and [Sentry](#sentry) below).
- `account_id`: Specifies the Cloudflare account ID. This is not required for local previews but is necessary for deployments. You can obtain an account ID for free by signing up at [dash.cloudflare.com](https://dash.cloudflare.com/login).
- This is currently set to `fb4a2d0f103c6ff38854ac69eb709272`, which is the ID of a Cloudflare account controlled by Node.js, and used for testing.
- `build`: Defines the build command to generate the Node.js filesystem polyfills required for the application to run on Cloudflare Workers. This uses the [`@flarelabs/wrangler-build-time-fs-assets-polyfilling`](https://github.com/flarelabs-net/wrangler-build-time-fs-assets-polyfilling) package.
- `alias`: Maps aliases for the Node.js filesystem polyfills generated during the build process.
- `r2_buckets`: Contains a single R2 binding definition for `NEXT_INC_CACHE_R2_BUCKET`. This is used to implement the Next.js incremental cache.
- This is currently set up to a R2 bucket in the aforementioned Cloudflare testing account.
- `durable_objects`: Contains a single DurableObject binding definition for `NEXT_CACHE_DO_QUEUE`. This is used to implement the Open-next cache queue.
- `version_metadata`: Contains a binding for `CF_VERSION_METADATA`, used for Sentry release configuration (see [Sentry](#sentry) below).

### OpenNext Configuration

Expand Down Expand Up @@ -54,6 +55,24 @@ The custom loader can be found at [`site/cloudflare/image-loader.ts`](../apps/si

For more details on this see: https://developers.cloudflare.com/images/transform-images/integrate-with-frameworks/#global-loader

### Custom Worker Entry Point

Instead of directly using the OpenNext-generated worker (`.open-next/worker.js`), the application uses a custom worker entry point at [`site/cloudflare/worker-entrypoint.ts`](../apps/site/cloudflare/worker-entrypoint.ts). This allows customizing the worker's behavior before requests are handled (currently used to integrate [Sentry](#sentry) error monitoring).

The custom entry point imports the OpenNext-generated handler from `.open-next/worker.js` and re-exports the `DOQueueHandler` Durable Object needed by the application.

For more details on custom workers, refer to the [OpenNext custom worker documentation](https://opennext.js.org/cloudflare/howtos/custom-worker).

### Sentry

Error monitoring is provided by [Sentry](https://sentry.io/) via the [`@sentry/cloudflare`](https://www.npmjs.com/package/@sentry/cloudflare) package.

The [custom worker entry point](#custom-worker-entry-point) wraps the OpenNext handler with `Sentry.withSentry()`, which instruments incoming requests for error and performance tracking.

The `version_metadata` binding (`CF_VERSION_METADATA`) in the Wrangler configuration enables Sentry [release configuration](https://docs.sentry.io/platforms/javascript/guides/cloudflare/#release-configuration-optional), allowing errors to be associated with specific worker versions.

Comment thread
ovflowd marked this conversation as resolved.
For more details, refer to the [Sentry Cloudflare guide](https://docs.sentry.io/platforms/javascript/guides/cloudflare).

## Scripts

Preview and deployment of the website targeting the Cloudflare network is implemented via the following two commands:
Expand Down
Loading
Loading