Bundle up an entire directory, and distribute it across Cloudflare's range of products, including embedded in the Worker, KV, and R2!
This uploads the necessary files & outputs a functional Cloudflare Worker that handles routing to the uploaded assets. You can use use Hono, the web framework/router, or Vanilla, handling the fetch event ourselves with no extra packages.
- If you don't have assets over KV/Cloudflare Page's limit of 25 MB, you probably are better off just using Cloudflare Pages, or Worker Sites.
- If you do have assets over KV's limit, or want to exclusively use R2, then this allows you to upload a static directory anywhere.
- If you want to spread your assets out by size / directory / extension across KV and R2, even multiple buckets/namespaces, without having to manage it yourself.
- This also lets you (optionally) embed assets inside of the worker itself, base64 encoded. The ultimate unnecessary speed boost.
- Lastly, this optionally supports a "Manifest", keeping track of all old uploads, and removing unused files. We use this for avoiding uploading the same file twice, and also to keep assets around for a few versions (MaxManifestCount, default 3), in case your worker deployment goes wrong/worker propagation is slow and your old scripts are still around.
- Download the executable (or build it), and run it once. It will generate a bundleconfig.json for you to configure.
- Set up the storages / etc you want to use. You can have multiple of the same storage if you want different settings. See the configurations below, or the full configuration example below.
- Run the script with bundle (i.e ./CloudflareSuperSites bundle), and it will output a (hopefully) usable worker. Deploy the worker via Wrangler (wrangler publish)! If you want to set up CI/CD (not that I would recommend it, this may upload junk/a broken script): check here!
- You can use the clean up command (./CLoudflareSuperSites cleanup) with a manifest storage provider configured to clean up old files & manifests.
Upload.mp4
| Name | Use | Environment Variable | Type |
|---|---|---|---|
| BundleDirectory | The Directory to bundle! Can be absolute or relative. Just be careful of JSON slash escaping | BUNDLE_DIRECTORY | string |
| OutputLocation | The Output location of the worker! Can be absolute or relative. Just be careful of JSON slash escaping. This includes the file name. | OUTPUT_LOCATION | string |
| Router | "Vanilla" or "Hono", outputs the worker using Hono, or completely vanilla Cloudflare Worker | ROUTER | string |
| Verbose | Verbose logging, or not. | VERBOSE | bool |
| DryRun | If true, does not upload anything to R2/KV/Any storage. | VERBOSE | bool |
| StorageConfigurations | Your Storage Configurations! See specific Configurations below! | list of StorageConfiguration | |
| MaxManifestCount | The max amount of manifests before we prune old ones and remove their assets! (Only if you run the cleanup command though!) | MAX_MANIFEST_COUNT | int |
| Etags | Should we return ETags on each request, and handle returning 304 not modified if-not-match? | USE_ETAGS | bool |
| ManifestStorageConfiguration | The Storage to use for our Manifests! R2 is recommended. | StorageConfiguration |
| Name | Use | Type |
|---|---|---|
| Type | The Type used to identify the storage! "Embedded", "R2", or "KV | string |
| AllowedFileExtensions | File Extensions that are allowed in this configuration | List of strings |
| DisallowFileExtensions | File Extensions that are not allowed in this configuration | List of strings |
| IncludePaths | File paths that are allowed in this configuration | List of strings |
| ExcludePaths | File paths that are not allowed in this configuration | List of strings |
| FileSizeLimit | Max file size in bytes | long |
| CacheSeconds | Seconds to cache the item for. If Specified, it is cached in the CF Worker Cache API. Not supported for Embedded. | int |
Notes:
- These must all match for the asset to be included. For example, if you specify to include the file path /cookies/, and only HTML file extensions are allowed, it must match both
- Include Paths based on the case-insentive Start of the relative path. For example, if your website is example.com, and you have a path at example.com/cookies/, IncludePaths /cookies/ would match any assets under that path
- File Extensions are also case-insensitive
Embedded Storage Configuration - Assets that are base64 encoded and included in your worker js output
There are no unique embedded storage configuration options, just the base storage configuration options.
| Name | Use | Environment Variable | Type |
|---|---|---|---|
| ApiToken | Cloudflare API Token, needs KV Edit Permissions | CLOUDFLARE_API_TOKEN | string |
| ACCOUNTID | Cloudflare Account Id | ACCOUNTID | string |
| NamespaceId | KV Namespace Id | string | |
| BindingName | Name of the KV Binding (in your wrangler.toml, or use the generated one) | string |
| Name | Use | Environment Variable | Type |
|---|---|---|---|
| AccessKey | Cloudflare R2 S3 API Access Key | ACCESSKEY | string |
| SecretKey | Cloudflare R2 S3 Secret Key | SECRETKEY | string |
| ACCOUNTID | Cloudflare Account Id | ACCOUNTID | string |
| BucketName | R2 Bucket Name | string | |
| BindingName | Name of the KV Binding (in your wrangler.toml, or use the generated one) | string |
Why the S3 API Keys? We use Minio under the hood, there's no offical CF API for R2, and the unofficial one has an upload limit of ~100 MB (as does the entire API!). There are bits of code left for using the unofficial API, if you see them in the source.
Todo:
- Tests
- Maybe Tests with unstable_dev/the worker itself?
- Support for serving old assets (could force uploading all to a persistent data store, and re-creating routes based on the manifest)
- A Non-Full Worker mode, that outputs code that appends to your existing worker / otherwise lets you hook into it and use SuperSites alongside a normal worker (like you can use Cloudflare Worker Sites alongside a worker)
Full Configuration Example:
{ "BundleDirectory":"../public", # Relative or Exact Directory "OutputLocation":"worker/worker.js", # Relative or Exact File Path "Router":"Vanilla", # Vanilla or Hono "StorageConfigurations":[ # Repeat mutiple of the same type or exact same namespaceid/bucket name if you want. { "Type":"Embedded", "AllowedFileExtensions":[ "html", "css", "js" ], "FileSizeLimit":200000 }, { "Type":"KV", "FileSizeLimit":10000000, "ApiToken":"...", # Use Environment Variables if your environment supports it. KV needs KV Edit Permissions "AccountId":"...", "NamespaceId":"...", "BindingName":"KV", }, { "Type":"R2", "AccessKey":"...", # R2 S3 API Keys "SecretKey":"...", "AccountId":"...", "BucketName":"main-website", "BindingName":"R2", "CacheSeconds": 3600 } ], "MaxManifestCount":3, "ManifestStorageConfiguration":{ # Not Required, if you don't care about leaving files for old deploys behind/leaving unused files in storage "Type":"R2", "BucketName":"main-website-manifest", "AccessKey":"...", "SecretKey":"...", "AccountId":"...", "BindingName":"R2", } }Example Site using Super Sites: https://tylerobrien.dev