57

I have created a JavaScript program which generates a list of data. Example output below:

output one 
output two 
output three 
...

I would like to be able to generate a HTML file which can be saved to disk and opened with a browser. Below is a sample of the HTML I would like to generate.

<html>
    <head>
    </head>
    <body>
        <table id="history_table">
            <tr>
                <td>header 1</td>
                <td>header 2</td>
                <td>header 3</td>
            </tr>
            <tr>
               <td>output one</td>
            </tr>
            ...
        </table>
    </body>
</html>

I have tried doing this:

var htmlDoc = document.createElement("HMTL");
htmlDoc.innerhtml('<head></head><body>...</body>');

But this is clearly wrong since the document object does not exist.

I think this question makes sense especially from the amount of up votes it has received. can it be reopened?

4
  • 3
    There is plenty of node examples on how to serve page templates.. specially if you look at ExpressJS. Although not one part of your code shows any thing to do with NodeJS...im wondering if you are confused on what NodeJS is...
    – Sir
    Commented Feb 7, 2014 at 1:14
  • 2
    Nodejs does not have DOM manipulation out of the box. You will have to install a relevant library to be able to do such things. I'm about to try node-dom but you can do some research on that direction by yourself
    – Loupax
    Commented Apr 25, 2015 at 7:36
  • 3
    I have no idea why this question was originally closed. With many upvotes and 4 stars, along with a detailed answer (shameless plug), the intent of the poster was very clear. My two cents. Commented Jun 21, 2017 at 14:32
  • 1
    Im not sure if someone can change that but i agree, the answer helped me out allot and a bunch of others Commented Jan 10, 2019 at 1:30

6 Answers 6

87

Node.js does not run in a browser, therefore you will not have a document object available. Actually, you will not even have a DOM tree at all. If you are a bit confused at this point, I encourage you to read more about it before going further.

There are a few methods you can choose from to do what you want.


Method 1: Serving the file directly via HTTP

Because you wrote about opening the file in the browser, why don't you use a framework that will serve the file directly as an HTTP service, instead of having a two-step process? This way, your code will be more dynamic and easily maintainable (not mentioning your HTML always up-to-date).

There are plenty frameworks out there for that :

The most basic way you could do what you want is this :

var http = require('http');

http.createServer(function (req, res) {
  var html = buildHtml(req);

  res.writeHead(200, {
    'Content-Type': 'text/html',
    'Content-Length': html.length,
    'Expires': new Date().toUTCString()
  });
  res.end(html);
}).listen(8080);

function buildHtml(req) {
  var header = '';
  var body = '';

  // concatenate header string
  // concatenate body string

  return '<!DOCTYPE html>'
       + '<html><head>' + header + '</head><body>' + body + '</body></html>';
};

And access this HTML with http://localhost:8080 from your browser.

(Edit: you could also serve them with a small HTTP server.)


Method 2: Generating the file only

If what you are trying to do is simply generating some HTML files, then go simple. To perform IO access on the file system, Node has an API for that, documented here.

var fs = require('fs');

var fileName = 'path/to/file';
var stream = fs.createWriteStream(fileName);

stream.once('open', function(fd) {
  var html = buildHtml();

  stream.end(html);
});

Note: The buildHtml function is exactly the same as in Method 1.


Method 3: Dumping the file directly into stdout

This is the most basic Node.js implementation and requires the invoking application to handle the output itself. To output something in Node (ie. to stdout), the best way is to use console.log(message) where message is any string, or object, etc.

var html = buildHtml();

console.log(html);

Note: The buildHtml function is exactly the same as in Method 1 (again)

If your script is called html-generator.js (for example), in Linux/Unix based system, simply do

$ node html-generator.js > path/to/file

Conclusion

Because Node is a modular system, you can even put the buildHtml function inside it's own module and simply write adapters to handle the HTML however you like. Something like

var htmlBuilder = require('path/to/html-builder-module');

var html = htmlBuilder(options);
...

You have to think "server-side" and not "client-side" when writing JavaScript for Node.js; you are not in a browser and/or limited to a sandbox, other than the V8 engine.

