node load js on createServer
when I load a static html page I want to send a JS Object
to that page (which is data that comes from mongo). I can accomplish this with a Socket
emit
, but that seems like overkill. I also know I can write the whole document using JS, but I want to leverage HTML for the bulk of the page as it makes things easier for people I work with.
It would be nice if I could inject html into my static page before it gets sent out by the server, but I don't think this is possible. I'll settle with an html page that has either a function to parse data sent to the page at "load" time, etc..
My current samples are bogus or I'd send them along. Thanks for looking at my question!
** current sn开发者_开发技巧ippet, for fun **
function createServer(req, res) {
var path = url.parse(req.url).pathname;
var fsCallback = function(error, data, cb) {
if(error) throw error;
res.writeHead(200);
res.write(data);
res.end();
if(cb) cb();
}
switch(path) {
case '/subpage':
case '/subpage.html':
doc = fs.readFile(__dirname + '/subpage.html', function(error, data) {
fsCallback(error, data, function() {
var db = new mongo.Db('mydb', new mongo.Server('localhost', '27017', {}), {});
db.open(function() {
db.collection('mytable', function(error, collection) {
collection.find(function (error, cursor) {
//store some data and send it to the page -- that will happen somewhere around here?
});
});
});
});
});
break;
default:
doc = fs.readFile(__dirname + '/index.html', fsCallback);
break;
}
}
I've had great results with Express and the JADE templating engine.
I find that JADE makes hand-crafted HTML much cleaner and less bulky, even if most of the page is static. And, inserting dynamic data is obviously supported. JADE is simple and elegant with a very straightforward mapping between template syntax and generated HTML. With the indentation driving hierarchy versus more fragile XML tags, and minus the verbosity of all the closing tags, I have found JADE to be quicker to write and significantly more maintainable.
For example
html
body
div.myClass
img(src="images/foo.png")
versus
<html>
<body>
<div class="myClass">
<img src="images/foo.png"/>
</div>
</body>
</html>
if you really want to keep your existing static HTML file, narrowly solving your asked problem is pretty easy. There's absolutely no reason you need to spit out the HTML file before the DB data comes back (unless you deliberately want the data populated async to mask DB latency).
Transforming your existing code sample:
function createServer(req, res) {
var path = url.parse(req.url).pathname;
function emitResponse(error, data) {
if(error) throw error;
res.writeHead(200);
res.end(data);
}
switch(path) {
case '/subpage':
case '/subpage.html':
fs.readFile(__dirname + '/subpage.html', function(error, data) {
var db = new mongo.Db('mydb', new mongo.Server('localhost', '27017', {}), {});
db.open(function() {
db.collection('mytable', function(error, collection) {
collection.find(function (error, cursor) {
data = data.replace('__INJECTED_HTML_CONTENT__', fnWhateverOneDoesWithACursor(cursor));
emitResponse(error, data);
});
});
});
});
break;
default:
doc = fs.readFile(__dirname + '/index.html', emitResponse);
break;
}
}
But it could still be a lot nicer. If we update the code to follow a few best practices:
- Using Express to organize the site
- Using Step to organize async workflows
- Using a template instead of string manipulation
- Proper error handling w/ stack traces sent to client (while running in "development" mode)
Best Practices Code Sample:
server.js
var _ = require('underscore');
var express = require('express');
var Step = require('step');
var mongo = require('mongo');
var app = express.createServer(
// these filters run in order to process the incoming request
// can also add cookie parsing / sessions / request logging / etc
express.logger()
,express.static(__dirname + '/public')
);
var mongoDbServer = new mongo.Server('localhost', '27017', {});
function fetchDbData(cb) {
var db;
Step(
function stepDbConnect() {
db = new mongo.Db('mydb', mongoDbServer, {});
db.open(this); // this is the callback. runs the next "step"
}
,function stepDbGetCollection(err, p_db) {
if(err) throw err; // percolates errors to the next step
db.collection('mytable', this);
}
,function stepDbFind(err, collection) {
if(err) throw err;
collection.find(this);
}
,function stepEnd(err, cursor) {
db.end();
cb(err, cursor);
}
);
}
app.get('/subpage(.html)?', function(req, res, next) {
fetchDbData(function(err, rows) {
if(err) next(err);
else res.render('subpage.ejs', {rows: rows});
});
});
app.listen(3000);
views/subpage.ejs:
<html>
<body>
<%= partial('row.jade', rows); %>
</body>
</html>
views/row.jade:
p Row #{row.name} blah blah blah
Depending on how simple the injection into the HTML page is, you might just want to use a templating library, like {{ mustache }}. (This will definitely enable you to "inject html into my static page before it gets sent out by the server").
Templating libraries you to do the bulk of the work in HTML, but pass dynamically pass objects to the pages you are serving up.
精彩评论