diff --git a/public/__redirects b/public/__redirects index 78b4e67f9445841..7fa5a3925d85a3d 100644 --- a/public/__redirects +++ b/public/__redirects @@ -1584,7 +1584,9 @@ /workers/tutorials/create-sitemap-from-sanity-cms/ /developer-spotlight/tutorials/create-sitemap-from-sanity-cms/ 301 /workers/tutorials/custom-access-control-for-files-in-r2-using-d1-and-workers/ /developer-spotlight/tutorials/custom-access-control-for-files/ 301 /workers/tutorials/generate-dynamic-og-images-using-workers/ /workers/tutorials/ 302 -/workers/static-assets/compatibility-matrix/ /workers/static-assets/migrate-from-pages/ 301 +/workers/static-assets/migrate-from-pages/ /workers/static-assets/migration-guides/migrate-from-pages/ 301 +/workers/static-assets/compatibility-matrix/ /workers/static-assets/migration-guides/migrate-from-pages/ 301 +/workers/static-assets/migrations/vercel-to-workers/ /workers/static-assets/migration-guides/vercel-to-workers/ 301 /workers/frameworks/framework-guides/remix/ /workers/frameworks/framework-guides/react-router/ 301 /workers/testing/unit-testing/ /workers/testing/vitest-integration/write-your-first-test/ 301 /workers/testing/integration-testing/ /workers/testing/ 301 diff --git a/src/components/DirectoryListing.astro b/src/components/DirectoryListing.astro index 17a56f5b8486948..2b8e3d1d9192060 100644 --- a/src/components/DirectoryListing.astro +++ b/src/components/DirectoryListing.astro @@ -15,9 +15,10 @@ const props = z.object({ descriptions: z.boolean().default(false), folder: z.string().optional(), maxDepth: z.number().default(1), + tag: z.string().optional(), }); -let { descriptions, folder, maxDepth } = props.parse(Astro.props); +let { descriptions, folder, maxDepth, tag } = props.parse(Astro.props); if (!folder) folder = Astro.params.slug!; @@ -34,7 +35,11 @@ function getChildren(parentPath: string, depth: number) { return allPages.filter((page) => { const pagePath = page.id; const pageDepth = pagePath.split("/").length; - return pageDepth === depth && pagePath.startsWith(parentPath); + return ( + pageDepth === depth && + pagePath.startsWith(parentPath) && + (tag ? page.data.tags?.includes(tag) : true) + ); }); } diff --git a/src/content/compatibility-flags/assets-navigation-prefers-asset-serving.md b/src/content/compatibility-flags/assets-navigation-prefers-asset-serving.md index ee022fe65a78ce2..19fc68ecbfa200a 100644 --- a/src/content/compatibility-flags/assets-navigation-prefers-asset-serving.md +++ b/src/content/compatibility-flags/assets-navigation-prefers-asset-serving.md @@ -11,7 +11,7 @@ enable_flag: "assets_navigation_prefers_asset_serving" disable_flag: "assets_navigation_has_no_effect" --- -For Workers with [static assets](/workers/static-assets/) and this compatibility flag enabled, navigation requests (requests which have a `Sec-Fetch-Mode: navigate` header) will prefer to be served by our asset-serving logic, even when an exact asset match cannot be found. This is particularly useful for applications which operate in either [Single Page Application (SPA) mode](/workers/static-assets/routing/#not_found_handling--404-page--single-page-application--none) or [404 page mode](/workers/static-assets/routing/#not_found_handling--404-page--single-page-application--none), as this now means the fallback pages of `200 /index.html` and `404 /404.html` will be served ahead of invoking a Worker script and will therefore avoid incurring a charge. +For Workers with [static assets](/workers/static-assets/) and this compatibility flag enabled, navigation requests (requests which have a `Sec-Fetch-Mode: navigate` header) will prefer to be served by our asset-serving logic, even when an exact asset match cannot be found. This is particularly useful for applications which operate in either [Single Page Application (SPA) mode](/workers/static-assets/routing/single-page-application/) or have [custom 404 pages](/workers/static-assets/routing/static-site-generation/#custom-404-pages), as this now means the fallback pages of `200 /index.html` and `404 /404.html` will be served ahead of invoking a Worker script and will therefore avoid incurring a charge. Without this flag, the runtime will continue to apply the old behavior of invoking a Worker script (if present) for any requests which do not exactly match a static asset. diff --git a/src/content/docs/pages/framework-guides/nextjs/ssr/supported-features.mdx b/src/content/docs/pages/framework-guides/nextjs/ssr/supported-features.mdx index f05d5f5becfe956..69273cd8afb0d4d 100644 --- a/src/content/docs/pages/framework-guides/nextjs/ssr/supported-features.mdx +++ b/src/content/docs/pages/framework-guides/nextjs/ssr/supported-features.mdx @@ -22,7 +22,7 @@ The [`@opennextjs/cloudflare` adapter](https://opennext.js.org/cloudflare), whic `@opennextjs/cloudflare` is pre 1.0, and still in active development. As it approaches 1.0, it will become the clearly better choice for most Next.js apps, since Next.js has been engineered to only support its Node.js "runtime" for many newly introduced features. -Refer to the [OpenNext docs](https://opennext.js.org/cloudflare) and the [Workers vs. Pages compatibility matrix](/workers/static-assets/migrations/migrate-from-pages/#compatibility-matrix) for more information to help you decide which to use. +Refer to the [OpenNext docs](https://opennext.js.org/cloudflare) and the [Workers vs. Pages compatibility matrix](/workers/static-assets/migration-guides/migrate-from-pages/#compatibility-matrix) for more information to help you decide which to use. #### Supported Node.js APIs when using `@cloudflare/next-on-pages` diff --git a/src/content/docs/style-guide/components/directory-listing.mdx b/src/content/docs/style-guide/components/directory-listing.mdx index 2b76b1527f96f90..13dcde39662f54e 100644 --- a/src/content/docs/style-guide/components/directory-listing.mdx +++ b/src/content/docs/style-guide/components/directory-listing.mdx @@ -53,6 +53,12 @@ When enabled, shows the [frontmatter `description`](/style-guide/frontmatter/) f Controls how many levels of nested pages to display. A value of `1` shows only direct children, while higher values will show deeper nesting levels. +### `tag` + +**type:** `string` + +Optionally, filter the listing to only pages with a specific tag. + ## Associated content types - [Navigation](/style-guide/documentation-content-strategy/content-types/navigation/) diff --git a/src/content/docs/workers/configuration/multipart-upload-metadata.mdx b/src/content/docs/workers/configuration/multipart-upload-metadata.mdx index a66222a58afe0aa..307bf3cb0b9c620 100644 --- a/src/content/docs/workers/configuration/multipart-upload-metadata.mdx +++ b/src/content/docs/workers/configuration/multipart-upload-metadata.mdx @@ -43,8 +43,8 @@ At a minimum, the `main_module` key is required to upload a Worker. * [Asset](/workers/static-assets/) configuration for a Worker. * `config` - * [html_handling](/workers/static-assets/routing/#1-html_handling) determines the redirects and rewrites of requests for HTML content. - * [not_found_handling](/workers/static-assets/routing/#2-not_found_handling) determines the response when a request does not match a static asset, and there is no Worker script. + * [html_handling](/workers/static-assets/routing/advanced/html-handling/) determines the redirects and rewrites of requests for HTML content. + * [not_found_handling](/workers/static-assets/routing/) determines the response when a request does not match a static asset. * `jwt` field provides a token authorizing assets to be attached to a Worker. * `keep_assets` diff --git a/src/content/docs/workers/frameworks/framework-guides/angular.mdx b/src/content/docs/workers/frameworks/framework-guides/angular.mdx index 14dca8d2fcb607c..27a1503ca9fdba3 100644 --- a/src/content/docs/workers/frameworks/framework-guides/angular.mdx +++ b/src/content/docs/workers/frameworks/framework-guides/angular.mdx @@ -1,7 +1,7 @@ --- pcx_content_type: how-to title: Angular -head: [] +tags: ["full-stack"] description: Create an Angular application and deploy it to Cloudflare Workers with Workers Assets. --- diff --git a/src/content/docs/workers/frameworks/framework-guides/astro.mdx b/src/content/docs/workers/frameworks/framework-guides/astro.mdx index e147f6b80ed00cf..05e67cb4c06a7b4 100644 --- a/src/content/docs/workers/frameworks/framework-guides/astro.mdx +++ b/src/content/docs/workers/frameworks/framework-guides/astro.mdx @@ -1,7 +1,7 @@ --- pcx_content_type: how-to title: Astro -head: [] +tags: ["ssg", "full-stack"] description: Create an Astro application and deploy it to Cloudflare Workers with Workers Assets. --- @@ -38,7 +38,7 @@ import { Astro emphasizes performance through minimal client-side JavaScript - by default, it renders as much content as possible at build time, or [on-demand](https://docs.astro.build/en/guides/on-demand-rendering/) on the "server" - this can be a Cloudflare Worker. [“Islands”](https://docs.astro.build/en/concepts/islands/) of JavaScript are added only where interactivity or personalization is needed. -Astro is also framework-agnostic, and supports every major UI framework, including React, Preact, Svelte, Vue, SolidJS , via its official [integrations](https://astro.build/integrations/). +Astro is also framework-agnostic, and supports every major UI framework, including React, Preact, Svelte, Vue, SolidJS, via its official [integrations](https://astro.build/integrations/). ## Deploy a new Astro project on Workers @@ -96,7 +96,7 @@ If your Astro project is entirely pre-rendered, follow these steps:
The key part of this config is the `assets` field, which tells Wrangler where to find your static assets. In this case, we're telling Wrangler to look in the `./dist` directory. If your assets are in a different directory, update the `directory` value accordingly. - Read about other [asset configuration options](/workers/static-assets/routing/). + Read about other [asset configuration options](/workers/wrangler/configuration/#assets). Also note how there's no `main` field in this config - this is because you're only serving static assets, so no Worker code is needed for on demand rendering/SSR.
@@ -161,7 +161,7 @@ If your Astro project uses [on demand rendering (also known as SSR)](https://doc - `main` points to the entry point of your Worker script. This is generated by the Astro adaptor, and is what powers your server-rendered pages. - `assets.directory` tells Wrangler where to find your static assets. In this case, we're telling Wrangler to look in the `./dist` directory. If your assets are in a different directory, update the `directory` value accordingly. - Read more about [Wrangler configuration options](/workers/wrangler/configuration/) and [asset configuration options](/workers/static-assets/routing/). + Read more about [Wrangler configuration options](/workers/wrangler/configuration/) and [asset configuration options](/workers/wrangler/configuration/#assets). 4. **Build and deploy your project** diff --git a/src/content/docs/workers/frameworks/framework-guides/docusaurus.mdx b/src/content/docs/workers/frameworks/framework-guides/docusaurus.mdx index 699c9679f41d4da..48b65909599c77e 100644 --- a/src/content/docs/workers/frameworks/framework-guides/docusaurus.mdx +++ b/src/content/docs/workers/frameworks/framework-guides/docusaurus.mdx @@ -1,7 +1,7 @@ --- pcx_content_type: how-to title: Docusaurus -head: [] +tags: ["ssg"] description: Create a Docusaurus application and deploy it to Cloudflare Workers with Workers Assets. --- diff --git a/src/content/docs/workers/frameworks/framework-guides/gatsby.mdx b/src/content/docs/workers/frameworks/framework-guides/gatsby.mdx index 37d1a6d19126282..88d357b7c79b47c 100644 --- a/src/content/docs/workers/frameworks/framework-guides/gatsby.mdx +++ b/src/content/docs/workers/frameworks/framework-guides/gatsby.mdx @@ -1,7 +1,7 @@ --- pcx_content_type: how-to title: Gatsby -head: [] +tags: ["ssg"] description: Create a Gatsby application and deploy it to Cloudflare Workers with Workers Assets. --- diff --git a/src/content/docs/workers/frameworks/framework-guides/nextjs.mdx b/src/content/docs/workers/frameworks/framework-guides/nextjs.mdx index 9deec69b7cc237c..96f3faa2500c731 100644 --- a/src/content/docs/workers/frameworks/framework-guides/nextjs.mdx +++ b/src/content/docs/workers/frameworks/framework-guides/nextjs.mdx @@ -1,7 +1,7 @@ --- pcx_content_type: how-to title: Next.js -head: [] +tags: ["full-stack"] description: Create an Next.js application and deploy it to Cloudflare Workers with Workers Assets. sidebar: badge: Beta diff --git a/src/content/docs/workers/frameworks/framework-guides/nuxt.mdx b/src/content/docs/workers/frameworks/framework-guides/nuxt.mdx index 8d3f2588b7475b2..e593967667cb5a8 100644 --- a/src/content/docs/workers/frameworks/framework-guides/nuxt.mdx +++ b/src/content/docs/workers/frameworks/framework-guides/nuxt.mdx @@ -1,7 +1,7 @@ --- pcx_content_type: how-to title: Nuxt -head: [] +tags: ["full-stack"] description: Create a Nuxt application and deploy it to Cloudflare Workers with Workers Assets. --- diff --git a/src/content/docs/workers/frameworks/framework-guides/qwik.mdx b/src/content/docs/workers/frameworks/framework-guides/qwik.mdx index a7fa96f3ba6bce3..8df297c3f41c9fc 100644 --- a/src/content/docs/workers/frameworks/framework-guides/qwik.mdx +++ b/src/content/docs/workers/frameworks/framework-guides/qwik.mdx @@ -1,7 +1,7 @@ --- pcx_content_type: how-to title: Qwik -head: [] +tags: ["full-stack"] description: Create a Qwik application and deploy it to Cloudflare Workers with Workers Assets. --- diff --git a/src/content/docs/workers/frameworks/framework-guides/react-router.mdx b/src/content/docs/workers/frameworks/framework-guides/react-router.mdx index ed54fb56d583425..025c84f75c381cc 100644 --- a/src/content/docs/workers/frameworks/framework-guides/react-router.mdx +++ b/src/content/docs/workers/frameworks/framework-guides/react-router.mdx @@ -1,6 +1,7 @@ --- pcx_content_type: how-to title: React Router (formerly Remix) +tags: ["full-stack"] description: Create a React Router application and deploy it to Cloudflare Workers --- diff --git a/src/content/docs/workers/frameworks/framework-guides/react.mdx b/src/content/docs/workers/frameworks/framework-guides/react.mdx index 0818f9da2d0e13f..75f4698e42fb5c8 100644 --- a/src/content/docs/workers/frameworks/framework-guides/react.mdx +++ b/src/content/docs/workers/frameworks/framework-guides/react.mdx @@ -1,7 +1,7 @@ --- pcx_content_type: how-to title: React -head: [] +tags: ["spa"] description: Create a React application and deploy it to Cloudflare Workers with Workers Assets. --- diff --git a/src/content/docs/workers/frameworks/framework-guides/solid.mdx b/src/content/docs/workers/frameworks/framework-guides/solid.mdx index 68250af12f19d74..1cc833a80f20d32 100644 --- a/src/content/docs/workers/frameworks/framework-guides/solid.mdx +++ b/src/content/docs/workers/frameworks/framework-guides/solid.mdx @@ -1,7 +1,7 @@ --- pcx_content_type: how-to title: Solid -head: [] +tags: ["full-stack"] description: Create a Solid application and deploy it to Cloudflare Workers with Workers Assets. sidebar: badge: Beta diff --git a/src/content/docs/workers/frameworks/framework-guides/svelte.mdx b/src/content/docs/workers/frameworks/framework-guides/svelte.mdx index 60d442b13ff1135..8f702510c1d589c 100644 --- a/src/content/docs/workers/frameworks/framework-guides/svelte.mdx +++ b/src/content/docs/workers/frameworks/framework-guides/svelte.mdx @@ -1,7 +1,7 @@ --- pcx_content_type: how-to title: Svelte -head: [] +tags: ["spa"] description: Create a Svelte application and deploy it to Cloudflare Workers with Workers Assets. --- diff --git a/src/content/docs/workers/frameworks/framework-guides/vue.mdx b/src/content/docs/workers/frameworks/framework-guides/vue.mdx index 30ff09bf17b1a3a..22502373709ef5c 100644 --- a/src/content/docs/workers/frameworks/framework-guides/vue.mdx +++ b/src/content/docs/workers/frameworks/framework-guides/vue.mdx @@ -1,7 +1,7 @@ --- pcx_content_type: how-to title: Vue -head: [] +tags: ["spa"] description: Create a Vue application and deploy it to Cloudflare Workers with Workers Assets. --- diff --git a/src/content/docs/workers/static-assets/binding.mdx b/src/content/docs/workers/static-assets/binding.mdx index adbabd3e91e0ede..f37472854e5cda1 100644 --- a/src/content/docs/workers/static-assets/binding.mdx +++ b/src/content/docs/workers/static-assets/binding.mdx @@ -61,7 +61,7 @@ Now Wrangler will not upload these files as client-side assets when deploying th ## `run_worker_first` -Controls whether to invoke the Worker script regardless of a request which would have otherwise matched an asset. `run_worker_first = false` ([default](/workers/static-assets/routing/#default-behavior)) will serve any static asset matching a request, while `run_worker_first = true` will unconditionally [invoke your Worker script](/workers/static-assets/routing/#invoking-worker-script-ahead-of-assets). +Controls whether to invoke the Worker script regardless of a request which would have otherwise matched an asset. `run_worker_first = false` (default) will serve any static asset matching a request, while `run_worker_first = true` will unconditionally [invoke your Worker script](/workers/static-assets/routing/worker-script/#run-your-worker-script-first). @@ -115,7 +115,7 @@ In the example above, assets would be available through `env.ASSETS`. Your dynamic code can make new, or forward incoming requests to your project's static assets using the assets binding. For example, `env.ASSETS.fetch(request)`, `env.ASSETS.fetch(new URL('https://assets.local/my-file'))` or `env.ASSETS.fetch('https://assets.local/my-file')`. -Take the following example that configures a Worker script to return a response under all requests headed for `/api/`. Otherwise, the Worker script will pass the incoming request through to the asset binding. In this case, because a Worker script is only invoked when the requested route has not matched any static assets, this will always evaluate [`not_found_handling`](/workers/static-assets/routing/#routing-configuration) behavior. +Take the following example that configures a Worker script to return a response under all requests headed for `/api/`. Otherwise, the Worker script will pass the incoming request through to the asset binding. In this case, because a Worker script is only invoked when the requested route has not matched any static assets, this will always evaluate [`not_found_handling`](/workers/static-assets/routing/) behavior. @@ -166,7 +166,7 @@ For the various static asset routing configuration options, refer to [Routing](/ ### Smart Placement with Worker Code First -If you desire to run your [Worker code ahead of assets](/workers/static-assets/routing/#invoking-worker-script-ahead-of-assets) by setting `run_worker_first=true`, all requests must first travel to your Smart-Placed Worker. As a result, you may experience increased latency for asset requests. +If you desire to run your [Worker code ahead of assets](/workers/static-assets/routing/worker-script/#run-your-worker-script-first) by setting `run_worker_first=true`, all requests must first travel to your Smart-Placed Worker. As a result, you may experience increased latency for asset requests. Use Smart Placement with `run_worker_first=true` when you need to integrate with other backend services, authenticate requests before serving any assets, or if your want to make modifications to your assets before serving them. @@ -178,4 +178,4 @@ Enabling Smart Placement with `run_worker_first=false` (or not specifying it) le Use Smart Placement with `run_worker_first=false` (or not specifying it) when prioritizing fast asset delivery. -This will not impact the [default routing behavior](/workers/static-assets/routing/#default-behavior). +This will not impact the [default routing behavior](/workers/static-assets/routing/). diff --git a/src/content/docs/workers/static-assets/direct-upload.mdx b/src/content/docs/workers/static-assets/direct-upload.mdx index 1c1410cc1a025cf..53d6a4fd9527c3e 100644 --- a/src/content/docs/workers/static-assets/direct-upload.mdx +++ b/src/content/docs/workers/static-assets/direct-upload.mdx @@ -15,6 +15,7 @@ import { Render, TabItem, Tabs, + TypeScriptExample, } from "~/components"; import { Icon } from "astro-icon/components"; @@ -176,7 +177,7 @@ If this is a Worker which already has assets, and you wish to just re-use the ex } ``` -Asset [routing configuration](/workers/static-assets/routing/#routing-configuration) can be provided in the `assets` object, such as `html_handling` and `not_found_handling`. +Asset [routing configuration](/workers/wrangler/configuration/#assets) can be provided in the `assets` object, such as `html_handling` and `not_found_handling`. ```bash title="Example Worker Metadata Specifying Asset Configuration" { @@ -213,7 +214,7 @@ Optionally, an assets binding can be provided if you wish to fetch and serve ass ## Programmatic Example - + ```ts import * as fs from "fs"; @@ -427,4 +428,4 @@ if (buckets.length > 0) { await scriptUpload(completionToken); ``` - + diff --git a/src/content/docs/workers/static-assets/headers.mdx b/src/content/docs/workers/static-assets/headers.mdx index a918a2531850295..217c22e8d4c239f 100644 --- a/src/content/docs/workers/static-assets/headers.mdx +++ b/src/content/docs/workers/static-assets/headers.mdx @@ -23,6 +23,12 @@ When serving static assets, Workers will attach some headers to the response by This header complements the default `Cache-Control` header. Its value is a hash of the static asset file, and browsers can use this in subsequent requests with an `If-None-Match` header to check for freshness, without needing to re-download the entire file in the case of a match. +- **`CF-Cache-Status`** + + This header indicates whether the asset was served from the cache (`HIT`) or not (`MISS`).[^1] + Cloudflare reserves the right to attach new headers to static asset responses at any time in order to improve performance or harden the security of your Worker application. + +[^1]: Due to a technical limitation that we hope to address in the future, the `CF-Cache-Status` header is not always entirely accurate. It is possible for false-positives and false-negatives to occur. This should be rare. In the meantime, this header should be considered as returning a "probablistic" result. diff --git a/src/content/docs/workers/static-assets/index.mdx b/src/content/docs/workers/static-assets/index.mdx index 05ba57d1f8a5d86..d575c32233d67b1 100644 --- a/src/content/docs/workers/static-assets/index.mdx +++ b/src/content/docs/workers/static-assets/index.mdx @@ -85,7 +85,7 @@ export default { By default, if a requested URL matches a file in the static assets directory, that file will always be served — without running Worker code. If no matching asset is found and a Worker is configured, the request will be processed by the Worker instead. -- If no Worker is set up, the [`not_found_handling`](/workers/static-assets/routing/#2-not_found_handling-1) setting in your Wrangler configuration determines what happens next. By default, a `404 Not Found` response is returned. +- If no Worker is set up, the [`not_found_handling`](/workers/static-assets/routing/) setting in your Wrangler configuration determines what happens next. By default, a `404 Not Found` response is returned. - If a Worker is configured and a request does not match a static asset, the Worker will handle the request. The Worker can choose to pass the request to the asset binding (through `env.ASSETS.fetch()`), following the `not_found_handling` rules. @@ -117,7 +117,7 @@ If you want the Worker code to execute before serving an asset (for example, to diff --git a/src/content/docs/workers/static-assets/migrations/index.mdx b/src/content/docs/workers/static-assets/migration-guides/index.mdx similarity index 69% rename from src/content/docs/workers/static-assets/migrations/index.mdx rename to src/content/docs/workers/static-assets/migration-guides/index.mdx index 7611bd3863b5357..b878e4f8f79b823 100644 --- a/src/content/docs/workers/static-assets/migrations/index.mdx +++ b/src/content/docs/workers/static-assets/migration-guides/index.mdx @@ -1,16 +1,15 @@ --- pcx_content_type: navigation -title: Migrations +title: Migration Guides sidebar: order: 11 + group: + hideIndex: true head: [] description: Learn how to migrate your applications to Cloudflare Workers. --- -import { - Description, - DirectoryListing, -} from "~/components"; +import { Description, DirectoryListing } from "~/components"; Migrate your existing applications to Cloudflare Workers. @@ -18,4 +17,4 @@ import { Take advantage of Cloudflare's global network and migrate your existing applications to Workers. - + diff --git a/src/content/docs/workers/static-assets/migrations/migrate-from-pages.mdx b/src/content/docs/workers/static-assets/migration-guides/migrate-from-pages.mdx similarity index 98% rename from src/content/docs/workers/static-assets/migrations/migrate-from-pages.mdx rename to src/content/docs/workers/static-assets/migration-guides/migrate-from-pages.mdx index d9a63d17073d99d..ad7829adb40090f 100644 --- a/src/content/docs/workers/static-assets/migrations/migrate-from-pages.mdx +++ b/src/content/docs/workers/static-assets/migration-guides/migrate-from-pages.mdx @@ -1,6 +1,6 @@ --- pcx_content_type: concept -title: Migrate from Pages +title: Migrate from Pages to Workers sidebar: order: 7 head: [] @@ -193,7 +193,7 @@ Once the Worker script has been compiled, you can update your configuration file If you authored [a `_routes.json` file](/pages/functions/routing/#create-a-_routesjson-file) in your Pages project, or used [middleware](/pages/functions/middleware/) in Pages Functions, you must pay close attention to the configuration of your Worker script. Pages would default to serving your Pages Functions ahead of static assets and `_routes.json` and Pages Functions middleware allowed you to customize this behavior. -Workers, on the other hand, will default to serving static assets ahead of your Worker script, unless you have configured [`assets.run_worker_first`](/workers/static-assets/routing/#invoking-worker-script-ahead-of-assets). This option is required if you are, for example, performing any authentication checks or logging requests before serving static assets. +Workers, on the other hand, will default to serving static assets ahead of your Worker script, unless you have configured [`assets.run_worker_first`](/workers/static-assets/routing/worker-script/#run-your-worker-script-first). This option is required if you are, for example, performing any authentication checks or logging requests before serving static assets. @@ -400,7 +400,7 @@ This compatibility matrix compares the features of Workers and Pages. Unless oth | [Middleware](/workers/static-assets/binding/#run_worker_first) | ✅ [^1] | ✅ | | [Redirects](/workers/static-assets/redirects/) | ✅ | ✅ | | [Smart Placement](/workers/configuration/smart-placement/) | ✅ | ✅ | -| [Serve assets on a path](/workers/static-assets/routing/) | ✅ | ❌ | +| [Serve assets on a path](/workers/static-assets/routing/advanced/serving-a-subdirectory/) | ✅ | ❌ | | **Observability** | | | | [Workers Logs](/workers/observability/) | ✅ | ❌ | | [Logpush](/workers/observability/logs/logpush/) | ✅ | ❌ | diff --git a/src/content/docs/workers/static-assets/migrations/vercel-to-workers.mdx b/src/content/docs/workers/static-assets/migration-guides/vercel-to-workers.mdx similarity index 94% rename from src/content/docs/workers/static-assets/migrations/vercel-to-workers.mdx rename to src/content/docs/workers/static-assets/migration-guides/vercel-to-workers.mdx index fed3e771707b297..dcd9c827c4489cb 100644 --- a/src/content/docs/workers/static-assets/migrations/vercel-to-workers.mdx +++ b/src/content/docs/workers/static-assets/migration-guides/vercel-to-workers.mdx @@ -9,7 +9,7 @@ import { WranglerConfig } from "~/components"; In this tutorial, you will learn how to migrate your Vercel application to Cloudflare Workers. -You should already have an existing project deployed on Vercel that you would like to host on Cloudflare Workers. Vercel specific features are not supported by Cloudflare Workers. Review the [Workers compatibility matrix](/workers/static-assets/migrations/migrate-from-pages/#compatibility-matrix) for more information on what is supported. +You should already have an existing project deployed on Vercel that you would like to host on Cloudflare Workers. Vercel specific features are not supported by Cloudflare Workers. Review the [Workers compatibility matrix](/workers/static-assets/migration-guides/migrate-from-pages/#compatibility-matrix) for more information on what is supported. ## Frameworks @@ -82,4 +82,4 @@ Once your custom domain is set up and sending requests to Cloudflare Workers, yo ## Troubleshooting -For additional migration instructions, review the [Cloudflare Pages to Workers migration guide](/workers/static-assets/migrations/migrate-from-pages/). While not Vercel specific, it does cover some additional steps that may be helpful. +For additional migration instructions, review the [Cloudflare Pages to Workers migration guide](/workers/static-assets/migration-guides/migrate-from-pages/). While not Vercel specific, it does cover some additional steps that may be helpful. diff --git a/src/content/docs/workers/static-assets/routing.mdx b/src/content/docs/workers/static-assets/routing.mdx deleted file mode 100644 index dbba1b2e06a0c97..000000000000000 --- a/src/content/docs/workers/static-assets/routing.mdx +++ /dev/null @@ -1,324 +0,0 @@ ---- -pcx_content_type: concept -title: Routing -sidebar: - order: 3 -head: [] -description: How Workers assets' routing and its configuration works. ---- - -import { - Badge, - Description, - FileTree, - InlineBadge, - Render, - TabItem, - Tabs, - WranglerConfig, -} from "~/components"; - -## Default behavior - -By default, assets are served by attempting to match up the incoming request's pathname to a static asset. The structure and organization of files in your static asset directory, along with any routing configuration, determine the routing paths for your application. When a request invokes a Worker with assets: - -1. If a request is found with a matching path to the current route requested then that asset will always be served. - -In this example, request to `example.com/blog` serves the `blog.html` file. - -![A request to `example.com/blog` serves the `/blog.html` file. ](~/assets/images/workers/platform/assets/workers-assets-serve-asset.png) - -2. If there is no Worker script, [`not_found_handling`](/workers/static-assets/routing/#2-not_found_handling) will be evaluated. By default, a null-body 404-status response will be served. - -If a Worker is configured, and there are no assets that match the current route requested, the Worker will be invoked. The Worker can then "fall back" to `not_found_handling` asset behavior, by passing the incoming request through to the [asset binding](/workers/static-assets/binding/#runtime-api-reference). - -In this example, a request to `example.com/api` doesn't match a static asset so the Worker is invoked. - -![A request to `example.com/blog` runs the Worker.](~/assets/images/workers/platform/assets/workers-assets-invoke-worker.png) - -## Invoking Worker Script Ahead of Assets - -You may wish to run code before assets are served. This is often the case when implementing authentication, logging, personalization, internationalization, or other similar functions. [`run_worker_first`](/workers/static-assets/binding/#run_worker_first) is a configuration option available in [Wrangler configuration file](/workers/wrangler/configuration/) which controls this behavior. When enabled, `run_worker_first = true` will invoke your Worker's code, regardless of any assets that would have otherwise matched. - -Take the following directory structure, [Wrangler configuration file](/workers/wrangler/configuration/), and user Worker code: - - - -- wrangler.json -- package.json -- public - - supersecret.txt -- src - - index.ts - - - - - -```toml title="wrangler.toml" -name = "my-worker" -compatibility_date = "2024-09-19" -main = "src/index.ts" -assets = { directory = "./public/", binding = "ASSETS", run_worker_first = true } -``` - - - -```js -export default { - async fetch( - request: Request, - env: Env, - ctx: ExecutionContext - ): Promise { - const url = new URL(request.url); - if (url.pathname === "/supersecret.txt") { - const auth = request.headers.get("Authorization"); - if (!auth) { - return new Response("Forbidden", { - status: 403, - statusText: "Forbidden", - headers: { - "Content-Type": "text/plain", - }, - }); - } - } - - return await env.ASSETS.fetch(request); - }, -}; -``` - -In this example, any request will be routed to our user Worker, due to `run_worker_first` being enabled. As a result, any request being made `/supersecret.txt` without an `Authorization` header will result in a 403. - -## Routing configuration - -There are two options for asset serving that can be configured in the [Wrangler configuration file](/workers/wrangler/configuration/#assets): - -#### 1. `html_handling` - -Forcing or dropping trailing slashes on request paths (for example, `example.com/page/` vs. `example.com/page`) is often something that developers wish to control for cosmetic reasons. Additionally, it can impact SEO because search engines often treat URLs with and without trailing slashes as different, separate pages. This distinction can lead to duplicate content issues, indexing problems, and overall confusion about the correct canonical version of a page. - -`html_handling` configuration determines the redirects and rewrites of requests for HTML content. It is used to specify the pattern for canonical URLs, thus where Cloudflare serves HTML content from, and additionally, where Cloudflare redirects non-canonical URLs to. - -#### 2. `not_found_handling` - -In the event a request does not match a static asset, and there is no Worker script (or that Worker script calls `fetch()` on [the assets binding](/workers/static-assets/binding/)), `not_found_handling` determines how Cloudflare will construct a response. - -It can be used to serve single-page applications (SPAs), or to serve custom 404 HTML pages. - -If creating a SPA, place an `/index.html` in your asset directory. When `not_found_handling` is configured to `"single-page-application"`, this page will be served with a 200 response. - -If you have custom 404 HTML pages, and configure `not_found_handling` to `"404-page"`, Cloudflare will recursively navigate up by pathname segment to serve the nearest `404.html` file. For example, you can have a `/404.html` and `/blog/404.html` file, and Cloudflare will serve the `/blog/404.html` file for requests to `/blog/not-found` and the `/404.html` file for requests to `/foo/bar`. - -### Default configuration - -#### 1. `html_handling` - -`"auto-trailing-slash"` is the default mode if `html_handling` is not explicitly specified. - -Take the following directory structure: - - - -- file.html -- folder - - index.html - - - -Based on the incoming requests, the following assets would be served: - -| Incoming Request | Response | Asset Served | -| ------------------ | --------------- | ------------------ | -| /file | 200 | /file.html served | -| /file.html | 307 to /file | - | -| /file/ | 307 to /file | - | -| /file/index | 307 to /file | - | -| /file/index.html | 307 to /file | - | -| /folder | 307 to /folder/ | - | -| /folder.html | 307 to /folder/ | - | -| /folder/ | 200 | /folder/index.html | -| /folder/index | 307 to /folder/ | - | -| /folder/index.html | 307 to /folder/ | - | - -#### 2. `not_found_handling` - -`"none"` is the default mode if `not_found_handling` is not explicitly specified. - -For all non-matching requests, Cloudflare will return a null-body 404-status response. - -``` -/not-found -> 404 -/foo/path/doesnt/exist -> 404 -``` - -### Alternate configuration options - -Alternate configuration options are outlined on this page and can be specified in your project's [Wrangler configuration file](/workers/wrangler/configuration/#assets). If you're deploying using a [framework](/workers/frameworks/), these options will be defined by the framework provider. - -Example Wrangler configuration file: - - - -```toml title="wrangler.toml" -assets = { directory = "./public", binding = "ASSETS", html_handling = "force-trailing-slash", not_found_handling = "404-page" } -``` - - - -#### `html_handling = "auto-trailing-slash" | "force-trailing-slash" | "drop-trailing-slash" | "none"` - -Take the following directory structure: - - - -- file.html -- folder - - index.html - - - -**`html_handling: "auto-trailing-slash"`** - -Based on the incoming requests, the following assets would be served: - -| Incoming Request | Response | Asset Served | -| ------------------ | --------------- | ------------------ | -| /file | 200 | /file.html | -| /file.html | 307 to /file | - | -| /file/ | 307 to /file | - | -| /file/index | 307 to /file | - | -| /file/index.html | 307 to /file | - | -| /folder | 307 to /folder/ | - | -| /folder.html | 307 to /folder | - | -| /folder/ | 200 | /folder/index.html | -| /folder/index | 307 to /folder | - | -| /folder/index.html | 307 to /folder | - | - -**`html_handling: "force-trailing-slash"`** - -Based on the incoming requests, the following assets would be served: - -| Incoming Request | Response | Asset Served | -| ------------------ | --------------- | ------------------ | -| /file | 307 to /file/ | - | -| /file.html | 307 to /file/ | - | -| /file/ | 200 | /file.html | -| /file/index | 307 to /file/ | - | -| /file/index.html | 307 to /file/ | - | -| /folder | 307 to /folder/ | - | -| /folder.html | 307 to /folder/ | - | -| /folder/ | 200 | /folder/index.html | -| /folder/index | 307 to /folder/ | - | -| /folder/index.html | 307 to /folder/ | - | - -**`html_handling: "drop-trailing-slash"`** - -Based on the incoming requests, the following assets would be served: - -| Incoming Request | Response | Asset Served | -| ------------------ | -------------- | ------------------ | -| /file | 200 | /file.html | -| /file.html | 307 to /file | - | -| /file/ | 307 to /file | - | -| /file/index | 307 to /file | - | -| /file/index.html | 307 to /file | - | -| /folder | 200 | /folder/index.html | -| /folder.html | 307 to /folder | - | -| /folder/ | 307 to /folder | - | -| /folder/index | 307 to /folder | - | -| /folder/index.html | 307 to /folder | - | - -**`html_handling: "none"`** - -Based on the incoming requests, the following assets would be served: - -| Incoming Request | Response | Asset Served | -| ------------------ | ------------------------------- | ------------------------------- | -| /file | Depends on `not_found_handling` | Depends on `not_found_handling` | -| /file.html | 200 | /file.html | -| /file/ | Depends on `not_found_handling` | Depends on `not_found_handling` | -| /file/index | Depends on `not_found_handling` | Depends on `not_found_handling` | -| /file/index.html | Depends on `not_found_handling` | Depends on `not_found_handling` | -| /folder | Depends on `not_found_handling` | Depends on `not_found_handling` | -| /folder.html | Depends on `not_found_handling` | Depends on `not_found_handling` | -| /folder/ | Depends on `not_found_handling` | Depends on `not_found_handling` | -| /folder/index | Depends on `not_found_handling` | Depends on `not_found_handling` | -| /folder/index.html | 200 | /folder/index.html | - -#### `not_found_handling = "404-page" | "single-page-application" | "none"` - -Take the following directory structure: - - - -- 404.html -- index.html -- folder - - 404.html - - - -**`not_found_handling: "none"`** - -``` -/not-found -> 404 -/folder/doesnt/exist -> 404 -``` - -**`not_found_handling: "404-page"`** - -``` -/not-found -> 404 /404.html -/folder/doesnt/exist -> 404 /folder/404.html -``` - -**`not_found_handling: "single-page-application"`** - -``` -/not-found -> 200 /index.html -/folder/doesnt/exist -> 200 /index.html -``` - -## Serving assets from a custom path - -:::note -This feature requires Wrangler v3.98.0 or later. -::: - -Like with any other Worker, [you can configure a Worker with assets to run on a path of your domain](/workers/configuration/routing/routes/). -Assets defined for a Worker must be nested in a directory structure that mirrors the desired path. - -For example, to serve assets from `example.com/blog/*`, create a `blog` directory in your asset directory. - -{/* prettier-ignore */} - -- dist - - blog - - index.html - - posts - - post1.html - - post2.html - - -With a [Wrangler configuration file](/workers/wrangler/configuration/) like so: - - -```toml -name = "assets-on-a-path-example" -main = "src/index.js" -route = "example.com/blog/*" - -[assets] -directory = "dist" - -``` - - -In this example, requests to `example.com/blog/` will serve the `index.html` file, and requests to `example.com/blog/posts/post1` will serve the `post1.html` file. - -If you have a file outside the configured path, it will not be served. For example, if you have a `home.html` file in the root of your asset directory, it will not be served when requesting `example.com/blog/home`. -However, if needed, these files can still be manually fetched over [the binding](/workers/static-assets/binding/#binding). -``` diff --git a/src/content/docs/workers/static-assets/routing/advanced/html-handling.mdx b/src/content/docs/workers/static-assets/routing/advanced/html-handling.mdx new file mode 100644 index 000000000000000..b058cd572d237eb --- /dev/null +++ b/src/content/docs/workers/static-assets/routing/advanced/html-handling.mdx @@ -0,0 +1,158 @@ +--- +pcx_content_type: concept +title: HTML handling +description: How to configure a HTML handling and trailing slashes for the static assets of your Worker. +--- + +import { FileTree, WranglerConfig } from "~/components"; + +Forcing or dropping trailing slashes on request paths (for example, `example.com/page/` vs. `example.com/page`) is often something that developers wish to control for cosmetic reasons. Additionally, it can impact SEO because search engines often treat URLs with and without trailing slashes as different, separate pages. This distinction can lead to duplicate content issues, indexing problems, and overall confusion about the correct canonical version of a page. + +The [`assets.html_handling` configuration](/workers/wrangler/configuration/#assets) determines the redirects and rewrites of requests for HTML content. It is used to specify the pattern for canonical URLs, thus where Cloudflare serves HTML content from, and additionally, where Cloudflare redirects non-canonical URLs to. + +Take the following directory structure: + + + +- dist + - file.html + - folder + - index.html + + + +## Automatic trailing slashes (default) + +This will usually give you the desired behavior automatically: individual files (e.g. `foo.html`) will be served _without_ a trailing flash and folder index files (e.g. `foo/index.html`) will be served _with_ a trailing slash. + + + +```json +{ + "name": "my-worker", + "compatibility_date": "$today", + "assets": { + "directory": "./dist/", + "html_handling": "auto-trailing-slash" + } +} +``` + + + +Based on the incoming requests, the following assets would be served: + +| Incoming Request | Response | Asset Served | +| ------------------ | --------------- | ----------------------- | +| /file | 200 | /dist/file.html | +| /file.html | 307 to /file | - | +| /file/ | 307 to /file | - | +| /file/index | 307 to /file | - | +| /file/index.html | 307 to /file | - | +| /folder | 307 to /folder/ | - | +| /folder.html | 307 to /folder | - | +| /folder/ | 200 | /dist/folder/index.html | +| /folder/index | 307 to /folder | - | +| /folder/index.html | 307 to /folder | - | + +## Force trailing slashes + +Alternatively, you can force trailing slashes (`force-trailing-slash`). + + + +```json +{ + "name": "my-worker", + "compatibility_date": "$today", + "assets": { + "directory": "./dist/", + "html_handling": "force-trailing-slash" + } +} +``` + + + +Based on the incoming requests, the following assets would be served: + +| Incoming Request | Response | Asset Served | +| ------------------ | --------------- | ----------------------- | +| /file | 307 to /file/ | - | +| /file.html | 307 to /file/ | - | +| /file/ | 200 | /dist/file.html | +| /file/index | 307 to /file/ | - | +| /file/index.html | 307 to /file/ | - | +| /folder | 307 to /folder/ | - | +| /folder.html | 307 to /folder/ | - | +| /folder/ | 200 | /dist/folder/index.html | +| /folder/index | 307 to /folder/ | - | +| /folder/index.html | 307 to /folder/ | - | + +## Drop trailing slashes + +Or you can drop trailing slashes (`drop-trailing-slash`). + + + +```json +{ + "name": "my-worker", + "compatibility_date": "$today", + "assets": { + "directory": "./dist/", + "html_handling": "drop-trailing-slash" + } +} +``` + + + +Based on the incoming requests, the following assets would be served: + +| Incoming Request | Response | Asset Served | +| ------------------ | -------------- | ----------------------- | +| /file | 200 | /dist/file.html | +| /file.html | 307 to /file | - | +| /file/ | 307 to /file | - | +| /file/index | 307 to /file | - | +| /file/index.html | 307 to /file | - | +| /folder | 200 | /dist/folder/index.html | +| /folder.html | 307 to /folder | - | +| /folder/ | 307 to /folder | - | +| /folder/index | 307 to /folder | - | +| /folder/index.html | 307 to /folder | - | + +## Disable HTML handling + +Alternatively, if you have bespoke needs, you can disable the built-in HTML handling entirely (`none`). + + + +```json +{ + "name": "my-worker", + "compatibility_date": "$today", + "assets": { + "directory": "./dist/", + "html_handling": "none" + } +} +``` + + + +Based on the incoming requests, the following assets would be served: + +| Incoming Request | Response | Asset Served | +| ------------------ | ------------------------------- | ------------------------------- | +| /file | Depends on `not_found_handling` | Depends on `not_found_handling` | +| /file.html | 200 | /dist/file.html | +| /file/ | Depends on `not_found_handling` | Depends on `not_found_handling` | +| /file/index | Depends on `not_found_handling` | Depends on `not_found_handling` | +| /file/index.html | Depends on `not_found_handling` | Depends on `not_found_handling` | +| /folder | Depends on `not_found_handling` | Depends on `not_found_handling` | +| /folder.html | Depends on `not_found_handling` | Depends on `not_found_handling` | +| /folder/ | Depends on `not_found_handling` | Depends on `not_found_handling` | +| /folder/index | Depends on `not_found_handling` | Depends on `not_found_handling` | +| /folder/index.html | 200 | /dist/folder/index.html | diff --git a/src/content/docs/workers/static-assets/routing/advanced/index.mdx b/src/content/docs/workers/static-assets/routing/advanced/index.mdx new file mode 100644 index 000000000000000..92e2d7ad7cbb823 --- /dev/null +++ b/src/content/docs/workers/static-assets/routing/advanced/index.mdx @@ -0,0 +1,14 @@ +--- +pcx_content_type: navigation +title: Advanced +sidebar: + order: 5 + group: + hideIndex: true +--- + +import { Badge, DirectoryListing } from "~/components"; + +Learn how to configure advanced routing options for the static assets of your Worker. + + diff --git a/src/content/docs/workers/static-assets/routing/advanced/serving-a-subdirectory.mdx b/src/content/docs/workers/static-assets/routing/advanced/serving-a-subdirectory.mdx new file mode 100644 index 000000000000000..35da3e1edbf7a43 --- /dev/null +++ b/src/content/docs/workers/static-assets/routing/advanced/serving-a-subdirectory.mdx @@ -0,0 +1,46 @@ +--- +pcx_content_type: concept +title: Serving a subdirectory +description: How to configure a Worker with static assets on a subpath. +--- + +import { FileTree, WranglerConfig } from "~/components"; + +:::note +This feature requires Wrangler v3.98.0 or later. +::: + +Like with any other Worker, [you can configure a Worker with assets to run on a path of your domain](/workers/configuration/routing/routes/). +Assets defined for a Worker must be nested in a directory structure that mirrors the desired path. + +For example, to serve assets from `example.com/blog/*`, create a `blog` directory in your asset directory. + + + +- dist + - blog + - index.html + - posts + - post1.html + - post2.html + + + +With a [Wrangler configuration file](/workers/wrangler/configuration/) like so: + + + +```toml +name = "assets-on-a-path-example" +main = "src/index.js" +route = "example.com/blog/*" + +[assets] +directory = "dist" +``` + + + +In this example, requests to `example.com/blog/` will serve the `index.html` file, and requests to `example.com/blog/posts/post1` will serve the `post1.html` file. + +If you have a file outside the configured path, it will not be served, unless it is part of the `assets.not_found_handling` for [Single Page Applications](/workers/static-assets/routing/single-page-application/) or [custom 404 pages](/workers/static-assets/routing/static-site-generation/). For example, if you have a `home.html` file in the root of your asset directory, it will not be served when requesting `example.com/blog/home`. However, if needed, these files can still be manually fetched over [the binding](/workers/static-assets/binding/#binding). diff --git a/src/content/docs/workers/static-assets/routing/full-stack-application.mdx b/src/content/docs/workers/static-assets/routing/full-stack-application.mdx new file mode 100644 index 000000000000000..ccdef894161c3e9 --- /dev/null +++ b/src/content/docs/workers/static-assets/routing/full-stack-application.mdx @@ -0,0 +1,18 @@ +--- +pcx_content_type: concept +title: Full-stack application +description: How to configure and use a full-stack application with Workers. +sidebar: + order: 1 +--- + +import { WranglerConfig, Render, DirectoryListing } from "~/components"; + +Full-stack applications are web applications which are span both the client and server. The build process of these applications will produce a HTML files, accompanying client-side resources (e.g. JavaScript bundles, CSS stylesheets, images, fonts, etc.) and a Worker script. Data is typically fetched the Worker script at request-time and the initial page response is usually server-side rendered (SSR). From there, the client is then hydrated and a SPA-like experience ensues. + +The following full-stack frameworks are natively supported by Workers: + + diff --git a/src/content/docs/workers/static-assets/routing/index.mdx b/src/content/docs/workers/static-assets/routing/index.mdx new file mode 100644 index 000000000000000..35a3c9de909471e --- /dev/null +++ b/src/content/docs/workers/static-assets/routing/index.mdx @@ -0,0 +1,14 @@ +--- +pcx_content_type: navigation +title: Routing +sidebar: + order: 3 + group: + hideIndex: true +--- + +import { Badge, DirectoryListing } from "~/components"; + +Learn how to configure different archtectures for the static assets of your Worker. + + diff --git a/src/content/docs/workers/static-assets/routing/single-page-application.mdx b/src/content/docs/workers/static-assets/routing/single-page-application.mdx new file mode 100644 index 000000000000000..f609df5588c2c58 --- /dev/null +++ b/src/content/docs/workers/static-assets/routing/single-page-application.mdx @@ -0,0 +1,40 @@ +--- +pcx_content_type: concept +title: Single Page Application (SPA) +description: How to configure and use a Single Page Application (SPA) with Workers. +sidebar: + order: 2 +--- + +import { WranglerConfig, Aside, TypeScriptExample, Render } from "~/components"; + +Single Page Applications (SPAs) are web applications which are client-side rendered (CSR). They are often built with a framework such as [React](/workers/frameworks/framework-guides/react/), [Vue](/workers/frameworks/framework-guides/vue/) or [Svelte](/workers/frameworks/framework-guides/svelte/). The build process of these frameworks will produce a single `/index.html` file and accompanying client-side resources (e.g. JavaScript bundles, CSS stylesheets, images, fonts, etc.). Typically, data is fetched by the client from an API with client-side requests. + +## Configuration + +In order to deploy a Single Page Application to Workers, you must configure the `assets.directory` and `assets.not_found_handling` options in your [Wrangler configuration file](/workers/wrangler/configuration/#assets): + + + +```json +{ + "name": "my-worker", + "compatibility_date": "$today", + "assets": { + "directory": "./dist/", + "not_found_handling": "single-page-application" + } +} +``` + + + +Configuring `assets.not_found_handling` to `single-page-application` overrides the default serving behavior of Workers for static assets. When an incoming request does not match a file in the `assets.directory`, Workers will serve the contents of the `/index.html` file with a `200 OK` status. + + + +## Local Development + +If you are using a Vite-powered SPA framework, you might be interested in using our [Vite plugin](/workers/vite-plugin/) which offers a Vite-native developer experience. + + \ No newline at end of file diff --git a/src/content/docs/workers/static-assets/routing/static-site-generation.mdx b/src/content/docs/workers/static-assets/routing/static-site-generation.mdx new file mode 100644 index 000000000000000..2ba31e2cdfe2577 --- /dev/null +++ b/src/content/docs/workers/static-assets/routing/static-site-generation.mdx @@ -0,0 +1,50 @@ +--- +pcx_content_type: concept +title: Static Site Generation (SSG) and custom 404 pages +description: How to configure a Static Site Generation (SSG) application and custom 404 pages with Workers. +sidebar: + order: 3 +--- + +import { WranglerConfig, Render } from "~/components"; + +Static Site Generation (SSG) applications are web applications which are predominantely built or "prerendered" ahead-of-time. They are often built with a framework such as [Gatsby](/workers/frameworks/framework-guides/gatsby/) or [Docusaurus](/workers/frameworks/framework-guides/docusaurus/). The build process of these frameworks will produce a many HTML files and accompanying client-side resources (e.g. JavaScript bundles, CSS stylesheets, images, fonts, etc.). Data is either static, fetched and compiled into the HTML at build-time, or fetched by the client from an API with client-side requests. + +Often, an SSG framework will allow you to create a custom 404 page. + +## Configuration + +In order to deploy a Static Site Generation application to Workers, you must configure the `assets.directory`, and optionally, the `assets.not_found_handling` and `assets.html_handling` options in your [Wrangler configuration file](/workers/wrangler/configuration/#assets): + + + +```json +{ + "name": "my-worker", + "compatibility_date": "$today", + "assets": { + "directory": "./dist/", + "not_found_handling": "404-page", + "html_handling": "auto-trailing-slash" + } +} +``` + + + +`assets.html_handling` defaults to `auto-trailing-slash` and this will usually give you the desired behavior automatically: individual files (e.g. `foo.html`) will be served _without_ a trailing flash and folder index files (e.g. `foo/index.html`) will be served _with_ a trailing slash. Alternatively, you can force trailing slashes (`force-trailing-slash`) or drop trailing slashes (`drop-trailing-slash`) on requests for HTML pages. + +### Custom 404 pages + +Configuring `assets.not_found_handling` to `404-page` overrides the default serving behavior of Workers for static assets. When an incoming request does not match a file in the `assets.directory`, Workers will serve the contents of the nearest `404.html` file with a `404 Not Found` status. + + + +## Local Development + +If you are using a Vite-powered SPA framework, you might be interested in using our [Vite plugin](/workers/vite-plugin/) which offers a Vite-native developer experience. + + diff --git a/src/content/docs/workers/static-assets/routing/worker-script.mdx b/src/content/docs/workers/static-assets/routing/worker-script.mdx new file mode 100644 index 000000000000000..1a75d7eb37620d5 --- /dev/null +++ b/src/content/docs/workers/static-assets/routing/worker-script.mdx @@ -0,0 +1,78 @@ +--- +pcx_content_type: concept +title: Worker script +description: How the presence of a Worker script influences static asset routing and the related configuration options. +sidebar: + order: 4 +--- + +import { WranglerConfig, TypeScriptExample, Aside } from "~/components"; + +If you have both static assets and a Worker script configured, Cloudflare will first attempt to serve static assets if one matches the incoming request. You can read more about how we match assets in the [HTML handling docs](/workers/static-assets/routing/advanced/html-handling/). + +If an appropriate static asset if not found, Cloudflare will invoke your Worker script. + +This allows you to easily combine together these two features to create powerful applications (e.g. a [full-stack application](/workers/static-assets/routing/full-stack-application/), or a [Single Page Application (SPA)](/workers/static-assets/routing/single-page-application/) or [Static Site Generation (SSG) application](/workers/static-assets/routing/static-site-generation/) with an API). + +## Run your Worker script first + +If you need to always run your Worker script before serving static assets, (for example, you wish to log requests, perform some authentication checks, use [HTMLRewriter](/workers/runtime-apis/html-rewriter/), or otherwise transform assets before serving), you can configure the [`assets.run_worker_first` setting](/workers/static-assets/binding/#run_worker_first). This will retain any other settings governing asset-serving behavior (e.g. `assets.not_found_handling`) but gives you more control over exactly how and when those assets are served. This could be considered a platform-level "middleware" feature. + + + +Once the Worker has been invoked, to then defer to static-asset serving, you can use an Assets binding: + + + +```json +{ + "name": "my-worker", + "compatibility_date": "$today", + "main": "./worker/index.ts", + "assets": { + "directory": "./dist/", + "binding": "ASSETS", + "run_worker_first": true + } +} +``` + + + + + +```ts +import { WorkerEntrypoint } from "cloudflare:workers"; + +export default class extends WorkerEntrypoint { + async fetch(request: Request) { + // You can perform checks before fetching assets + const user = await checkIfRequestIsAuthenticated(request); + + if (!user) { + return new Response("Unauthorized", { status: 401 }); + } + + // You can then just fetch the assets as normal, or you could pass in a custom Request object here if you wanted to fetch some other specific asset + const assetResponse = await this.env.ASSETS.fetch(request); + + // You can return static asset response as-is, or you can transform them with something like HTMLRewriter + return new HTMLRewriter() + .on("#user", { + element(element) { + element.setInnerContent(JSON.stringify({ name: user.name })); + }, + }) + .transform(assetResponse); + } +} +``` + + diff --git a/src/content/docs/workers/vite-plugin/reference/static-assets.mdx b/src/content/docs/workers/vite-plugin/reference/static-assets.mdx index be611c5e121200b..7e18d28a4dad4bf 100644 --- a/src/content/docs/workers/vite-plugin/reference/static-assets.mdx +++ b/src/content/docs/workers/vite-plugin/reference/static-assets.mdx @@ -21,7 +21,7 @@ On running `vite build`, an output `wrangler.json` configuration file is generat The `assets.directory` field in this file is automatically populated with the path to your `client` build output. It is therefore not necessary to provide the `assets.directory` field in your input Worker configuration. -The `assets` configuration should be used, however, if you wish to set [routing configuration](/workers/static-assets/routing/#routing-configuration) or enable the [assets binding](/workers/static-assets/binding/#binding). +The `assets` configuration should be used, however, if you wish to set [routing configuration](/workers/static-assets/routing/) or enable the [assets binding](/workers/static-assets/binding/#binding). The following example configures the `not_found_handling` for a single-page application so that the fallback will always be the root `index.html` file. diff --git a/src/content/docs/workers/vite-plugin/tutorial.mdx b/src/content/docs/workers/vite-plugin/tutorial.mdx index 9c51a4e2493c6b1..d7273f60b3d4b62 100644 --- a/src/content/docs/workers/vite-plugin/tutorial.mdx +++ b/src/content/docs/workers/vite-plugin/tutorial.mdx @@ -68,10 +68,10 @@ assets = { not_found_handling = "single-page-application" } -The [`not_found_handling`](/workers/static-assets/routing/#not_found_handling--404-page--single-page-application--none) value has been set to `single-page-application`. +The [`not_found_handling`](/workers/static-assets/routing/single-page-application/) value has been set to `single-page-application`. This means that all not found requests will serve the `index.html` file. With the Cloudflare plugin, the `assets` routing configuration is used in place of Vite's default behavior. -This ensures that your application's [routing configuration](/workers/static-assets/routing/#routing-configuration) works the same way while developing as it does when deployed to production. +This ensures that your application's [routing configuration](/workers/static-assets/routing/) works the same way while developing as it does when deployed to production. Note that the [`directory`](/workers/static-assets/binding/#directory) field is not used when configuring assets with Vite. The `directory` in the output configuration will automatically point to the client build output. diff --git a/src/content/docs/workers/wrangler/configuration.mdx b/src/content/docs/workers/wrangler/configuration.mdx index c302f3e6712fe7d..e71f4d6702eb4e3 100644 --- a/src/content/docs/workers/wrangler/configuration.mdx +++ b/src/content/docs/workers/wrangler/configuration.mdx @@ -204,6 +204,7 @@ At a minimum, the `name`, `main` and `compatibility_date` keys are required to d - Configures automatic observability settings for telemetry data emitted from your Worker. Refer to [Observability](#observability). * `assets` + - Configures static assets that will be served. Refer to [Assets](/workers/static-assets/binding/) for more details. * `migrations` @@ -1028,15 +1029,15 @@ The following options are available under the `assets` key. - `run_worker_first` - - Controls whether static assets are fetched directly, or a Worker script is invoked. Learn more about fetching assets when using [`run_worker_first`](/workers/static-assets/routing/#invoking-worker-script-ahead-of-assets). + - Controls whether static assets are fetched directly, or a Worker script is invoked. Learn more about fetching assets when using [`run_worker_first`](/workers/static-assets/routing/worker-script/#run-your-worker-script-first). - `html_handling`: - - Determines the redirects and rewrites of requests for HTML content. Learn more about the various options in [assets routing](/workers/static-assets/routing/#html_handling). + - Determines the redirects and rewrites of requests for HTML content. Learn more about the various options in [assets routing](/workers/static-assets/routing/advanced/html-handling/). - `not_found_handling`: - - Determines the handling of requests that do not map to an asset. Learn more about the various options in [assets routing](/workers/static-assets/routing/#not_found_handling). + - Determines the handling of requests that do not map to an asset. Learn more about the various options in [assets routing](/workers/static-assets/routing/). Example: diff --git a/src/content/partials/workers/custom_headers.mdx b/src/content/partials/workers/custom_headers.mdx index c3dac110d6f1305..ff960f6ef8c9c9d 100644 --- a/src/content/partials/workers/custom_headers.mdx +++ b/src/content/partials/workers/custom_headers.mdx @@ -8,7 +8,7 @@ import { Markdown, Render } from "~/components"; ## Custom headers -The default response headers served on static asset responses can be overridden, or added to, by creating a plain text file called `_headers` without a file extension, in the static asset directory of your project. This file will not itself be served as a static asset, but will instead be parsed by {props.product === 'workers' ? 'Workers' : 'Cloudflare Pages'} and its rules will be applied to static asset responses. +The default response headers served on static asset responses can be overridden, removed, or added to, by creating a plain text file called `_headers` without a file extension, in the static asset directory of your project. This file will not itself be served as a static asset, but will instead be parsed by {props.product === 'workers' ? 'Workers' : 'Cloudflare Pages'} and its rules will be applied to static asset responses. {props.filename} file can go directly into your {props.product === 'workers' ? static assets directory : build output directory}. +If you are using a framework, you will often have a directory named `public/` or `static/`, and this usually contains deploy-ready assets, such as favicons, `robots.txt` files, and site manifests. These files get copied over to a final output directory during the build, so this is the perfect place to author your {props.filename} file. If you are not using a framework, the {props.filename} file can go directly into your {props.product === 'workers' ? static assets directory : build output directory}. diff --git a/src/content/partials/workers/navigation_requests.mdx b/src/content/partials/workers/navigation_requests.mdx new file mode 100644 index 000000000000000..4f68c52e90fde58 --- /dev/null +++ b/src/content/partials/workers/navigation_requests.mdx @@ -0,0 +1,77 @@ +--- +{} +--- + +import { Aside, TypeScriptExample } from "~/components"; + +### Navigation requests + +If you have a Worker script (`main`), have configured `assets.not_found_handling`, and use the [`assets_navigation_prefers_asset_serving` compatibility flag](/workers/configuration/compatibility-flags/#navigation-requests-prefer-asset-serving) (or set a compatibility date of `2025-04-01` or greater), _navigation requests_ will not invoke the Worker script. A _navigation request_ is a request made with the `Sec-Fetch-Mode: navigate` header, which browsers automatically attach when navigating to a page. This reduces billable invocations of your Worker script, and is particularly useful for client-heavy applications which would otherwise invoke your Worker script very frequently and unnecessarily. + + + + + +#### Client-side callbacks + +In some cases, you might need to pass a value from a navigation request to your Worker script. For example, if you are acting as an OAuth callback, you might expect to see requests made to some route such as `/oauth/callback?code=...`. With the `assets_navigation_prefers_asset_serving` flag, your HTML assets will be server, rather than your Worker script. In this case, we recommend, either as part of your client application for this appropriate route, or with a slimmed-down endpoint-specific HTML file, passing the value to the server with client-side JavaScript. + +```html title="./dist/oauth/callback.html" + + + + OAuth callback + + +

Loading...

+ + + +``` + + + +```ts +import { WorkerEntrypoint } from "cloudflare:workers"; + +export default class extends WorkerEntrypoint { + async fetch(request: Request) { + const url = new URL(request.url); + if (url.pathname === "/api/oauth/callback") { + const code = url.searchParams.get("code"); + + const sessionId = await exchangeAuthorizationCodeForAccessAndRefreshTokensAndPersistToDatabaseAndGetSessionId(code); + + if (sessionId) { + return new Response(null, { + headers: { + "Set-Cookie": `sessionId=${sessionId}; HttpOnly; SameSite=Strict; Secure; Path=/; Max-Age=86400`, + }, + }); + } else { + return Response.json( + { error: "Invalid OAuth code. Please try again." }, + { status: 400 } + ); + } + } + + return new Response(null, { status: 404 }); + } +} +``` + + \ No newline at end of file diff --git a/src/content/partials/workers/static_asset_routing_reference.mdx b/src/content/partials/workers/static_asset_routing_reference.mdx new file mode 100644 index 000000000000000..928656bbd367fad --- /dev/null +++ b/src/content/partials/workers/static_asset_routing_reference.mdx @@ -0,0 +1,64 @@ +--- +params: + - not_found_handling +--- + +### Reference + +In most cases, configuring `assets.not_found_handling` to {props.not_found_handling} will provide the desired behavior. If you are building your own framework, or have specialized needs, the following diagram can provide insight into exactly how the routing decisions are made. + +
+Full routing decision diagram +
+{`flowchart
+	Request@{ shape: stadium, label: "Incoming request" }
+	Request-->RunWorkerFirst
+	RunWorkerFirst@{ shape: diamond, label: "Run Worker script first?" }
+	RunWorkerFirst-->|No|RequestMatchesAsset
+	RunWorkerFirst-->|Yes|WorkerScriptInvoked
+	RequestMatchesAsset@{ shape: diamond, label: "Request matches asset?" }
+	RequestMatchesAsset-->|Yes|AssetServing
+	RequestMatchesAsset-->|No|WorkerScriptPresent
+	WorkerScriptPresent@{ shape: diamond, label: "Worker script present?" }
+	WorkerScriptPresent-->|No|AssetServing
+	WorkerScriptPresent-->|Yes|RequestNavigation
+	RequestNavigation@{ shape: diamond, label: "Request is navigation request?" }
+	RequestNavigation-->|No|WorkerScriptInvoked
+	WorkerScriptInvoked@{ shape: rect, label: "Worker script invoked" }
+	WorkerScriptInvoked-.->|Asset binding|AssetServing
+	RequestNavigation-->|Yes|AssetServing
+
+	subgraph Asset serving
+		AssetServing@{ shape: diamond, label: "Request matches asset?" }
+		AssetServing-->|Yes|AssetServed
+		AssetServed@{ shape: stadium, label: "**200 OK**
asset served" } + AssetServing-->|No|NotFoundHandling + + ${props.not_found_handling === "single-page-application" ? `subgraph single-page-application + NotFoundHandling@{ shape: rect, label: "Request rewritten to /index.html" } + NotFoundHandling-->SPAExists + SPAExists@{ shape: diamond, label: "HTML Page exists?" } + SPAExists-->|Yes|SPAServed + SPAExists-->|No|Generic404PageServed + Generic404PageServed@{ shape: stadium, label: "**404 Not Found**
null-body response served" } + SPAServed@{ shape: stadium, label: "**200 OK**
/index.html page served" } + end` : `subgraph 404-page + NotFoundHandling@{ shape: rect, label: "Request rewritten to ../404.html" } + NotFoundHandling-->404PageExists + 404PageExists@{ shape: diamond, label: "HTML Page exists?" } + 404PageExists-->|Yes|404PageServed + 404PageExists-->|No|404PageAtIndex + 404PageAtIndex@{ shape: diamond, label: "Request is for root /404.html?" } + 404PageAtIndex-->|Yes|Generic404PageServed + 404PageAtIndex-->|No|NotFoundHandling + Generic404PageServed@{ shape: stadium, label: "**404 Not Found**
null-body response served" } + 404PageServed@{ shape: stadium, label: "**404 Not Found**
404.html page served" } + end`} + + end`} +
+
+ +Requests are only billable if a Worker script is invoked. From there, it is possible to serve assets using the assets binding (depicted as the dotted line in the diagram above). + +{props.not_found_handling === "single-page-application" ? "Although unlikely to impact how a SPA is served, you" : "You"} can read more about how we match assets in the [HTML handling docs](/workers/static-assets/routing/advanced/html-handling/). diff --git a/src/content/partials/workers/workers-assets-routing-summary.mdx b/src/content/partials/workers/workers-assets-routing-summary.mdx index 5707edc5c7395a4..d30823f56410a70 100644 --- a/src/content/partials/workers/workers-assets-routing-summary.mdx +++ b/src/content/partials/workers/workers-assets-routing-summary.mdx @@ -2,6 +2,6 @@ {} --- -By default, Cloudflare first tries to match a request path against a static asset path, which is based on the file structure of the uploaded asset directory. This is either the directory specified by `assets.directory` in your Wrangler config or, in the case of the [Cloudflare Vite plugin](/workers/vite-plugin/), the output directory of the client build. Failing that, we invoke a Worker if one is present. If there is no Worker, or the Worker then uses the asset binding, Cloudflare will fallback to the behaviour set by [`not_found_handling`](/workers/static-assets/routing/#not_found_handling). +By default, Cloudflare first tries to match a request path against a static asset path, which is based on the file structure of the uploaded asset directory. This is either the directory specified by `assets.directory` in your Wrangler config or, in the case of the [Cloudflare Vite plugin](/workers/vite-plugin/), the output directory of the client build. Failing that, we invoke a Worker if one is present. If there is no Worker, or the Worker then uses the asset binding, Cloudflare will fallback to the behaviour set by [`not_found_handling`](/workers/static-assets/routing/). -Refer to the [routing documentation](/workers/static-assets/routing/#routing-configuration) for more information about how routing works with static assets, and how to customize this behavior. +Refer to the [routing documentation](/workers/static-assets/routing/) for more information about how routing works with static assets, and how to customize this behavior.