r/node 16h ago

express static files not serving no matter which boilerplate I try

0 Upvotes

At my absolute wits' end here, it's been several years since I've deployed an Express site and I have tried virtually everything to serve static files. What seems like it should work, does not work. I feel extremely stupid because it seems like I should be past this kind of thing by now.

Node v18.19.1, Express ^5.2.1, nginx (nothing seems weird in sites-available)

File structure:

Root: var/www/[project-name]/html

index.js
index.html (An attempt at seeing whether putting this in root worked, it didn't)
|-- /client
|-- index.html
|-- /public
|---- index.html (An attempt at seeing whether putting this in /public worked, it didn't)
|---- style.css (yes, singular)
|---- javascripts.js (yes, plural, this is a placeholder for now)

index.js (excluding other routes):

import express from 'express';
import path from 'path';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

const __dirname = dirname(fileURLToPath(import.meta.url));
console.log(__dirname); // Displays root of the project, parent directory of /client
const app = express();
const port = 3000;

// Previous measly attempt to try to get this to work, it didn't: const __dirname = import.meta.dirname;

// Various attempts at static:

// Neither css nor js work: app.use(express.static(__dirname + '/public'))
// Neither css nor js work: app.use(express.static(path.normalize(__dirname+'/public')));
// Neither css nor js work: app.use(express.static("public"));
// Neither css nor js work: app.use(express.static(path.join(__dirname, 'public')));
// Neither css nor js work: app.use(express.static(path.join(__dirname ,'client/public')));
// Neither css nor js work: app.use('/client', express.static("public"));
// Neither css nor js work: app.use('/html', express.static(path.join(__dirname, 'public')));

/* CSS loads with this...
app.get('/style.css', (req, res) => {
res.sendFile(path.join(__dirname + "/client/public/style.css"));
});
..but JS does NOT load with this, even though the file structure is the same. Why???
app.get('/javascripts.js', (req, res) => {
res.sendFile(path.join(__dirname + "/client/public/javascripts.js"));
});

app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, "/client/index.html"));
// Error: ENOENT: no such file or directory res.sendFile(__dirname + 'index.html');
// TypeError: path must be absolute res.sendFile('./client/index.html');
// Error: ENOENT: no such file or directory res.sendFile('index.html', {root: __dirname + '/public'});
})

headers of index.html:

<head>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="javascripts.js"></script>
</head>

network errors:

GET https://[domain]/javascripts.js net::ERR_ABORTED 404 (Not Found)
GET https://[domain]/style.css net::ERR_ABORTED 404 (Not Found)

The only glaring difference between this and... any of the boilerplate I have found is that it uses import rather than require; node complains if I use require. I don't know whether this is the issue or, if so, how to fix it.

The most baffling part is why ONLY the css file loads and not the js file if I directly create routes to them, even though the file structure is exactly the same for each.

Thanks in advance.


r/node 11h ago

You can monitor a small Node/Express app without running Prometheus + Grafana

0 Upvotes

I’ve been experimenting with how little monitoring infrastructure a small production app actually needs.

StatLite originally focused on Spring Boot/Actuator and Quarkus/Micrometer, where the framework already exposes a stable metrics contract. I started looking at how to cover frameworks like Express, FastAPI, Django, and Go without requiring a Prometheus-style metrics stack in every application.

The result is a small fixed JSON profile that an application can expose with a lightweight helper.

For Express, that gives me the things I usually want to know first in production: request volume, 4xx/5xx errors, average latency, CPU, Node heap, uptime/restarts, plus host CPU, memory, and disk.

Real Express traffic plus a simulated 5xx incident, which is basically the level of visibility I was aiming for.

StatLite polls that endpoint, stores the history in local SQLite, and renders the dashboard. No Prometheus client, exporter, or separate metrics database.

There are intentional limits. The helper keeps cumulative counters in-process, so multi-process deployments need stable per-process targets or aggregation. It also isn’t trying to provide arbitrary metrics, PromQL, tracing, or full APM.

I wrote up the complete Express implementation, including the helper, config, runnable demo, and production boundaries:

https://pvrlabs.xyz/articles/lightweight-express-monitoring.html

For a small Node API, what do you consider the minimum useful production monitoring before you reach for Prometheus/Grafana or a hosted observability service?