How do I serve static files through Node.js locally?
Asked Answered
H

3

21

I have the following file locations :

file:///Users/MyName/Developer/sitename/scripts (contains all .js files..)
file:///Users/MyName/Developer/sitename/css (contains all .css files..)
file:///Users/MyName/Developer/sitename/images (contains all .jpg/png/etc. files..)
file:///Users/MyName/Developer/sitename/sitename.html
file:///Users/MyName/Developer/sitename/server.js

Inside sitename.html I load all necessary files as follows for example :

<html>
  <head>
    <script src="scripts/somefile.js"></script>
  </head>
  ...
</html>

So whenever I open up file:///Users/MyName/Developer/sitename/sitename.html everything works fine.

However, whenever I try to load file:///Users/MyName/Developer/sitename/sitename.html via a local Node.js server that I've setup (server file location : file:///Users/MyName/Developer/sitename/server.js) as follows :

var http = require("http"); 
var fs = require("fs");

fs.readFile('./sitename.html', function (err, html) 
{
    if (err) throw err; 

    http.createServer(function (request,response)
    {  
        // serve site
        if (request.url === "/")
        {
            response.writeHeader(200, {"Content-Type": "text/html"});  
            response.write(html);  
        }
        response.end(); 
    }).listen(8080); 
});

sitename.html is found and loaded but all the other files that are supposed to load through it fail to load because they're all given the prefix http://localhost:8080/ (http://localhost:8080/scripts/somefile.jsis not a valid file path for example).

It looks like as soon as the server is created (inside http.createServer(.....);) the context changes and the parent directory now becomes http://localhost:8080/ instead of file:///Users/MyName/Developer/sitename/ which makes sense I guess but is not very helpful when using files that are still stored locally.

How do I work around that? Is the fact that I'm storing server.js (just for the time being) in the same directory making things even more confusing?

Thanks!

Heilungkiang answered 1/10, 2014 at 15:55 Comment(0)
C
12

You're able to load the files using the file:// URL because it's a feature of your web browser.

When loading the address http://localhost:8080 you're no longer leveraging the browser's ability to serve the files (you're accessing the Node.js server). The HTML page being served contains relative paths which work in conjunction with the current hostname to load the assets.

There is a multitude of options for serving the assets.

You could serve the files with Node.js:

Alternatively you could use a web server to serve the files for you. This is likely to be the most performant option. Here is an example of serving static content with nginx.

Copernicus answered 1/10, 2014 at 23:34 Comment(3)
Hey thanks a lot for your reply. I'll take a look at those 2 options you suggested. But just because I'm new at this, could you please elaborate a bit more : So whenever someone builds a web app and uses Node.js to serve the app, and the app has lots of static files (obviously), does that mean they always need to use "plugins" like the one you suggested, when testing their app locally ? It seems a bit weird doesn't it, that Node doesn't come with a default option to specify the parent folder location for all static files that will be served.? Thanks once again for your help!Heilungkiang
Node gives you the tools to serve those files, you simply have to implement it. That's why so many modules exist, because functionality just doesn't come out of the box. You can definitely serve the file with Node.js but you would have to implement a route in your server that recognizes a request for "/style.css" and have it read that file from disk.Copernicus
Thanks a lot for clarifying that JeffHeilungkiang
M
43

The easiest solution I found on serving local static files is to use Http-Server.

Its usage is dead simple. After installing it globally

 npm install http-server -g

Go to the root directory you want to serve

cd <dir>
http-server

That's it!

Manipur answered 17/12, 2015 at 2:40 Comment(2)
This worked perfectly for me and I believe is the exact solution the OP was was looking for! Thank you @ManipurNadean
Wow, that's amazing bro! From now on I can check my React and Next app builds by serving locally.Cerelia
C
12

You're able to load the files using the file:// URL because it's a feature of your web browser.

When loading the address http://localhost:8080 you're no longer leveraging the browser's ability to serve the files (you're accessing the Node.js server). The HTML page being served contains relative paths which work in conjunction with the current hostname to load the assets.

There is a multitude of options for serving the assets.

You could serve the files with Node.js:

Alternatively you could use a web server to serve the files for you. This is likely to be the most performant option. Here is an example of serving static content with nginx.

Copernicus answered 1/10, 2014 at 23:34 Comment(3)
Hey thanks a lot for your reply. I'll take a look at those 2 options you suggested. But just because I'm new at this, could you please elaborate a bit more : So whenever someone builds a web app and uses Node.js to serve the app, and the app has lots of static files (obviously), does that mean they always need to use "plugins" like the one you suggested, when testing their app locally ? It seems a bit weird doesn't it, that Node doesn't come with a default option to specify the parent folder location for all static files that will be served.? Thanks once again for your help!Heilungkiang
Node gives you the tools to serve those files, you simply have to implement it. That's why so many modules exist, because functionality just doesn't come out of the box. You can definitely serve the file with Node.js but you would have to implement a route in your server that recognizes a request for "/style.css" and have it read that file from disk.Copernicus
Thanks a lot for clarifying that JeffHeilungkiang
C
5

The problem is that while you've defined the path for one static resource (sitename.html), you haven't defined the path for all the other static resources it references (e.g. somefile.js). Assuming the following file structure, below contains the server code that handles loading static resources relative to your public directory (www), without using external modules. (partly taken from here)

project/
    server/    
        server.js
        dispatcher.js
    www/
        index.html
        js/ (your javascript files)
        css/ (your css files)

server.js:

var http = require('http');
http.createServer(handleRequest).listen(8124, "127.0.0.1");
var dispatcher = require('./dispatcher.js');

function handleRequest(req, res) {
    try {
        console.log(req.url);
        dispatcher.dispatch(req, res);
    } catch(err) {
        console.log(err);
    }
}

dispatcher.js:

var fs = require('fs');
var path = require('path');

this.dispatch = function(request, response) {
    //set the base path so files are served relative to index.html
    var basePath = "../www";
    var filePath = basePath + request.url;

    var contentType = 'text/html';
    var extname = path.extname('filePath');
    //get right Content-Type
    switch (extname) {
        case '.js':
            contentType = 'text/javascript';
            break;
        case '.css':
            contentType = 'text/css';
            break;
    }

    //default to index.html
    if (filePath == basePath + "/") {
        filePath = filePath + "index.html";
    }

    //Write the file to response
    fs.readFile(filePath, function(error, content) {
        if (error) {
            response.writeHead(500);
            response.end();
        } else {
            response.writeHead(200, {'Content-Type': contentType});
            response.end(content, 'utf-8');
        }
    });

}
Chalcedony answered 2/10, 2015 at 20:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.