0

I am building my first Node.js MVC app (native node, not using Express) and having trouble displaying images from my html files via relative their paths.

I'll spare you my server.js and router.js code, but here is my controller code which is basically how Im loading my views:

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

var load_view = 'view_home';
var context = { foo : 'bar' };

controller.load_view(res, req, fs, load_view, context);

this gets passed to...

var url         = require('url');
var Handlebars  = require('handlebars');

function load_view(res, req, fs, view, context, session){

    // Files to be loaded, in order
    var files = [
        'view/elements/head.html',
        'view/elements/header.html',
        'view/' + view +'.html',
        'view/elements/footer.html'
    ];      

    // Start read requests, each with a callback that has an extra
    // argument bound to it so it will be unshifted onto the callback's
    // parameter list
    for(var i=0; i<files.length; ++i) 
        fs.readFile(files[i], handler.bind(null, i));

    var count = 0;

    function handler(index, err, content) {

        // Make sure we don't send more than one response on error
        if(count < 0) return;
        if(err) {
            count = -1;
            console.log('Error for file: ' + files[index]);
            console.log(err);
            res.writeHead(500);
            return res.end();
        }

        // Reuse our `files` array by simply replacing filenames with
        // their respective content
        files[index] = content;


        // Check if we've read all the files and write them in order if
        // we are finished
        if(++count===files.length) {
            res.writeHead(200, { 'Content-Type': 'text/html' });
            for(var i = 0; i < files.length; ++i) {

                var source = files[i].toString('utf8');

                // Handlebars
                var template = Handlebars.compile(source);
                var html = template(context);   

                res.write(html); /* WRITE THE VIEW (FINALLY) */

            }
            res.end();
        }

    } // handler()

} // load()

Finally, here is my html with tag and relative path in the src attribute:

<div class="help">

    <img src="../public/img/test.jpg" />

</div>

My file system as it relates to the above is as follows:

I am certain the relative path is correct but have tried all combinations of a relative path and even an absolute path. Still, no image is displayed.

Coming from a LAMP background, accessing images in the file tree is trivial but I realize the server is set up much differently here (since I was the one who set it up).

I access other files (like stylesheets) in the filesystem by creating a separate controller to load those files explicitly and access that controller using a URI. But this approach in impractical for an indeterminate number of images.

How do I access & display my images in the filesystem with Node.js?

yevg
  • 1,846
  • 9
  • 34
  • 70
  • 1
    Do you understand that node.js serves NO files by default, nothing from the file system. So, for every image you want served from the file system, you need to make sure that it is covered by a route handler for your http server. For static files and using a framework like Express, you would typically use `express.static()` to tell express to look for any files that have a specific path prefix in a particular sub-directory hierarchy on your hard drive. – jfriend00 Nov 16 '16 at 23:21
  • 1
    And, you would typically NOT want to use relative paths because those are relative to the URL of the page you're on which usually complicates things more than it simplifies things. More typically, you would use something like `/public/img/test.jpg` and you've use a route handler that sees any prefix of `/public` and then looks for that the rest of the path in a particular sub-directory hierarchy. – jfriend00 Nov 16 '16 at 23:22
  • 1
    And, a lot of the code you show in your question can go away if you use express and the built-in support that handlebars has for it. – jfriend00 Nov 16 '16 at 23:24
  • Thank your for your thorough reply. Yup..gotta route everything. its a bit hard for me to wrap my brain around NOTHING being served from the file system. I kinda expect html markup to just work, but I suppose such are the things taken for granted when working in LAMP. I'll put together a router for the images then. As for Express, I'll probably make the move over shortly, but Id prefer to do it all myself for learning reasons before I enjoy the benefits of a framework. quick question.. does ANYONE use node natively or do they all use Express or another popular framework? – yevg Nov 17 '16 at 00:57
  • 1
    I have never found a time that Express gets in my way. You have all the source code so you can always understand exactly what it's doing, you can nearly always drop down to the bare metal if you want to and it has so much code built-in that I don't have to write myself that it makes me massively more productive. Plus, there's a rich set of NPM modules built to work with it to solve all sorts of common issues, everything from user auth to cookie parsing. There really is no reason to write all this stuff yourself. If you want to know how it works, just study its source. – jfriend00 Nov 17 '16 at 01:01

1 Answers1

2

I access other files (like stylesheets) in the filesystem by creating a separate controller to load those files explicitly and access that controller using a URI.

You need to have a controller. That's how the code translates the URL that the browser requests into a response.

But this approach in impractical for an indeterminate number of images.

Write a generic one then. Convert all URLs that don't match another controller, or which start with a certain path, or which end with .jpg, or whatever logic you like into file paths based on the URL.

The read the contents of the file and output a suitable HTTP header (including the right content-type) followed by the data.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335