elysiajs / elysia

Ergonomic Framework for Humans
https://elysiajs.com
MIT License
10.25k stars 219 forks source link

Stylesheet route must be wrapped in explicit `new Response` #166

Closed ferntheplant closed 1 year ago

ferntheplant commented 1 year ago

I was following the code examples from Ethan Niser's BETH Stack and ran into an issue with loading my stylesheet. His example code looks something like:

const app = new Elysia()
  .use(html())
  .get("/", () => <SomeHtmlJsx />)
  .get("/styles.css", () => Bun.file("./styles.css"))

However in my browser I would see Welcome to Bun! To get started, return a Response object. for the source of my stylesheet. To fix it I did:

const rawCss = await Bun.file("./styles.css").text()
return new Response(rawCss)

While this works for now I'm not quite sure why returning the file doesn't just work. Even just returning the awaited .text() does not work and must be explicitly wrapped in a response. Is it because of the .use(html()) plugin?

fecony commented 1 year ago

Hey that's the issue after changes to html plugin, now it has autoDetect property and tries to return response as html, because of that you see that bun default message

Try to turn off autoDetect and see if it helps, but it will require you to wrap your html/jsx with html method https://elysiajs.com/plugins/html.html

I just had same thing with regular endpoint and saw bun message instead of simple string there 😄

ferntheplant commented 1 year ago

Ah yea that worked thanks. Still feels weird since the docs for isHtml say

Default implementation if length is greater than 7, starts with < and ends with >.

My CSS file definitely doesn't fit those criterion so the html plugin shouldn't have tried to kick in

bogeychan commented 1 year ago

Hi👋

There seems to be a bug in the Ahead of Time compliation. new Elysia({ aot: false }) solves this problem too.

bogeychan commented 1 year ago

With Ahead of Time compliation

composeHandler generates:

const {
  handler,
  handleError,
  hooks: {
    transform,
    beforeHandle,
    afterHandle,
    parse,
    error: handleErrors,
    onResponse
  },
  validator: { body, headers, params, query, response },
  utils: { mapResponse, mapCompactResponse, mapEarlyResponse, parseQuery },
  error: { NotFoundError, ValidationError, InternalServerError },
  meta,
  ERROR_CODE
} = hooks;

return async function (c) {
  Object.assign(c, await transform[0](c));
  let r = await handler(c);
-  let af0 = await afterHandle[0](c, r);
+  let af0 = mapEarlyResponse(await afterHandle[0](c, r), c.set);
  if (af0) return af0;
  return mapResponse(r, c.set);
};

which doesn't call mapEarlyResponse if result exists (result = BunFile -> should be Response<BunFile>)

Without Ahead of Time compliation

createDynamicHandler calls mapEarlyResponse after handle:

https://github.com/elysiajs/elysia/blob/741ffe7659cf049c8627d30b91cd1f05cfbab53e/src/dynamic-handle.ts#L254-L258

mapEarlyResponse takes care of mapping BunFile (Blob) to Response:

https://github.com/elysiajs/elysia/blob/741ffe7659cf049c8627d30b91cd1f05cfbab53e/src/handler.ts#L49-L50

To fix this..

mapEarlyResponse has to be called after handle in generated composeHandler (see diff above)