Extra reading, learn about npm. Hope this helps.

4
  • 2
    I find no reason for a Document object not to exist on the server. Let's not forget what window.document is on the client: An XML Document instance with methods that allow you DOM manipulation. We should (and can) do DOM manipulation on the server using any language
    – Loupax
    Commented Apr 25, 2015 at 7:32
  • 4
    @Loupax, the question, here, is not whether you can or can't, but if there is one by default. Server side JavaScript do not have a global window object. It does not have a Document either. It can have either, but don't need any. Therefore, and unless you create or add an implementation of either, they won't exist. Try not confuse novice programmers with Node.js. There must be a distinction between server side programming and client side; both are using the same language and syntax, but are not sharing the same privileges and container. Commented Apr 25, 2015 at 17:25
  • Maybe, but I find it a bit wrong when the question was about "how can I do DOM manipulation on the server" and all answers are "you cannot" when you clearly can. You might need to install a library but you can. And this is worth mentioning at least IMO
    – Loupax
    Commented Apr 25, 2015 at 19:55
  • 6
    @Loupax I believe you have misread the question. It is not about DOM manipulation, but about generating HTML. The only mention of the Document object is what the OP tried to do, which is why I said "you cannot do that", and I am 100% correct about that; he was confusing JavaScript for the browser, and JavaScript in a Node.js application. I repeat, this has nothing to do with whether you can or can't do DOM manipulation. Now, please re-read the question and my answer and stop arguing about it. Commented Apr 25, 2015 at 23:49
18

Although @yanick-rochon answer is correct, the simplest way to achieve your goal (if it's to serve a dynamically generated html) is:

var http = require('http');
http.createServer(function (req, res) {
  res.write('<html><head></head><body>');
  res.write('<p>Write your HTML content here</p>');
  res.end('</body></html>');
}).listen(1337);

This way when you browse at http://localhost:1337 you'll get your html page.

2
  • -1 This gives none of the header info that is required by the HTTP standard. Node doesn't do that automatically. Commented Aug 26, 2014 at 0:04
  • 6
    @OneHoopyFrood what required headers are you missing? content-length? that's a hard ask for dynamically generated content. Content-type defaults to text/html, encoding defaults to latin1, so this should all be good. This is valid and great for quick & dirty scripts.
    – hraban
    Commented Sep 6, 2017 at 14:45
9

You can use jsdom

const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const { document } = (new JSDOM(`...`)).window;

or, take a look at cheerio, it may more suit your case.

6

If you want to create static files, you can use Node.js File System Library to do that. But if you are looking for a way to create dynamic files as a result of your database or similar queries then you will need a template engine like SWIG. Besides these options you can always create HTML files as you would normally do and serve them over Node.js. To do that, you can read data from HTML files with Node.js File System and write it into response. A simple example would be:

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

http.createServer(function (req, res) {
  fs.readFile(req.params.filepath, function (err, content) {
    if(!err) {
      res.end(content);
    } else {
      res.end('404');
    }
  }
}).listen(3000);

But I suggest you to look into some frameworks like Express for more useful solutions.

2
  • Just a note on this answer; do not use code like this on production :) because req.params.filepath could very well be a value such as /etc/passwd or something like that. Commented Sep 3, 2014 at 14:26
  • you're right Yanick. I'm just keeping the code simple to make it easier to understand :). On a production server I would use static file serving feature of ExpressJS anyway.
    – ozantunca
    Commented Sep 4, 2014 at 8:39
3

You can use jade + express:

app.get('/', function (req, res) { res.render('index', { title : 'Home' } ) });

above you see 'index' and an object {title : 'Home'}, 'index' is your html and the object is your data that will be rendered in your html.

2

Using jsdom.

  1. npm install jsdom
  2. code
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const dom = new JSDOM();

let heading = dom.window.document.createElement("h3");
let headingText = dom.window.document.createTextNode("Hello World");
heading.appendChild(headingText);
dom.window.document.body.appendChild(heading);

console.log(dom.window.document.body.innerHTML);
0

Not the answer you're looking for? Browse other questions tagged or ask your own question.