-
Notifications
You must be signed in to change notification settings - Fork 284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Workers Sites support #54
Comments
I don't have a solution in mind for this, but it is a good question. I'm not super familiar with the asset manifest, or with Workers Sites, but will start tracking this request and see if there is something we will officially support. For now, the code in the Wrangler codebase (https://github.com/cloudflare/wrangler) may point you in the right direction as to reading/deconstructing the asset manifest for use in a Rust KvAssetHandler. |
You can access static files through the #[event(fetch)]
pub async fn main(req: worker::Request, env: worker::Env) -> worker::Result<worker::Response> {
let kv = worker::kv::KvStore::from_this(&env, "__STATIC_CONTENT")?;
let index = kv.get("index.html").text().await?.expect("index html");
worker::Response::from_html(index)
} There is still a lot missing, like caching, mime types etc, butyou can just follow the JS implementation of pub async fn serve_asset(req: Request, store: KvStore) -> worker::Result<Response> {
let path = req.path();
let path = path.trim_start_matches('/');
let value = match store.get(path).bytes().await? {
Some(value) => value,
None => return Response::error("Not Found", 404),
};
let mut response = Response::from_bytes(value)?;
response
.headers_mut()
.set("Content-Type", get_mime(path).unwrap_or("text/plain"))?;
Ok(response)
}
fn get_mime(path: &str) -> Option<&'static str> {
let ext = if let Some((_, ext)) = path.rsplit_once(".") {
ext
} else {
return None;
};
let ct = match ext {
"html" => "text/html",
"css" => "text/css",
"js" => "text/javascript",
"json" => "application/json",
"png" => "image/png",
"jpg" => "image/jpeg",
"jpeg" => "image/jpeg",
"ico" => "image/x-icon",
"wasm" => "application/wasm",
_ => return None,
};
return Some(ct);
} |
Thank you for the explanation here, @Dav1dde! One minor note, is that you should be able to use the let kv = worker::kv::KvStore::from_this(&env, "__STATIC_CONTENT")?; you can do: let kv = env.kv("__STATIC_CONENT")?; The caveat is that you're forced to use the |
Thanks, I was looking for something like The 0.5 version of the Improvements like:
|
@nilslice now I am actually trying to deploy this on cloudflare with wrangler, I am running into the issue that the files are hashed and I don't seem to have access to the manifest |
I have a solution now, but I wish it wasn't necessary: Have a post-processing script: cat <<EOF > build/worker/assets.mjs
import manifestJSON from '__STATIC_CONTENT_MANIFEST'
const assetManifest = JSON.parse(manifestJSON)
export function get_asset(name) {
return assetManifest[name];
}
EOF Then you can access it in Rust: #[wasm_bindgen(raw_module = "./assets.mjs")]
extern "C" {
fn get_asset(name: &str) -> Option<String>;
}
pub fn resolve(name: &str) -> Cow<'_, str> {
match get_asset(name) {
Some(name) => Cow::Owned(name),
None => Cow::Borrowed(name),
}
} |
Thanks to @Dav1dde , I also found a solution without using JavaScript directly. #[wasm_bindgen(module = "__STATIC_CONTENT_MANIFEST")]
extern "C" {
#[wasm_bindgen(js_name = "default")]
static MANIFEST: String;
}
pub fn resolve(name: &str) -> Cow<'_, str> {
match serde_json::from_str::<HashMap<&str, &str>>(&MANIFEST)
.ok()
.and_then(|m| m.get(name).map(|v| v.to_string()))
{
Some(val) => Cow::Owned(val),
None => Cow::Borrowed(name),
}
} |
This solution wouldn't work with the latest Fortunately, the |
@nilslice there seems to be a couple good solutions proposed above. Would you be open to accepting a PR for either @Dav1dde or @SeokminHong solution?
Perhaps I am missing something, but I came to the conclusion today that Cloudflare Pages is not at all compatible with Rust/WebAssembly. It seems to me that functions do not support WebAssembly and even if one were to try to use the legacy worker support via the I guess it would be possible to encode the entire module as base64 and inline it into a |
This is my complete solution based on the answers above // asset.rs
use once_cell::sync::Lazy;
use std::collections::HashMap;
use worker::*;
use worker::wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "__STATIC_CONTENT_MANIFEST")]
extern "C" {
#[wasm_bindgen(js_name = "default")]
static MANIFEST: String;
}
static MANIFEST_MAP: Lazy<HashMap<&str, &str>> = Lazy::new(|| {
serde_json::from_str::<HashMap<&str, &str>>(&MANIFEST)
.unwrap_or_default()
});
pub async fn serve(context: RouteContext<()>) -> worker::Result<Response> {
let assets = context.kv("__STATIC_CONTENT")?;
let asset = context.param("asset")
.map(String::as_str)
.unwrap_or("index.html");
/* if we are using miniflare (or wrangler with --local), MANIFEST_MAP is empty and we just
fetch the requested name of the asset from the KV store, otherwise, MANIFEST_MAP
provides the hashed name of the asset */
let path = MANIFEST_MAP.get(asset).unwrap_or(&asset);
match assets.get(path).bytes().await? {
Some(value) => {
let mut response = Response::from_bytes(value)?;
response.headers_mut()
.set("Content-Type", path.rsplit_once(".")
.map_or_else(|| "text/plain", |(_, ext)| match ext {
"html" => "text/html",
"css" => "text/css",
"js" => "text/javascript",
"json" => "application/json",
"png" => "image/png",
"jpg" => "image/jpeg",
"jpeg" => "image/jpeg",
"ico" => "image/x-icon",
"wasm" => "application/wasm",
_ => "text/plain",
})
)
.map(|_| response)
}
None => Response::error("Not Found", 404),
}
} For my router, I then can just write: // lib.rs
use worker::*;
mod utils;
mod asset;
#[event(fetch)]
pub async fn main(req: Request, env: Env, _: worker::Context) -> Result<Response> {
utils::set_panic_hook();
Router::new()
.get_async("/", |_, context| asset::serve(context)) // for index.html
.get_async("/:asset", |_, context| asset::serve(context))
.run(req, env).await
}
This issue wasn't relevant to me since I don't use worker-build or swc-bundler |
@SeokminHong not really the place to ask, but what pattern did you use for matching assets in sub-directories? I am finding that |
You may not need the leading "/" on "/images/some_image.png" - perhaps just "images/some_image.png". I haven't tried accessing assets in a cloudflare workers site from rust/wasm yet (was just browsing about to see if anyone else has done it already) but I have done it from JavaScript, where not including the leading slash in an asset path worked ok. |
In #308 I propose a function that allows to make the translation of asset names, |
I'm saddened to see Sites being deprecated. Just like @allsey87, I cannot see how Pages can replace Workers. |
@lemmih I'm trying to figure that out as well. I have a full stack Rust application that runs on workers but also has some static assets (logo, favicon, language files) and am being told by the Cloudflare Pages migration guide to merely "remove the Workers application and any associated wrangler.toml configuration files or build output" which is one of the most ridiculous things I've ever heard. Theoretically, it's possible to run WASM in a Pages function, but there is no documentation on how to do that or what is even possible, all the while being told "Do not use Workers Sites for new projects." |
With the introduction of Workers Assets, I'm going to close this. |
@kflansburg could you perhaps leave a link here to the change log, PR, or a summary of Worker Assets? |
https://developers.cloudflare.com/workers/static-assets/ Static Assets are perfect for my use case. Thanks! |
This is a new platform feature, there were no changes to workers-rs. Docs: https://developers.cloudflare.com/workers/static-assets/ |
@allsey87 They have an example on how to use it in conjunction with a full-stack leptos app: https://github.com/cloudflare/workers-rs/tree/main/templates/leptos |
@kflansburg In regards to this:
What about access to |
Ah, I haven't added that yet. It's only needed if you want access to static assets from your Worker, if you just want us to serve the assets without modification, that is done without invoking your Worker at all. I created #644 |
Hi 👋
I had tried to re-implement the Workers Sites using Rust, but I was stuck by KV access.
As far as I know, the kv-asset-handler package uses the
STATIC_CONTENT_MANIFEST
variable from global context generated by wrangler. Am I right?If it is, can you provide some ways to accessing the manifest or Rust version of
getAssetFromKV
function?The text was updated successfully, but these errors were encountered: