preactjs / preset-vite

Preset for using Preact with the vite bundler
https://npm.im/@preact/preset-vite
MIT License
260 stars 26 forks source link

feat: Allow non-text (and non-UTF8) files to be fetched during prerender #138

Closed mwszekely closed 2 months ago

mwszekely commented 2 months ago

I've run into an issue where I need to fetch binary data from a local file, and while this is fine at runtime, the patched version of fetch that prerendering uses always decodes all local files as text via UTF-8.

All this change includes is a fetchEncoding option for the PrerenderPlugin that, when not undefined, specifies the encoding passed to fs.readFile. I'm not sure this is the ideal solution to the problem (e.g. it's unfortunate that null and undefined end up being treated differently, and I don't know about fetchEncoding as a name), so I'm more than okay with any alternative method—I can open an issue instead if that's the better route for this.

rschristian commented 2 months ago

Thanks, but this is better left to user land. You can trivially provide your own "polyfill" like so instead:

let initialized = false;
export async function prerender(data) {
    const init = async () => {
        globalThis.fetch = ...

        initialized = true;
    }
    if (!initialized) await init();
    ...
}

This also lets you control the content type a bit better, perhaps by file extension for provided URL.

rschristian commented 2 months ago

I realize only now that I go to use it that we don't provide a way to get the original fetch impl very nicely, requiring users to cache the vanilla impl in their config file themselves.

I'm going to think on it for a day, but at the very least, I'll introduce a way to get at the original fetch implementation for users who want to make their own wrapper. Something along the lines of this:

let initialized = false;
export async function prerender(data) {
    const init = async () => {
        globalThis.fetch = (url, opts) => {
            if (...) { ... }

            // this is the standard/vanilla fetch impl,
            // not the patched version.
            return globalThis.nodeFetch(url, opts);
        };

        initialized = true;
    }
    if (!initialized) await init();
    ...
}

Hopefully this will be better.