I'm an absolute begginer to Node.js, I'm mostly just trying to implement an npm package into my website but I am struggling to run my existing HTML and CSS (.less specifically).
I am not using express.
Here's my current index.js:
const http = require("http");
const fs = require("fs");
const PORT = 3030;
fs.readFile('website/index.html', function (error, html) {
if (error) {
console.error("Error reading HTML file:", error);
return;
}
http.createServer(function (request, response) {
response.writeHeader(200, {"Content-Type": "text/html"});
response.write(html);
response.end();
}).listen(PORT);
console.log(`Server is running on port ${PORT}`);
});
When I enter the page it's just plain HTML with no images and any kind of css. The issue is not with LESS, I tried using just CSS aswell.
I think the issue is that I have to tell the server to load the image and style like I did with HTML but I don't know how, I couldn't find any question or tutorial for this since I don't use Express.
Any help is appreciated, I'm willing to provide more info on need.
Welcome to Stack Overflow!
Looking at your code, it makes total sense that you're only seeing a plain HTML file — the browser is probably trying to load styles and images, but your backend is hardcoded to only ever return your HTML file.
If you look at this section of your code:
http.createServer(function (request, response) {
response.writeHeader(200, {"Content-Type": "text/html"});
response.write(html);
response.end();
}).listen(PORT);
This code creates an HTML server that, only every request, responds with the contents of the html
variable with the Content-Type
header set to html
. Since the html
variable only contains the contents of website/index.html
, that is all that will ever be sent whenever any page is visited!
There are a couple ways to serve everything.
If you want to keep using plain Node.js without any external libraries, you can access request.url
to return different files depending on what path was requested. When, for example, http://localhost:3030/file.txt
is loaded, the value of request.url
will be "/file.txt"
.
A naive solution is to use a switch statement, like so:
switch (request.url) {
case "/": {
response.writeHeader(200, {"Content-Type": "text/html"});
fs.createReadStream("website/index.html").pipe(response);
response.end();
break;
}
case "/file.txt": {
// serve file.txt
// etc.
}
}
Note: what are
createReadStream()
and.pipe()
?That line basically just feeds the contents of the file into the HTTP response.
createReadStream()
creates something called a stream, which is a little bit like it sounds — a stream of bytes flowing from somewhere into something else. Calling.pipe(thing)
on a stream lets you choose what the stream flows into. In this case, we're streaming data from a file into the HTTP response.You can learn more about streams in this lovely FreeCodeCamp article.
However, this quickly falls apart when you have lots of different files and images. It sucks to have to hardcode another branch every time you want to add another file. It would be much better just to serve up everything in your filesystem...
I heavily encourage you to figure this out yourself, but I will provide a couple pointers.
To get a file path, you can simply concatenate "website" + request.url
. If request.url
is "/file.txt"
, this will be "website/file.txt"
, giving you the right file path!
However, notice that paths ending in /
typically serve a file called index.html
instead. You can handle this with an if case, like so:
let path = "website" + request.url;
if (path.endsWith("/")) {
path += "index.html";
}
// now serve the file at path!
This appends index.html
to the end of the path if it ends with /
.
Finally, be really careful with this method! You can easily let anyone on the internet access any file on your computer simply by using ..
. You might know from terminals that ..
means "previous directory," and this works when reading files in Node.js too! You should make sure to remove all instances of /..
from the path, perhaps like so:
path = path.replaceAll("/..", "");
If you don't care about learning vanilla Node.js, or you want to experiment with some more complex code, Express is a very popular HTTP server library.
Using Express, you can implement a static server (that's also ..
-safe) in just a couple lines:
const express = require("express");
const app = express();
app.use(express.static("website"));
app.listen(3030, () => {
console.log("Server is running on port 3030");
});
(Make sure to run the command npm install express
to install the library.)
I recommend exploring the Express documentation to learn more if you want to go down this route!