reactjsexpressvite

Files in the public directory are served at the root path error when serving a React + Vite app with Express


I've built an app using React + Vite.

The UI is using IBM's Carbon Design System. I built the CSS with Sass which has

// src/assets/styles.scss
@use '@carbon/react' with (
    $font-path: 'public/fonts/ibm'
); 

Compiled with sass src/assets/styles.scss src/styles.css --load-path=node_modules

This generates a static CSS file at src/styles.css. That file contains references to the fonts which Carbon supplies, all of which have a path public/fonts/ibm/* which is what's specified as $font-path in the Sass file.

I had to copy over the fonts using cp -r node_modules/@ibm/plex/IBM-Plex-* public/fonts/ibm

When I run the application with npm run dev I get the following warning in the terminal

Files in the public directory are served at the root path. Instead of /public/fonts/ibm/IBM-Plex-Sans/fonts/split/woff2/IBMPlexSans-Light-Latin1.woff2, use /fonts/ibm/IBM-Plex-Sans/fonts/split/woff2/IBMPlexSans-Light-Latin1.woff2

This message is repeated several times, for several different font files.

However, the application loads correctly in the browser. I get a 200 response for all fonts and they are accessible from a path that does include "public" e.g.

http://localhost:5173/public/fonts/ibm/IBM-Plex-Sans/fonts/split/woff2/IBMPlexSans-Light-Latin1.woff2

I then needed to build the application to deploy to Google Cloud. I did that by following a tutorial at https://www.youtube.com/watch?v=NMnKGHgw8aM. The tutorial says to use npm run build. This does indeed create the dist/* folder with the relevant files however the following warning appears many times for different font files e.g.

public/fonts/ibm/IBM-Plex-Sans/fonts/split/woff2/IBMPlexSans-Light-Latin1.woff2 referenced in public/fonts/ibm/IBM-Plex-Sans/fonts/split/woff2/IBMPlexSans-Light-Latin1.woff2 didn't resolve at build time, it will remain unchanged to be resolved at runtime

The files are created in the dist/ directory as shown in VSCode:

enter image description here

Bizarrley, if I list the files/folders in the dist/ directory (including hidden) they don't appear in the terminal:

% pwd 
/Users/andy/Documents/VSCode/react/dist/assets
andy@macbook assets % ls -lah 
total 1824
drwxr-xr-x  4 andy  staff   128B Nov  7 10:00 .
drwxr-xr-x  6 andy  staff   192B Nov  7 10:00 ..
-rw-r--r--  1 andy  staff   693K Nov  7 10:00 index-524dIBfm.css
-rw-r--r--  1 andy  staff   214K Nov  7 10:00 index-C6J8y3S0.js

The tutorial starts an Express server by going up a level cd .. and then doing npm install express followed by adding this as index.js

const express = require('express');
const app = express();
app.use(express.json());
app.use(express.static('react/dist'));
const port = process.env.PORT || 8080;
app.listen(port, () => {
    console.log(`Listening on port ${port}`);
})

The line app.use(express.static('react/dist')); is meant to serve the built React app as static files.

When running npm run start the Express server does indeed start and the application loads in the browser at http://localhost:8080/

But all of the fonts give 404 errors. These errors appear in the console for many different font files

index-524dIBfm.css:1 GET http://localhost:8080/assets/public/fonts/ibm/IBM-Plex-Sans/fonts/split/woff2/IBMPlexSans-Light-Latin1.woff2 net::ERR_ABORTED 404 (Not Found)

I'm confused as to what the source of this error really is. Given the strange behaviour where the files are shown in VSCode's file browser but not with ls -lah. Or, whether this is something specific to Vite's configuration. For reference the Vite config only has what was created by default, i.e.

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'

// https://vitejs.dev/config/
export default defineConfig({
    plugins: [react()],
})

Solution

  • In react all the files that are inside public folder are served inside the root as your error says.

    So you have to remove public from your paths so instead of using /public/fonts/ibm use /fonts/ibm and apply this to all the paths where you added public in them.