kwhitley / itty-router

A little router.
MIT License
1.8k stars 78 forks source link

DOCS: serve json/jpeg and static files via itty-router/cloudflare workers #183

Closed ghost closed 1 year ago

ghost commented 1 year ago

Describe the Issue

I am new to itty-router and cloudflare workers, I started using itty-router and it's awesome. I can see there is a jpeg/png response methods on itty-router but I can't see any examples on how the data would be loaded and sent as a response. Should I use a base64 encoded image? load the image from somewhere else Cloudflare KV and then stream it back? what about serving css or other static file contents via the worker? I am mostly looking to serve small auxilliary data (meta jpg image, logo and css file)

kwhitley commented 1 year ago

Hey there! Welcome to the club!

A) I should more docs around these use cases - you're absolutely right! Now for a bit more in-depth:

So all these response helpers do is set the MIME type (content-type) header, to save you the boilerplate of this each time:

new Response(JSON.stringify(data), { 
  headers: {
    'content-type': 'application/json'
  }
})

This means that whatever you pass to the helper will go straight to response.body (optionally passed through a transformer, like in the case of json(), which passes a transformer of JSON.stringify so you don't have to do that step yourself.

With this in mind, you could create a css() helper very similarly like this:

import { createResponse } from 'itty-router'

export const css = createResponse('text/css')

// css('body { color: red; }') will emit a Response as type `text/css`
ghost commented 1 year ago

Thank you for the quick reply! The css one is pretty straightforward indeed! The main challenge I had was how to render a jpeg/png image since this can't be easily loaded/encoded in JavaScript files? I was thinking base64 encoding it and returning it but not sure what the supposed way to use it is. Thanks again for the css example I will try this out

kwhitley commented 1 year ago

A quick note on those... what's your specific use-case? If you're trying to serve a website/MPA/SPA, I highly, highly recommend you just use Cloudflare Pages, with the appropriate build integration (they support many). For instance, I use SvelteKit for mine... because of this, I leave 100% of the asset management to SvelteKit/Pages, and let the API focus purely on remote stuff like resources out of KV.

If that's what you're already doing - great! If not, I'd start there and save yourself a ton of time/effort :)

ghost commented 1 year ago

I am building a simple web app - full-stack and web2.0 style. Everything is served through the backend, rendered with mustache templating. So 99% of my response is going to be either html or json which is the api part. The only thing I need to serve via jpg is literraly the logo of my website and one meta image for socials. So just 2 images. I thought of using cloudflare images for that but I don't feel like i need to pay US$5/month extra just to serve one jpeg. Using standard cloudflare workers right now with itty-router serving html/json and simple crude web app

kwhitley commented 1 year ago

Now to the jpeg/png bits...

For itty.sh, I store raw images in KV as arrayBuffer (an option when talking to KV) and serve that back to the client with the matching mime-type as the original content (whatever that was, jpg, or png). This means you should be able to pass an arrayBuffer (of a jpeg source) to jpeg() and have it work.

https://github.com/kwhitley/itty-router/assets/865416/38b729d8-926f-4431-86f5-16f99f32915c

ghost commented 1 year ago

that's very helpful thank you! so arraybuffer it is. I will try create an example and see if i can share it later on this thread

kwhitley commented 1 year ago

I love the minimalist approach! Definitely let me know how it turns out - we can always add it as an example for other folks! :)

kwhitley commented 1 year ago

As a random aside, have you heard of Astro? That might be something to consider as well... it's an opinionated MPA framework, that basically just lets you write HTML/Markdown and spits out raw HTML files (minimal or zero JS). Hooking up to Cloudflare Pages (free) is a couple second affair (just point to your repo, pick Astro from the dropdown, and you're done).

For simple site launching these days, I've been consistently blown away with using Pages. I can usually buy a domain (if through CF), spawn a repo for it, and have it live on that domain in maybe... 10 minutes tops? Certainly faster if I did it more often, haha.

ghost commented 1 year ago

Solved storing image as base64 and then converting it to ArrayBuffer as follows

function base64ToArrayBuffer(base64) {
  var binaryString = atob(base64);
  var bytes = new Uint8Array(binaryString.length);
  for (var i = 0; i < binaryString.length; i++) {
      bytes[i] = binaryString.charCodeAt(i);
  }
  return bytes.buffer;
}

router.get('/img/logo.png', async (request) => {
  const buf = base64ToArrayBuffer(`<base64 logo image>`);
  return png(buf);
});
kwhitley commented 1 year ago

Nice! Where you storing them?

ghost commented 1 year ago

just in js file export default '<base64>'; then import image from 'image.js'