If you haven't done so yet - read Part 1: The Vite Chronicals where I go into my woes when it comes to bundling and hosting a PDF file using Vite
. Partially because js
can be a pain but mostly because I was a dingus.
What about .json
files?
You might be laughing a bit here. Of course .json
and js
goes hand in hand. Since the beginning of time we have used .json
files to throw in config, mock data or see how many levels of data-indentation we can reach before we go crazy.
Well, what I want to do is have a data.json
file where I "mock" all the data I want/need for a page so:
a. I can move away from hardcoding things into my components.
b. I have a quick and dirty way to get up and running.
c. Mock the response from an API call.
In practise this means I can simply import my file, and since I am not crazy and love using TypeScript
, I can also type my data:
import rawData from "./assets/data.json";
const myData: UserAboutMe = rawData as UserAboutMe;
Again, as our PDF issue this works perfectly locally. No damage, all fun. but the moment you build or deploy the app, you'll notice 2 things.
1. There is no data.json
in your assets folder
Yup that is right. No file, also we're importing it like an asset so don't come at me about embedding it into the .js
file.
2. The page doesn't load and you get a console error
Failed to load module script: expected a javascript module script but the server responded with a mime type of "application/octet-stream". strict mime type checking is enforced for module scripts per html spec.
Yeah. A big. Fat. Middle finger. 💩
The solution!
So if you recall last time, our config looked like this:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
base: "/",
build: {
rollupOptions: {
input: {
main: "index.html"
},
output: {
assetFileNames: assetInfo => {
if (assetInfo?.name?.endsWith(".pdf")) {
return "[name][extname]";
}
return "assets/[name]-[hash][extname]";
}
}
}
}
});
What we need to do however is copy any .json
assets over to our distribution folder. We need static content! Luckily, there is a plugin that does the job called viteStaticCopy
. It is as simple as:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { viteStaticCopy } from "vite-plugin-static-copy";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
viteStaticCopy({
targets: [
{
src: "src/assets/*.json",
dest: "assets"
}
]
})
],
base: "/",
build: {
rollupOptions: {
input: {
main: "index.html"
},
output: {
assetFileNames: assetInfo => {
if (assetInfo?.name?.endsWith(".pdf")) {
return "[name][extname]";
}
return "assets/[name]-[hash][extname]";
}
}
}
}
});
One merge, deploy and refresh later and our problems are solved! You could also double check that it works as expected by ensuring that the file is present in your dist
folder locally.
The next enhancement I think I could make is rather move the data.json
file itself to a data
folder (since it isn't just an asset), what do you think?
Versions Used
node: 18.14.0
vite: 6.3.3
react: 18.3.1