26

I want to render raw .html pages using Express 3 as follows:

server.get('/', function(req, res) {
    res.render('login.html');
}

This is how I have configured the server to render raw HTML pages (inspired from this outdated question):

server
    .set('view options', {layout: false})
    .set('views', './../')
    .engine('html', function(str, options) {
        return function(locals) {
             return str;
        };
    });

Unfortunately, with this configuration the page hangs and is never rendered properly. What have I done wrong? How can I render raw HTLM using Express 3 without fancy rendering engines such as Jade and EJS?

Community
  • 1
  • 1
Randomblue
  • 112,777
  • 145
  • 353
  • 547
  • What's the motivation behind the decision to serve static HTML via Nodejs? In isolation from the broader context it seems like a sub-optimal solution. – Richard Marr Jan 11 '13 at 15:45
  • 3
    It's a very simple page. The overhead of using Jade, for example, is not worth it. – Randomblue Jan 11 '13 at 15:48
  • Okay, so assuming a heavily hit static page within an existing high traffic Node app, with no requirement for shared templates. Even still, this seems like too much coding to me, and coding means dev cost + testing + maintenance. I'd personally just set long cache headers on the response and let Nginx/Apache serve the content from cache. That way you don't need custom code and the template generation overhead becomes irrelevant. – Richard Marr Jan 11 '13 at 16:20
  • 4
    It's actually static HTML pages that are populated client-side using JavaScript. The information for the population is generated real-time by Node.JS. I'm not moving off Node.JS. – Randomblue Jan 11 '13 at 16:23
  • Not suggesting you abandon Node, can I assume from your response that you're not running Node behind a web server? Does that mean you need direct access for websockets? – Richard Marr Jan 11 '13 at 16:27
  • I'm indeed using Node as a webserver. No Nginx involved. I do have websockets, but this is maybe a bit too cutting edge for my purposes. – Randomblue Jan 11 '13 at 16:30
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/22598/discussion-between-richard-marr-and-randomblue) – Richard Marr Jan 11 '13 at 16:42

11 Answers11

46

What I think you are trying to say is: How can I serve static html files, right?

Let's get down to it.

First, some code from my own project:

app.configure(function() {
    app.use(express.static(__dirname + '/public'));
});

What this means that there is a folder named public inside my app folder. All my static content such as css, js and even html pages lie here.

To actually send static html pages, just add this in your app file

app.get('/', function(req, res) {
  res.sendFile(__dirname + '/public/layout.html');
});

So if you have a domain called xyz.com; whenever someone goes there, they will be served layout.html in their browsers.

Edit

If you are using express 4, things are a bit different. The routes and middleware are executed exactly in the same order they are placed.

One good technique is the place the static file serving code right after all the standard routes. Like this :

// All standard routes are above here
app.post('/posts', handler.POST.getPosts);

// Serve static files
app.use(express.static('./public'));

This is very important as it potentially removes a bottleneck in your code. Take a look at this stackoverflow answer(the first one where he talks about optimization)

The other major change for express 4.0 is that you don't need to use app.configure()

shash7
  • 1,719
  • 1
  • 18
  • 20
  • 2
    Works like a charm - in my case I was using relative paths and ended up with a 403 so used: `res.sendfile(path.resolve('../path/to/index.html'));` – Michael Feb 10 '14 at 22:02
  • Sorry for bringing up such an old post - but does `sendfile` cache the contents? Or does it actually read the file before sending it? – Martol1ni Oct 25 '15 at 23:10
  • @Martol1ni I am not really sure. In my test I changed the contents of a single html file and express was able to served the updated copy so I reckon it doesn't cache by default. However, I think you're looking for this though: https://github.com/isaacs/st – shash7 Oct 26 '15 at 12:26
  • 1
    use sendFile instead of sendfile which now is deprecated – Gonzalo.- Jun 13 '17 at 19:52
20

If you don't actually need to inject data into templates, the simplest solution in express is to use the static file server (express.static()).

However, if you still want to wire up the routes to the pages manually (eg your example mapping '/' to 'login.html'), you might try res.sendFile() to send your html docs over:

http://expressjs.com/api.html#res.sendfile

hunterloftis
  • 13,386
  • 5
  • 48
  • 50
  • 1
    `res.sendFile()` does indeed send the html, but not all the associated CSS, JS, etc. It doesn't seem appropriate for manual routing. – Randomblue Jan 11 '13 at 10:09
  • In order to get css, js, etc sent over, the simplest mechanism is to just server them with `express.static()` ... actually for the opposite reason, because `sendFile()` is manual routing while `static()` will automatically server static pages. – hunterloftis Jan 11 '13 at 21:12
  • @Randomblue See my answer to handle css and javascript, lest you want a whole bunch of 404's – FredTheWebGuy Sep 04 '13 at 17:30
  • 2
    For the record, it's sendfile with a lower case F. Weird that it's not camel-cased, but that's how it is. – WuTheFWasThat May 23 '14 at 21:14
19

Have you tried using the fs module?

