Integrating Workers Assets with Fullstack Apps
How to integrate Workers Assets, service bindings, and full-stack apps
The Cloudflare team1 recently released Workers Assets, a feature that allows you to serve static assets from Workers. More from the docs:
You can combine asset hosting with Cloudflare’s data and storage products such as Workers KV, Durable Objects, and R2 Storage to build full-stack applications that serve both front-end and back-end logic in a single Worker.
This is a great way to combine the power of Workers with the flexibility of a full-stack app. To use it, you just pass an assets
directive to your wrangler.json
file:
The src/index.js
file is just a traditional Workers application. You can use it to serve requests for specific paths, and depending on your Assets configuration, it will call the Workers app conditionally, based on the presence of an asset:
By doing this, you can serve your assets from the dist
directory, and your code from the src
directory. If an asset is found in the dist
directory, it will be served, otherwise, your code will execute.
Integrating with Fullstack Apps
I’ve been working over the past few weeks on a SaaS admin template built on Astro and D1, Cloudflare’s SQL database.
I've been hacking on this SaaS admin template built with @CloudflareDev D1, @astrodotbuild and @shadcn UI
— Kristian Freeman (@kristianf_) December 23, 2024
You'll be able to deploy a full SaaS admin template with real data in just a few minutes to @cloudflare
Full REST API included!
Quick sneak peek at it in this video pic.twitter.com/rET0cB1cmb
It uses the Cloudflare integration for Astro to compile the app into a bunch of JS bundles that get dynamically served by Workers. These integrations with full-stack frameworks work by essentially hijacking all requests to your app, and routing them to the appropriate bundle.
Out of the box, Workers Assets plays well with these frameworks, with just a bit of extra work. For Astro, you can update the main
directive in wrangler.json
to point to the index.js
file inside of Astro’s compiled _worker.js
bundle. dist
still remains the default directory for serving assets:
Integrating with Cloudflare primitives
This will work for serving assets correctly for full-stack frameworks like Astro. But by doing this, you’re losing the ability to integrate with any Cloudflare primitives that must be defined as additional classes. This includes things like Cloudflare Workflows, as well as traditional Service Bindings.2
In my saas-admin-template project, I have a Cloudflare Workflow (read my Workflows intro) that can be ran for any customer. Because it doesn’t get compiled into the Astro bundle, Wrangler3 doesn’t know how to find it in the source bundle. This means that the standard Workflow configuration, seen below, will fail:
Building a custom wrapper
How do we fix this? For now, we can build a custom wrapper that imports everything we need, both from the Astro bundle and the Cloudflare Workflow. This imports all the code from Astro, the Cloudflare Workflow, and then exports them appropriately. This is totally manual - and a hack - but it works for now. I think we’ll fix this, either at the platform or integration-level, in the future:
In build scripts, both for dev
and build
, we can copy the wrapper into the dist
directory, and make it the main entry point:
Note the difference between wrangler:dev
and dev
. wrangler:dev
will build the Astro bundle, and then run the Wrangler dev server. dev
will only build the Astro bundle and run it as a traditional Astro application.
The Cloudflare integration does have the idea of a “platform proxy”, which is supposed to natively run wrangler
as part of the Astro dev
process, but it does not currently support our wrapper integration, and thus any Workflows you may want to run as part of API requests won’t be available.
In our wrangler.json
, we can now import our custom wrapper:
With that, we can now use service bindings and Workflows in our Astro application, and have intelligent fallbacks to Workers Assets for the application’s static assets. Like I mentioned earlier, this is a hack, and I expect us to make this process in the future. But if you’re looking to build more complex applications using full-stack frameworks and Workers Assets, this is a viable way to do it right now!
Footnotes
-
Disclosure: I work at Cloudflare as a Senior Developer Advocate. ↩
-
Note that any bindings-based integrations, like KV or D1, do work without any addititional config. They get added to your request
env
, and you can access them inside of Astro endpoints (example docs). ↩