vitejs / vite

Next generation frontend tooling. It's fast!
http://vite.dev
MIT License
68.6k stars 6.19k forks source link

Dev server should send pre-compressed static files without `Content-Encoding: gzip` #12266

Open mz8i opened 1 year ago

mz8i commented 1 year ago

Description

I am serving some pre-compressed .csv.gzip files from the public directory.

The dev server automatically serves these with Content-Type: text/csv and Content-Encoding: gzip.

This seems somewhat overzealous, especially when the requested file explicitly has a .csv.gzip extension and the client code expects the content it receives to be compressed.

The problem is mostly that this doesn't seem to be configurable, which leads to inconsistencies when later deploying to sites without such a behaviour. Consider that GitHub Pages sends the same files as Content-Type: application/gzip which is definitely less unexpected.

For example, I ran into this issue because it turned out that my code was not decompressing the CSV files correctly, but I only realised this after deploying to a server because locally I didn't realise the browser was actually doing the decompression based on Content-Encoding. Now, I know that a lot of hosting services like GH Pages gzip content automatically and send it with Content-Encoding so that the compression is transparent to user code, but when the user specifically requests files that are hosted pre-compressed, the services usually don't interfere, and I think Vite dev server should act the same way.

I personally think this should not be the default behaviour, but at least should be possible to turn off.

Suggested solution

Change the default behaviour to not set Content-Encoding: gzip and Content-Type: [...] but rather send as Content-Type: application/gzip for files that are stored as already compressed.

Alternative

Expose a server configuration toggle to allow for turning the current behaviour off.

Additional context

No response

Validations

xiaohk commented 1 year ago

I was also tripped by this behavior. See this question on StackOverflow.

amw commented 10 months ago

Ran into the same issue. Our application uses JS fetch to get the file contents and expects them to be gzip data that is later extracted with Pako (JS gzip library). But since Vite added the header the browser already extracted the data.

aiktb commented 5 months ago

I have the same issue due to vite adding the following response header: (The left side is the abnormal case for vite, the right side is the normal case) image

This answer on Stackoverflow doesn't solve my problem because I can't change the filename. I found a VERY hacky way to fix it:

const gzipFixPlugin = () => {
  const fixHeader = (server) => {
    server.middlewares.use((req, res, next) => {
      if (req.originalUrl?.includes(".dat.gz")) {
        res.setHeader("Content-Type", "application/x-gzip");
        // `res.removeHeader("Content-Encoding")` does not work
        res.setHeader("Content-Encoding", "invalid-value");
      }
      next();
    });
  };

  return {
    name: "gzip-fix-plugin",
    configureServer: fixHeader,
    // vite dev and vite preview use different server, so we need to configure both.
    configurePreviewServer: fixHeader,
  };
};

In the header of the middleware the Content-Encoding is undefined, and setting a value explicitly prevents it from being overwritten by "gzip", but I don't know how that works at all.

I'd appreciate it if someone could explain this.

bluwy commented 5 months ago

Is the issue with .gzip or .gz? If it's the latter, there's an upstream issue for that https://github.com/lukeed/sirv/issues/158. I'm not sure Vite is affecting it otherwise.

It would be nice to fix the issue upstream fix, before needing Vite to patch it.

mz8i commented 5 months ago

It's been a while since I originally ran into this, but if my original description is to be trusted, I encountered this with .gzip. I can see the issue you linked mentions .gz only, but I presume this was simply the extension the issue poster was using and the behavior is the same for both extensions. Hopefully the proposed fix tackles both cases.

bluwy commented 5 months ago

I don't think so based on https://github.com/lukeed/sirv/blob/50b1964b8a8342e14a711d47f793298c2a7aeeb7/packages/sirv/index.js#L95 (also tested locally)

jektvik commented 5 months ago

Experiencing this with .gz. The CDN serves these files differently so the dev environment gets the content auto gunzipped by the browser but in production it's crashing.

hi-ogawa commented 3 months ago

FYI, I just attempted a PR on upstream to fixed this https://github.com/lukeed/sirv/pull/161. Upstream fix is a little more involved, but if Vite needs to fix this for own usage, then it would be a one liner to comment out Content-Encoding since Vite doesn't use sirv's gzip: true, brotli: true options.