kravetsone / elysia-remix

Use Remix with Elysia with HMR support!
MIT License
31 stars 4 forks source link

`Fetch` performs badly #4

Open Gn3po4g opened 3 months ago

Gn3po4g commented 3 months ago

As the title says, fetch has poor performance when running remix with this elysia-remix compared to remix vite:dev.

in elysia-remix: image

in remix vite image

And my config:


//server.ts
import { Elysia } from 'elysia';
import { remix } from 'elysia-remix';

new Elysia().use(await remix()).listen(3000, console.log);

//vite.config.ts
import { vitePlugin as remix } from '@remix-run/dev';
import tailwind from 'tailwindcss';
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig({
  plugins: [
    remix({
      future: {
        unstable_singleFetch: true,
        v3_relativeSplatPath: true,
        v3_throwAbortReason: true,
      },
    }),
    tsconfigPaths(),
  ],
  css: {
    postcss: { plugins: [tailwind()] },
  },
});
Gn3po4g commented 3 months ago

Is it because of elysia-connect-middleware?

kravetsone commented 3 months ago

Is it because of elysia-connect-middleware?

Probably. I haven't dealt with possible optimizations yet. Does this only happen in dev mode?

kravetsone commented 3 months ago

Is it because of elysia-connect-middleware?

Probably. I haven't dealt with possible optimizations yet. Does this only happen in dev mode?

but such a big difference was unlikely to appear...

Gn3po4g commented 3 months ago

Is it because of elysia-connect-middleware?

Probably. I haven't dealt with possible optimizations yet. Does this only happen in dev mode?

In production mode it works normally: image

btw, if set prefix to '/' in staticPlugin , it will handle every request as a file request. so localhost:3000/ returns notfound.

i use like this:

new Elysia()
  .all('*', async context => {
    const url = new URL(context.request.url);

    const file = Bun.file(`build/client${url.pathname}`);

    return (await file.exists()) ? file : handler(context.request);
  })
  .listen(3000);
kravetsone commented 3 months ago

Is it because of elysia-connect-middleware?

Probably. I haven't dealt with possible optimizations yet. Does this only happen in dev mode?

In production mode it works normally: image

btw, if set prefix to '/' in staticPlugin , it will handle every request as a file request. so localhost:3000/ returns notfound.

i use like this:

new Elysia()
  .all('*', async context => {
    const url = new URL(context.request.url);

    const file = Bun.file(`build/client${url.pathname}`);

    return (await file.exists()) ? file : handler(context.request);
  })
  .listen(3000);

Can you share with me some code with a lot of requests?

Gn3po4g commented 3 months ago

ok, i will do some modification first.

-- edit @kravetsone you can try this. https://github.com/Gn3po4g/elysia-remix-demo

Gn3po4g commented 3 months ago

i change localhost fetch to https://jsonplaceholder.typicode.com, so ms may be higher

kravetsone commented 3 months ago

ok, i will do some modification first.

-- edit @kravetsone you can try this. https://github.com/Gn3po4g/elysia-remix-demo

Thanks! I'll see how I get some free time)

Gn3po4g commented 3 months ago

I add trace to calc handle time.

new Elysia()
  .trace(async ({ onHandle }) => {
    onHandle(({ begin, onStop }) => {
      onStop(({ end }) => {
        console.log('handle took', end - begin, 'ms');
      });
    });
  })
  .use(await remix())
  .listen(3000);

And it prints image So i think elysia-connect-middleware takes time

Gn3po4g commented 3 months ago
      const begin = Date.now()
      connectApp.handle(message, response, () => {
        console.log(Date.now()-begin)
        const webResponse = transformResponseToServerResponse(response);
        webResponse.headers.forEach((value, key) => {
          set.headers[key] = value;
        });
        set.status = webResponse.status;
        resolve(void 0);
      });

The value of the console output floats from 100 to 600

connectApp.handle seems to be slow

kravetsone commented 3 months ago
      const begin = Date.now()
      connectApp.handle(message, response, () => {
        console.log(Date.now()-begin)
        const webResponse = transformResponseToServerResponse(response);
        webResponse.headers.forEach((value, key) => {
          set.headers[key] = value;
        });
        set.status = webResponse.status;
        resolve(void 0);
      });

The value of the console output floats from 100 to 600

connectApp.handle seems to be slow

I was thinking the same thing. after all, express/connect are outdated and bad solutions. I can write my own middleware handler that will work better, faster and not pull a bad dependency.

Gn3po4g commented 3 months ago

you know what, if i use vite.middlewares directly, it performs well and response within in 30ms.

import { type ServerBuild, createRequestHandler } from '@remix-run/node';
import { Elysia } from 'elysia';
import { createRequest, createResponse } from 'node-mocks-http';
import { createServer } from 'vite';

function transformRequestToIncomingMessage(request, options) {
  const parsedURL = new URL(request.url, 'http://localhost');
  const query = {};
  for (const [key, value] of parsedURL.searchParams.entries()) {
    query[key] = value;
  }
  const message = createRequest({
    method: request.method.toUpperCase(),
    url: parsedURL.pathname,
    headers: request.headers.toJSON(),
    query,
    ...options,
  });
  return message;
}
function transformResponseToServerResponse(serverResponse) {
  return new Response(serverResponse._getData(), {
    status: serverResponse.statusCode,
    statusText: serverResponse.statusMessage,
    headers: serverResponse.getHeaders(),
  });
}

const vite = await createServer({ server: { middlewareMode: true } });
const build = await vite.ssrLoadModule('virtual:remix/server-build');

new Elysia()
  .onRequest(
    async ({ request, set }) =>
      await new Promise(resolve => {
        const message = transformRequestToIncomingMessage(request);
        const response = createResponse();
        const end = response.end.bind(response);
        response.end = (...args) => {
          end(...args);
          resolve(transformResponseToServerResponse(response));
        };
        vite.middlewares(message, response, resolve);
      }),
  )
  .all('*', async ({ request }) => {
    return createRequestHandler(build, 'development')(request);
  })
  .listen(3000);