server.get('/', function(req, res) {
    fs.readFile('index.html', function(err, page) {
        res.writeHead(200, {'Content-Type': 'text/html'});
        res.write(page);
        res.end();
    });
}
sheldonk
  • 2,604
  • 3
  • 22
  • 32
  • Apparently this is not production-ready because it doesn't cache the results. – Randomblue Jan 02 '13 at 11:26
  • 1
    Randomblue, this shouldn't be a problem for you as you're serving static files so (a) in production caching of static content should be handled by your web server not your application server, and (b) you're serving static files not processed templates so the performance hit is far less than the normal case – Richard Marr Jan 11 '13 at 15:42
7

as the document says : 'Express expects: (path, options, callback)' format function in app.engin(...).

so you can write your code like below(for simplicity, but it work):

server
.set('view options', {layout: false})
.set('views', './../')
.engine('html', function(path, options, cb) {
    fs.readFile(path, 'utf-8', cb);
});

of course just like 2# & 3# said, you should use express.static() for static file transfer; and the code above not suit for production

tztxf
  • 173
  • 2
  • 8
6

First, the mistake you did was trying to use the express 2.x code snippet to render raw HTML in express 3.0. Beginning express 3.0, just the filepath will be passed to view engine instead of file content.

Coming to solution,

create a simple view engine

var fs = require('fs'); 

function rawHtmlViewEngine(filename, options, callback) {
    fs.readFile(filename, 'utf8', function(err, str){
        if(err) return callback(err);

        /*
         * if required, you could write your own 
         * custom view file processing logic here
         */

        callback(null, str);
    }); 
}

use it like this

server.engine('html', rawHtmlViewEngine)
server.set('views', './folder');
server.set('view engine', 'html');


Reference

Official express 2.x to 3.x migration guide

See 'Template engine integration' section in this url https://github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x

sidonaldson
  • 24,431
  • 10
  • 56
  • 61
Jay Kumar
  • 1,514
  • 1
  • 14
  • 17
2

After a fresh install of the latest version of Express

express the_app_name

Creates a skeleton directory that includes app.js.

There is a line in app.js that reads:

  app.use(express.static(path.join(__dirname, 'public')));

So a folder named public is where the magic happens...

Routing is then done by a function modeled this way:

app.get('/', function(req,res) {
      res.sendfile('public/name_of_static_file.extension');
    });

*Example:* An index.html inside the public folder is served when invoked by the line:

   app.get('/', function(req,res) {
  res.sendfile('public/index.html');
});

As far as assets go: Make sure the css and javascript files are called from the folder relative to the public folder.

A vanilla Express install will have stylesheets, javascripts, and images for starting folders. So make sure the scripts and css sheets have the correct paths in index.html:

Examples:

<link href="stylesheets/bootstrap.css" rel="stylesheet">

or

<script src="javascripts/jquery.js"></script>
FredTheWebGuy
  • 2,546
  • 3
  • 27
  • 34
0

You can render .html pages in express using following code:-

var app = express();

app.engine('html', ejs.__express);

And while rendering, you can use following code:-

response.render('templates.html',{title:"my home page"});
Meet Mehta
  • 4,839
  • 3
  • 20
  • 27
0

I wanted to do this because I'm creating a boilerplate NodeJS server that I don't want tied to a view engine. For this purpose it's useful to have a placeholder rendering engine which simply returns the (html) file content.

Here's what I came up with:

//htmlrenderer.js

'use strict';

var fs = require('fs'); // for reading files from the file system

exports.renderHtml = function (filePath, options, callback) { // define the template engine
    fs.readFile(filePath, function (err, content) {
        if (err) return callback(new Error(err));
        var rendered = content.toString();
        // Do any processing here...
        return callback(null, rendered);
    });
};

To use it:

app.engine('html', htmlRenderer.renderHtml);
app.set('view engine', 'html');

Source: http://expressjs.com/en/advanced/developing-template-engines.html

Comments and constructive feedback are welcome!

stone
  • 8,422
  • 5
  • 54
  • 66
0

After years a new answer is here.

Actually this approach like skypecakess answer;

var fs = require('fs');

app.get('/', function(req, res, next) {
    var html = fs.readFileSync('./html/login.html', 'utf8')
    res.send(html)
})

That's all...

Also if EJS or Jade will be used the below code could be used:

var fs = require('fs');

app.get('/', function(req, res, next) {
    var html = fs.readFileSync('./html/login.html', 'utf8')
    res.render('login', { html: html })
})

And views/login.ejs file contains only the following code:

<%- locals.html %>
efkan
  • 12,991
  • 6
  • 73
  • 106
0
app.get('/', function(req, res) {
  returnHtml(res, 'index');
});

function returnHtml(res, name) {
  res.sendFile(__dirname + '/' + name + '.html');
}

And put your index.html to your root page, of course you could create a /views folder for example and extend returnHtml() function.

Robert
  • 106
  • 1
  • 6
0

You can send file using res.sendFile(). You can keep all html files in views folder and can set path to it in options variable.

app.get('/', (req, res)=>{
    var options = {  root: __dirname + '/../views/' };
      var fileName = 'index.html';
      res.sendFile(fileName, options);
});
last_fix
  • 369
  • 1
  • 4
  • 19