vite icon indicating copy to clipboard operation
vite copied to clipboard

Import files as direct bytearray

Open tristan-f-r opened this issue 2 years ago • 17 comments

Description

I'm making a tool that allows reading NBT files, and NBT files are directly binary data. In order to provide a clear demonstration, I'm grabbing all files from my local /resources folder with a glob import, but whenever I use ?raw or { as: "raw" }, it corrupts the data when it turns it into a string.

This also seems to be a used use case for other situations (stackoverflow) by other developers as well.

Do note that (if this enhancement is accepted), I am fully willing to implement this myself.

Suggested solution

Provide a new query type, e.g. ?buffer that loads the data as a Uint8Array.

Alternative

I could make a new Vite plugin, but this seems useful enough to not mandate the use of a plugin.

Validations

tristan-f-r avatar Mar 10 '23 18:03 tristan-f-r

Seems like a nice addition, but we probably can't add this until the next major since it could collide with other Vite plugins that uses ?buffer for something else. A vite plugin would be good to implement this at the meantime though.

bluwy avatar Mar 11 '23 08:03 bluwy

Alright, it seems that the stackoverflow answer offers a pretty good substitute and works for both glob imports { as: "raw-hex" } and regular/dynamic imports in the meantime.

tristan-f-r avatar Mar 11 '23 14:03 tristan-f-r

@bluwy given that the plugin is straight forward, maybe we should close this one? I also think it is an interesting feature but for completness we may later need to add other types too? ArrayBuffer, SharedArrayBuffer, etc.

patak-dev avatar May 15 '23 20:05 patak-dev

I'm not sure about your point with ArrayBuffer and SharedArrayBuffer since we're reading the file as a buffer itself. But I could see the scope grow with needing Int32Array etc instead, which maybe we can support with ?buffer=Int32Array.

I think it's a nice addition for Vite since it's small, generic, and (kinda) useful when you need it, unlike other feature requests that are specific to their preference and/or non-standard.

bluwy avatar May 16 '23 07:05 bluwy

Alright, it seems that the stackoverflow answer offers a pretty good substitute and works for both glob imports { as: "raw-hex" } and regular/dynamic imports in the meantime.

Any idea why this plugin works during build, but not during dev? In dev, my import.default is just a string (the path to the file) so I'm a bit stuck on this one 😅

braebo avatar May 29 '23 18:05 braebo

@LeoDog896 Hi there 👋 I was wondering if import raw from 'some.wasm?raw' would help!

ryuujo1573 avatar Sep 15 '23 07:09 ryuujo1573

God damn this is annoying. There needs to be an arraybuffer import

I used this plugin to get it to work

import { sveltekit } from "@sveltejs/kit/vite"
import { defineConfig } from "vite"
import arraybuffer from "vite-plugin-arraybuffer"

export default defineConfig({
    plugins: [
        sveltekit(),
        // used for importing fonts in satori /api/og/+server.ts
        arraybuffer()
    ],
})

and declared a fonts.d.ts in the folder where I was importing some fonts

declare module "*.ttf?arraybuffer" {
    const content: ArrayBuffer
    export default content
}

AlbertMarashi avatar Jan 19 '24 08:01 AlbertMarashi

Seems like a nice addition, but we probably can't add this until the next major since it could collide with other Vite plugins that uses ?buffer for something else.

@bluwy Any chance of supporting ?buffer in Vite 6?

Serator avatar May 23 '24 14:05 Serator

I am not sure if ?buffer will be added, but a neat workaround that might work for some is to use fetch in order to obtain the arrayBuffer:


import someResource from '/dir/resource.ext?url';
const arrayBuffer = await fetch(someResource).then(b => b.arrayBuffer());

The only downside with this method is that it relies on a Promise, which in some use cases might be inconvenient. Anyways I hope it helps someone!

pepefeliblu avatar Nov 27 '24 12:11 pepefeliblu

Since we now have ?url&inline, you can convert it into ArrayBuffers with a function like this:

function dataUrlToArrayBuffer(dataUrl) {
  const base64StartIndex = dataUrl.indexOf('base64,');
  if (base64StartIndex >= 0) {
    const base64 = dataUrl.slice(base64StartIndex + 'base64,'.length);
    const binaryString = atob(base64);
    const bytes = new Uint8Array(binaryString.length);
    for (var i = 0; i < binaryString.length; i++) {
      bytes[i] = binaryString.charCodeAt(i);
    }
    return bytes.buffer;
  }
  const str = decodeURIComponent(dataUrl.slice(dataUrl.indexOf(',') + 1));
  const enc = new TextEncoder();
  const bytes = enc.encode(str);
  return bytes.buffer;
}

https://stackblitz.com/edit/vitejs-vite-jgmtwvec?file=src%2Fmain.js&terminal=dev

sapphi-red avatar Feb 21 '25 10:02 sapphi-red

For those who are interested in having this a built-in support, it would be helpful if you described your expected usage of it. We are not sure how the API should be designed. For example,

  • whether you need an ArrayBuffer or a TypedArray
  • whether you can convert ArrayBuffer to what you want on your own
  • why fetching via URL is not an option
  • if you are using it on the server side, why fs.readFile is not an option

sapphi-red avatar Feb 21 '25 10:02 sapphi-red

Hi

My usage was about inlining a svg in astro in a static website. The easiest way would be to have a simple (single) line to import it as binary I've now others solutions

Note that I think your function is almost correct but it should use decodeURIComponent(). If we use decodeURI(), hashtag are not replaced and are still %23

Its-Just-Nans avatar Feb 22 '25 13:02 Its-Just-Nans

I want to import an image and then convert it to an ArrayBuffer to get a blurhash from it in my Astro app.

---
import arrayBuffer from "@assets/img/img.jpg?arraybuffer";
import { encode } from "blurhash";
import { getPixels } from "@unpic/pixels";

const jpgData = await getPixels(
  arrayBuffer
);

const data = Uint8ClampedArray.from(jpgData.data);
const blurhash = encode(data, jpgData.width, jpgData.height, 4, 4);
const placeholder = blurhashToCssGradientString(blurhash);
---

carlos-dubon avatar Feb 22 '25 18:02 carlos-dubon

For those who are interested in having this a built-in support, it would be helpful if you described your expected usage of it. We are not sure how the API should be designed. For example,

  • whether you need an ArrayBuffer or a TypedArray

  • whether you can convert ArrayBuffer to what you want on your own

  • why fetching via URL is not an option

  • if you are using it on the server side, why fs.readFile is not an option

A typedarray would be nice, but I can't think of a nice API design for it, and converting from ArrayBuffer to any TypedArray worked perfectly fine for my use case. Fetching via URL was an option, but this meant that I would have to deal with lifecycle hooks when I can very much just avoid it: essentially, fetching via URL would be a minor performance penalty on my side. This fetching, regardless, is happening client-side.

tristan-f-r avatar Feb 23 '25 20:02 tristan-f-r

A typedarray would be nice, but I can't think of a nice API design for it

Another API design idea https://github.com/vitejs/vite/pull/19346#issuecomment-2669832133

import data from 'path/to/file' with { type: "arrayBuffer" }

Its-Just-Nans avatar Feb 23 '25 21:02 Its-Just-Nans