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?
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()
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
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();
});
}
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
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
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>
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"});
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!
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 %>
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.
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);
});
Related
I want to send the <head> containing stylesheets before processing the rest of the page. In PHP, I could use ob_flush().
I tried doing something like this:
app.set('view engine','ejs');
app.get('*',function(req,res){
res.writeHead(200,{'Content-Type':'text/html'});
res.write('<!doctype...<link rel=stylesheet...');
doDBStuff()
.then(function(data){
res.render('index',{...}); // uses EJS for templating
});
});
However, the res.render() part does not get sent. Is there a built-in way to send chunked data?
One way to do it would be to manually load the EJS files and manually process them. I would also have to manually send the appropriate headers. I prefer a build-in method if it exists.
Here's a simple PoC that does what you want:
var express = require('express');
var app = express();
var server = app.listen(3000);
app.set('views', 'views');
app.set('view engine', 'ejs');
app.get('/', function (req, res, next) {
res.write('<!-- prefix -->');
setTimeout(function() {
res.render('index', { ... }, function(err, html) {
// TODO: handle errors
res.end(html);
});
}, 1000);
});
Note that it uses the "callback variant" of res.render(), which can be used to just render a template without sending back a response (if you don't do it this way, res.render() will generate an error). Alternatively, you can use app.render() which does the same.
I have a bunch of html files that I want to serve as static files. However, I need the routes to not have any .html in it.
When the route is
example.com/about
it should serve about.html
The research I did on serving static files seems to suggest that it is not entirely possible. Is that right, or am I missing something?
You need to serve your static file using the router
app.get('/about', function(req, res) {
res.render('about.html');
});
Before that you should setup a middleware for the html rendering engine
Or if you have a lot of static files, you could use a middleware to do it for you
https://www.npmjs.com/package/clean-urls
You can create a short little piece of middleware that will process whichever preset names you configure it for. Anything not in that list will go to your normal routes:
// create static file lookup table for the desired names
var staticFiles = ["about", "index", "home"].reduce(function(obj, item) {
obj["/" + item] = true;
return obj;
}, {});
app.use(function(req, res, next) {
// if the path is found in the lookup table, then
// add ".html" onto the end and get that file from the base directory
// of you could use any source directory for those files
if (staticFiles[req.path]) {
res.sendFile(path.join(__dirname, req.path + ".html"));
return;
}
next();
});
Note: this very carefully only serves specific files so nobody can go snooping around in your file system with other types of URLs.
Here's an example where the files are served from a subdirectory below our base directory named "html":
app.use(function(req, res, next) {
if (staticFiles[req.path]) {
res.sendFile(path.join(__dirname, "html", req.path + ".html"));
return;
}
next();
});
In node v0.12+, you can use the Set object for your list of static routes like this:
var staticFiles = new Set(["/about", "/index", "/home"]);
app.use(function(req, res, next) {
if (staticFiles.has(req.path)) {
res.sendFile(path.join(__dirname, "html", req.path + ".html"));
return;
}
next();
});
If you have a lot of static pages, the ideal way would be to put them up in a single route, lets call it static.js. It can be something like,
module.exports = function () {
var router = require('express').Router();
var pages = {
'about-us': 'path/to/about-us',
'contact-us': 'path/to/contact-us'
};
router.get('/:page', function (req, res, next) {
if (! pages[req.params.page]) {
return next();
}
res.render(pages[req.params.page]);
});
return router;
};
Attach this route to the app, app.use(require('./static')()); and you are good to go.
Try this.
app.use(express.static(path.join(__dirname, 'xyz')));
where xyz is the folder you are trying to make available as static. The folder name is relative to the application root.
I am new to Express and semi-new to nodejs and I am trying to run a simple app / webserver as a proof of concept. I have been stuck for hours because my server serves every file as index.html (with the content of index.html).
In my index.html I am making calls to JS files and CSS files and they are all coming back but with a 200 in the console but they are all coming back with index.html content instead of the actual content contained in them. I believe the problem is in my server.js file which is below:
// server.js
// modules =================================================
var express = require('express');
var app = express();
var mongoose= require('mongoose');
var path = require('path');
// configuration ===========================================
// config files
var db = require('../config/db');
var port = process.env.PORT || 9999; // set our port
//mongoose.connect(db.url); // connect to our mongoDB database (uncomment after you enter in your own credentials in config/db.js)
app.configure(function() {
app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users
app.use(express.logger('dev')); // log every request to the console
app.use(express.bodyParser()); // have the ability to pull information from html in POST
app.use(express.methodOverride()); // have the ability to simulate DELETE and PUT
});
// routes ==================================================
require('../../app/routes')(app); // configure our routes
// start app ===============================================
app.listen(port); // startup our app at http://localhost:9999
console.log('Magic happens on port ' + port); // shoutout to the user
exports = module.exports = app; // expose app
// app/routes.js
module.exports = function(app) {
// server routes ===========================================================
// handle things like api calls
// authentication routes
// sample api route
app.get('/api/nerds', function(req, res) {
// use mongoose to get all nerds in the database
Nerd.find(function(err, nerds) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
res.send(err);
res.json(nerds); // return all nerds in JSON format
});
});
// route to handle creating (app.post)
// route to handle delete (app.delete)
// frontend routes =========================================================
// route to handle all angular requests
app.get('*', function(req, res) {
res.sendfile('/Users/...../app/public/index.html'); // load our public/index.html file
//res.sendfile(path, {'root': '../'});
});
};
I have been following this tutorial verbatum: http://scotch.io/bar-talk/setting-up-a-mean-stack-single-page-application but haven't had much success.
I cannot confirm without looking at your computer but I get the feeling the paths in your application are wrong.
The crucial parts in the express setup are:
app.use(express.static(__dirname + '/public'));
and
app.get('*', function(req, res) {
res.sendfile('/Users/...../app/public/index.html');
The first rule catches and returns any static file in __dirname + '/public'.
The second returns index.html for anything else.
The problem is that your server.js is not in the apps directory (I can see this since you use ../../app/routes.js to get to routes.js) this means __dirname + '/public' is not pointing to the public directory. Which is why your static files are being served by the global rule in routes.js.
In order to fix this change __dirname + '/public' to ../../app/public, or better yet place your server.js file where it should be and update your paths.
I can also see you are using an absolute full path to index.html in routes.js instead of a relative one so it seems as if your applications needs to tidied out.
The tutorial that you are following contains this route
app.get('*', function(req, res) {
res.sendfile('./public/index.html'); // load our public/index.html file
});
which explicitly defines the behaviour you described.
In this tutorial it makes sense because it explains how to build a single page application. This type of the application typically returns the same content for all the request while the actual presentation work happens on the client by the client-side library (angular in this example).
So if you what to serve more pages with different content you need to add more routes for them, just like route for /api/nerds in the example.
Update:
After clarifying that the issue is incorrectly served CSS and JS files, the proposed solution is to check the location of the server.js - it should be in the folder together with the folder "public".
i am really new to Node Js and Express Js and i am following the (book)[http://www.sitepoint.com/store/jump-start-node-js/] to learn Node Js.
In the book the author created a simple page for simple Login Form. I am following that but getting 404 Not found.
Not Found
404
Error: Not Found
at Layer.app.use.res.render.message [as handle] (/Applications/MAMP/htdocs/resto/app.js:29:15)
at trim_prefix (/Applications/MAMP/htdocs/resto/node_modules/express/lib/router/index.js:240:15)
at /Applications/MAMP/htdocs/resto/node_modules/express/lib/router/index.js:208:9
at Function.proto.process_params (/Applications/MAMP/htdocs/resto/node_modules/express/lib/router/index.js:269:12)
at next (/Applications/MAMP/htdocs/resto/node_modules/express/lib/router/index.js:199:19)
at next (/Applications/MAMP/htdocs/resto/node_modules/express/lib/router/index.js:176:38)
at /Applications/MAMP/htdocs/resto/node_modules/express/lib/router/index.js:137:5
at /Applications/MAMP/htdocs/resto/node_modules/express/lib/router/index.js:250:10
at next (/Applications/MAMP/htdocs/resto/node_modules/express/lib/router/index.js:160:14)
at next (/Applications/MAMP/htdocs/resto/node_modules/express/lib/router/index.js:176:38)
I added the following code in App.js
var fs = require('fs');
app.get('/form', function(req, res){
fs.readFile('.views/form.html', function(error, content){
if(error){
res.writeHead(500);
res.end();
}
else{
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(content, 'utf-8');
}
});
});
and then created a file form.html in Views folder in which i created a simple html form.
This didnt work for me, so following the flow of default index.jade, i created a file form.js and added the following code in it
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/form', function(req, res) {
res.render('form');
});
module.exports = router;
Which also did not work. I am sure i am doing something wrong but i do not know where.
Please help, Thanks
Assuming you have those files :
-- app.js
-- routes (folder containing root.js)
-- views (folder containing form.jade)
Then, in your app.js :
var path = require('path');
var express = require('express');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use('/', require('./routes/root')); // Say that all the routes defined in root.js will start with http://yourdomain.com/
And in root.js :
var express = require('express');
var router = express.Router();
/* GET http://yourdomain.com/form */
router.get('/form', function(req, res) {
res.render('form'); // Render form.jade view
});
Of course, this is really minimalist and you'll have much more things to do... but I hope this will help you to better understand node.js using Express
Express Router documentation
I am new to NodeJS and Express too but I think the problem is that you never declare where to find the form.html file. Right before the app.get('/form',....), put app.use(express.static(__dirname+'put the directory your form.html is in or dont put anything if it's not in a directory')); this way express knows where to find the form.html and you shouldn't get a 404 anymore
Express provides a sendFile function in the response object, which allows you to do this:
app.get('/form', function(req, res){
res.sendFile('./views/form.html', {root: __dirname}, function(error, content){
if(error){
res.writeHead(500);
res.end();
}
});
});
The jade renderer isn't used in this case.
I have a basic expressjs app (using jade), but I am having trouble rendering basic Jade files. When I get a request, i parse the url for the pathname and use the handle object to route the request as follows:
index.js
var requestHandlers = require('./requestHandlers');
var handle = {};
handle['/'] = requestHandlers.start;
handle['/download'] = requestHandlers.download
requestHandlers.js
function start(res) {
console.log("request handler for start called");
res.render('home', {title: 'express'});
}
function download(res) {
res.render('download', {title: 'download'})
res.end();
}
exports.start = start;
exports.download = download;
home.jade
h1= title
p Welcome to #{title}
I am using Jade as my templating engine, and have configured the server in a seperate server.js file. When i request either of the pages, the title displays correctly on my browser tab, but the page doesn't display, it just keeps loading. Weirdly, when I cancel the request the page displays. It's as if everything works but nothing tells the process to end?
I am relatively new to node so excuse my naiveté on any of the above. Let me know if there are any questions I can clear up.
I'm not 100% positive why your code isn't killing the TCP connection as needed to prevent your browser from timing out, but I can provide a solution that is friendly towards Express conventions that should solve your issues and maintain code readability, maintainability, and separation.
./app.js (your main server script)
var express = require('express'),
app = express.createServer(),
routes = require('./routes');
app.configure(function () {
// Render .jade files found in the ./views folder
// I believe you are already doing this
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
// Use the built-in Express router
// This kills the "handle" method you had implemented
app.use(app.router);
// Client-side assets will be served from a separate ./public folder
// i.e. http://yourhost.com/js/main.js will link to ./public/js/main.js
app.use(express.static(__dirname + '/public'));
});
// Initialize routes
routes.init(app);
./routes/index.js
exports.init = function (app) {
app.get('/', function (req, res) {
console.log("request handler for start called");
// Render __dirname/views/home.jade
res.render('home', {title: 'express'});
});
app.get('/download', function (req, res) {
// Render __dirname/views/download.jade
res.render('download', {title: 'download'})
});
});
The above prevents you from needing to parse the URL parameters by yourself. Also you can define more readable and powerful request handlers (i.e. app.post for POST methods). You are now enabled to more easily tie in things like the Express-Resource module if you decide to build a REST API.
If you need more powerful mappings you can use regular expressions in the first parameter of app.[get/post/put/del] to filter for specific paths instead.