Issue with serving images from express.js - javascript

I have issues with serving .png image from my express app. I think there is something wrong with the router setup, because it tries to render page rather than serve a static file. The setup is as follows:
// app.js
// Module dependencies
var express = require('express'),
http = require('http'),
path = require('path'),
session = require('./middlewares/session');
// Create server
var app = module.exports = app ? app : express();
app.set('port', process.env.PORT || 3000);
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');
app.set('view options', { layout: true });
app.use(express.static(path.join(__dirname, '../../public')));
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.errorHandler());
app.use(express.responseTime());
app.use(express.cookieParser());
app.use(app.router);
var routes = require('./routes')(app);
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
// Start server
http.createServer(app).listen(app.get('port'), function() {
console.log('Express server listening on port ' + app.get('port'));
console.log(__dirname);
});
Then my routes file looks like this:
// routes.js
module.exports = function(app) {
//Routes
// app.get('/', routes.index);
app.get('/api/places', places);
app.get('/add-review', review);
app.get('/logout', logout);
app.get('/:location?/:category?', session(app), routes.index);
}
The jade view where I'm trying to load an image
# view
img(src="/nodeapp/img/logo-white.png")
I'm using reverse proxy for node app which root is this http://app.com/nodeapp
The folder structure:
public
components
css
img
js
server
srs
views
app.js
test
The error that I'm getting is this:
TypeError: Cannot read property 'logo-white.png' of undefined
at Object.get_listings (/app/server/src/models/vendors.js:354:16)
at exports.index (/app/server/src/handlers/index.js:6:31)
at callbacks (/app/node_modules/express/lib/router/index.js:161:37)
at /app/server/src/middlewares/session.js:13:5
at /app/bbe/server/src/api.js:18:3
at _fulfilled (/app/node_modules/requestify/node_modules/q/q.js:798:54)
at self.promiseDispatch.done (/app/requestify/node_modules/q/q.js:827:30)
at Promise.promise.promiseDispatch (/app/node_modules/requestify/node_modules/q/q.js:760:13)
at /app/node_modules/requestify/node_modules/q/q.js:574:44
at flush (/app/node_modules/requestify/node_modules/q/q.js:108:17)
GET /img/logo-white.png 500 857ms
So, here it's trying to actually render my jade views rather than serving from a static folder. Other static files such as js and css are served fine. Why is this happening?
Thanks!
=== Edit (added function that renders views) ===
exports.index = function(req, res) {
res.locals.location = data().get_location(req.params);
res.locals.categories = data().get_categories(res.locals.location);
res.locals.listings = data().get_listings(res.locals.location, req.params.category);
var meta = {
title: "My app",
module: "/nodeapp/js/core/index/main.js"
};
res.render('nodeapp/index', meta);
};

I had trouble myself with setting the 'views' path, so maybe the issue is the same.
I would try to set different view paths for the different sites I had like so (per app)
// site1.js
app.set('views', __dirname + '/views/site1');
// site2.js
app.set('views', __dirname + '/views/site2');
For some reason, it just wouldn't find the views to render. So, I had to set them all back to just '/views' directory, and when I rendered them, I included the extra directory there, and that worked.
I'm thinking if you restructured your directories so this
app.use(express.static(path.join(__dirname, '../../public')));
becomes
app.use(express.static(path.join(__dirname, '/public')));
that it might start working for you. I'm assuming all the other things in your public directories aren't being handled right either. If it's just that png file...check the name, rename it, fiddle with it.

Related

Serving css with express js

I have been having a lot of trouble with serving css using express js. I finally figured out how, but I'm a bit confused why my new code works, but my old code doesn't. This is my new code that does work:
const express = require('express');
const path = require('path');
const app = express();
const port = process.env.PORT || 5010;
console.log(__dirname)
app.use('/public', express.static('public'));
app.set('views', path.join(__dirname, 'views'))
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'views', 'home.html'));
});
app.listen(port, () => {
console.log(`Server started on port ${port}`);
});
My file system looks like this:
index.js
public
css
home.css
views
home.html
Originally instead of having:
app.use('/public', express.static('public'));
I had:
app.use(express.static(path.join(__dirname, 'public')));
Why does the second version work, but the first one doesn't? What is the purpose of the first parameter in the second version? Also, just in case it makes a difference, I'm coding on replit.com.
When using 1 parameter
app.use(express.static(path.join(__dirname, 'public')));
This code serve files in the "public" subdirectory of the current directory. The URL to access the file at public/css/home.css is : http://localhost/css/home.css
When using 2 parameters
app.use('/public', express.static('public'));
This code also serve files in the "public" subdirectory of the current directory, with a virtual path prefix "/public". So, the URL to access the file at public/css/home.css is : http://localhost/public/css/home.css
We can change the first parameter to anything, for example, if we have :
app.use('/static', express.static('public'));
Then the URL to the same file becomes : http://localhost/static/css/home.css.
You can find more information from the official document here

How can I use Handlebars with Express?

The question is actually not difficult to understand, I do not know how to implement handlebars in Express.
That's what I've already coded:
var express = require('express');
var app = express();
app.get('/', function (req, res, next) {
return res.render('index');
});
Now is my question, how to set handlebars as app engine for express?
Here is the code as I currently use and learned. I have added a note behind every important line so that you understand it well!
var express = require('express');
var app = express();
var handlebars = require('express-handlebars');
app.engine('handlebars', handlebars({ // Here we define what format you will use (That means what's at the end of each file, for example test.handlebars or test.hbs)
defaultLayout: 'main', // That's the name of your template file. In my case it's main.handlebars
layoutsDir: __dirname + '/views/layouts/' // That's the directory where the template file is
}));
app.set('views', path.join(__dirname, 'views')); // Here you give express the information that it has to look at all files that are in the path /views
app.set('view engine', 'handlebars'); // Here you say express that you are using handlebars to build your website
app.get('/home', function (req, res, next) { // That's a simple GET request (This GET request gets triggered when you enter http://localhost/home for example)
return res.render('index'); // Here we render the index.handlebars file (that is in the /views folder)
});

ExpressJS app.use

I'm trying to learn ExpressJS and I came across this piece of code. I just can't seem to understand the app.use function and the documentation is unclear to me. What exactly is happening to the /public directory in this particular example code when app.use is called?
// Require dependencies
var express = require('express');
var app = express();
// Set server port
app.set('port', (process.env.PORT || 3000));
// Set static page directory, /public
app.use(express.static(__dirname + '/public'));
app.use('/public', express.static('public'));
// Set template file directory, /views. Set view engine to EJS
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
// Route root request to pages/index
app.get('/', function(request, response) {
response.render('pages/index');
});
// Route favicon request to public/favicons
app.get('/favicon.ico', function(request, response) {
response.render('./public/favicons');
});
// Begin listening at specified port
app.listen(app.get('port'), function() {
console.log('Node app is running on port', app.get('port'));
});
It's simple - you are setting up the public directory to be accessible over HTTP.
So, something like http://localhost:3000/public/abc.jpg will give you the abc.jpg from the public folder.
The
app.use('/public', express.static('public'))
line simply means - match any path that starts with /public like:
http://localhost/public/*.jpg
or any other extension - will choose that file from your public (the argument in express.static('public')) folder and serve it.
The line
app.use(express.static(__dirname + '/public'))
means - match any path and if file found in public directory, serve it over HTTP.
You can just use of the these two lines - difference being the /public part in the URL.
The docs are quite clear about this: https://expressjs.com/en/starter/static-files.html

Unable to load external css file with node/express - 404 error

Hello I have got to configure an express app in an architecture that look like this:
![my architecture][1]
Build
Core/pulse.core/assets/styles/global.css
app.js
Express_app
views/home.jade
controller/routes.js
node_modules
my app.js looks like this:
var express = require('express'),
http = require('http'),
fs = require('fs'),
path = require('path');
var app = express();
html_templates = __dirname + '/Express_app';
app.set('views', html_templates + '/views');
app.set('view engine', 'jade');
app.use("/Core", express.static(__dirname + 'Core/Pulse.Core/Assets/Styles/'));
app.listen(3000, function () {
console.log("express has started on port 3000");
});
require('./Express_app/controller/routes.js')(app);
in my home.jade file, i have:
link(rel="stylesheet", href=levelarbo+"../../Core/Pulse.Core/Assets/Styles/global.css")
My html is loading fine, however, i am getting a 404 for my css file, please help. I have been stuck on this for hours :(
app.use("/Core", express.static(__dirname + 'Core/Pulse.Core/Assets/Styles/'));
Should be (note the location of the /)...
app.use("/Core", express.static(__dirname + '/Core'));
The casing in the URL should match the casing in the file system. If the actual path is Core/pulse.core/assets/styles/global.css, the jade file should read...
link(rel="stylesheet", href=levelarbo+"../../Core/pulse.core/assets/styles/global.css")

Render basic HTML view?

I have a basic Node.js app that I am trying to get off the ground using the Express framework. I have a views folder where I have an index.html file. But I receive the following error when loading the web page:
Error: Cannot find module 'html'
Below is my code.
var express = require('express');
var app = express.createServer();
app.use(express.staticProvider(__dirname + '/public'));
app.get('/', function(req, res) {
res.render('index.html');
});
app.listen(8080, '127.0.0.1')
What am I missing here?
You can have jade include a plain HTML page:
in views/index.jade
include plain.html
in views/plain.html
<!DOCTYPE html>
...
and app.js can still just render jade:
res.render(index)
Many of these answers are out of date.
Using express 3.0.0 and 3.1.0, the following works:
app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);
See the comments below for alternative syntax and caveats for express 3.4+:
app.set('view engine', 'ejs');
Then you can do something like:
app.get('/about', function (req, res)
{
res.render('about.html');
});
This assumes you have your views in the views subfolder, and that you have installed the ejs node module. If not, run the following on a Node console:
npm install ejs --save
From the Express.js Guide: View Rendering
View filenames take the form Express.ENGINE, where ENGINE is the name of the module that will be required. For example the view layout.ejs will tell the view system to require('ejs'), the module being loaded must export the method exports.render(str, options) to comply with Express, however app.register() can be used to map engines to file extensions, so that for example foo.html can be rendered by jade.
So either you create your own simple renderer or you just use jade:
app.register('.html', require('jade'));
More about app.register.
Note that in Express 3, this method is renamed app.engine
You could also read the HTML file and send it:
app.get('/', (req, res) => {
fs.readFile(__dirname + '/public/index.html', 'utf8', (err, text) => {
res.send(text);
});
});
try this. it works for me.
app.configure(function(){
.....
// disable layout
app.set("view options", {layout: false});
// make a custom html template
app.register('.html', {
compile: function(str, options){
return function(locals){
return str;
};
}
});
});
....
app.get('/', function(req, res){
res.render("index.html");
});
app.get('/', function (req, res) {
res.sendfile(__dirname + '/public/index.html');
});
If you're using express#~3.0.0 change the line below from your example:
app.use(express.staticProvider(__dirname + '/public'));
to something like this:
app.set("view options", {layout: false});
app.use(express.static(__dirname + '/public'));
I made it as described on express api page and it works like charm. With that setup you don't have to write additional code so it becomes easy enough to use for your micro production or testing.
Full code listed below:
var express = require('express');
var app = express.createServer();
app.set("view options", {layout: false});
app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res) {
res.render('index.html');
});
app.listen(8080, '127.0.0.1')
I also faced the same issue in express 3.X and node 0.6.16. The above given solution will not work for latest version express 3.x. They removed the app.register method and added app.engine method. If you tried the above solution you may end up with the following error.
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
TypeError: Object function app(req, res){ app.handle(req, res); } has no method 'register'
at Function.<anonymous> (/home/user1/ArunKumar/firstExpress/app.js:37:5)
at Function.configure (/home/user1/ArunKumar/firstExpress/node_modules/express/lib/application.js:399:61)
at Object.<anonymous> (/home/user1/ArunKumar/firstExpress/app.js:22:5)
at Module._compile (module.js:441:26)
at Object..js (module.js:459:10)
at Module.load (module.js:348:31)
at Function._load (module.js:308:12)
at Array.0 (module.js:479:10)
at EventEmitter._tickCallback (node.js:192:40)
To get rid of the error message. Add the following line to your app.configure function
app.engine('html', require('ejs').renderFile);
Note: you have to install ejs template engine
npm install -g ejs
Example:
app.configure(function(){
.....
// disable layout
app.set("view options", {layout: false});
app.engine('html', require('ejs').renderFile);
....
app.get('/', function(req, res){
res.render("index.html");
});
Note: The simplest solution is to use ejs template as view engine. There you can write raw HTML in *.ejs view files.
folder structure:
.
├── index.html
├── node_modules
│   ├──{...}
└── server.js
server.js
var express = require('express');
var app = express();
app.use(express.static('./'));
app.get('/', function(req, res) {
res.render('index.html');
});
app.listen(8882, '127.0.0.1')
index.html
<!DOCTYPE html>
<html>
<body>
<div> hello world </div>
</body>
</html>
output:
hello world
If you don't have to use the views directory, Simply move html files to the public directory below.
and then, add this line into app.configure instead of '/views'.
server.use(express.static(__dirname + '/public'));
If you want to render HTML file you can use sendFile() method without using any template engine
const express = require("express")
const path = require("path")
const app = express()
app.get("/",(req,res)=>{
res.sendFile(**path.join(__dirname, 'htmlfiles\\index.html')**)
})
app.listen(8000,()=>{
console.log("server is running at Port 8000");
})
I have an HTML file inside htmlfile so I used path module to render index.html path is default module in node. if your file is present in root folder just used
res.sendFile(path.join(__dirname, 'htmlfiles\\index.html'))
inside app.get() it will work
For my project I have created this structure:
index.js
css/
reset.css
html/
index.html
This code serves index.html for / requests, and reset.css for /css/reset.css requests. Simple enough, and the best part is that it automatically adds cache headers.
var express = require('express'),
server = express();
server.configure(function () {
server.use('/css', express.static(__dirname + '/css'));
server.use(express.static(__dirname + '/html'));
});
server.listen(1337);
To render Html page in node try the following,
app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);
You need to install ejs module through npm like:
npm install ejs --save
With Express 4.0.0, the only thing you have to do is comment out 2 lines in app.js:
/* app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade'); */ //or whatever the templating engine is.
And then drop your static file into the /public directory. Example: /public/index.html
Express 4.x
res.sendFile(path [, options] [, fn])
Send .html files, no template engine...
//...
// Node modules
const path = require('path')
//...
// Set path to views directory
app.set('views', path.join(__dirname, 'views'))
/**
* App routes
*/
app.get('/', (req, res) => {
res.sendFile('index.html', { root: app.get('views') })
})
//...
.
├── node_modules
│
├── views
│ ├──index.html
└── app.js
I added below 2 line and it work for me
app.set('view engine', 'html');
app.engine('html', require('ejs').renderFile);
Try res.sendFile() function in Express routes.
var express = require("express");
var app = express();
var path = require("path");
app.get('/',function(req,res){
res.sendFile(path.join(__dirname+'/index.html'));
//__dirname : It will resolve to your project folder.
});
app.get('/about',function(req,res){
res.sendFile(path.join(__dirname+'/about.html'));
});
app.get('/sitemap',function(req,res){
res.sendFile(path.join(__dirname+'/sitemap.html'));
});
app.listen(3000);
console.log("Running at Port 3000");
Read here : http://codeforgeek.com/2015/01/render-html-file-expressjs/
I didn't want to depend on ejs for simply delivering an HTML file, so I simply wrote the tiny renderer myself:
const Promise = require( "bluebird" );
const fs = Promise.promisifyAll( require( "fs" ) );
app.set( "view engine", "html" );
app.engine( ".html", ( filename, request, done ) => {
fs.readFileAsync( filename, "utf-8" )
.then( html => done( null, html ) )
.catch( done );
} );
1)
The best way is to set static folder. In your main file (app.js | server.js | ???):
app.use(express.static(path.join(__dirname, 'public')));
public/css/form.html
public/css/style.css
Then you got static file from "public" folder:
http://YOUR_DOMAIN/form.html
http://YOUR_DOMAIN/css/style.css
2)
You can create your file cache.
Use method fs.readFileSync
var cache = {};
cache["index.html"] = fs.readFileSync( __dirname + '/public/form.html');
app.get('/', function(req, res){
res.setHeader('Content-Type', 'text/html');
res.send( cache["index.html"] );
};);
I was trying to set up an angular app with an express RESTful API and landed on this page multiple times though it wasn't helpful. Here's what I found that worked:
app.configure(function() {
app.use(express.static(__dirname + '/public')); // set the static files location
app.use(express.logger('dev')); // log every request to the console
app.use(express.bodyParser()); // pull information from html in POST
app.use(express.methodOverride()); // simulate DELETE and PUT
app.use(express.favicon(__dirname + '/public/img/favicon.ico'));
});
Then in the callback for your api routes look like: res.jsonp(users);
Your client side framework can handle routing. Express is for serving the API.
My home route looks like this:
app.get('/*', function(req, res) {
res.sendfile('./public/index.html'); // load the single view file (angular will handle the page changes on the front-end)
});
res.sendFile(__dirname + '/public/login.html');
Add the following Lines to your code
Replace "jade" with "ejs" & "X.Y.Z"(version) with "*" in package.json file
"dependencies": {
"ejs": "*"
}
Then in your app.js File Add following Code :
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
And Remember Keep All .HTML files in views Folder
Cheers :)
Here is a full file demo of express server!
https://gist.github.com/xgqfrms-GitHub/7697d5975bdffe8d474ac19ef906e906
hope it will help for you!
// simple express server for HTML pages!
// ES6 style
const express = require('express');
const fs = require('fs');
const hostname = '127.0.0.1';
const port = 3000;
const app = express();
let cache = [];// Array is OK!
cache[0] = fs.readFileSync( __dirname + '/index.html');
cache[1] = fs.readFileSync( __dirname + '/views/testview.html');
app.get('/', (req, res) => {
res.setHeader('Content-Type', 'text/html');
res.send( cache[0] );
});
app.get('/test', (req, res) => {
res.setHeader('Content-Type', 'text/html');
res.send( cache[1] );
});
app.listen(port, () => {
console.log(`
Server is running at http://${hostname}:${port}/
Server hostname ${hostname} is listening on port ${port}!
`);
});
It is very sad that it is about 2020 still express hasn't added a way to render an HTML page without using sendFile method of the response object. Using sendFile is not a problem but passing argument to it in the form of path.join(__dirname, 'relative/path/to/file') doesn't feel right. Why should a user join __dirname to the file path? It should be done by default. Why can't the root of the server be by defalut the project directory? Also, installing a templating dependency just to render a static HTML file is again not correct. I don't know the correct way to tackle the issue, but if I had to serve a static HTML, then I would do something like:
const PORT = 8154;
const express = require('express');
const app = express();
app.use(express.static('views'));
app.listen(PORT, () => {
console.log(`Server is listening at port http://localhost:${PORT}`);
});
The above example assumes that the project structure has a views directory and the static HTML files are inside it. For example, let's say, the views directory has two HTML files named index.html and about.html, then to access them, we can visit: localhost:8153/index.html or just localhost:8153/ to load the index.html page and localhost:8153/about.html to load the about.html. We can use a similar approach to serve a react/angular app by storing the artifacts in the views directory or just using the default dist/<project-name> directory and configure it in the server js as follows:
app.use(express.static('dist/<project-name>'));
index.js
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res) {
res.render('index.html');
});
app.listen(3400, () => {
console.log('Server is running at port 3400');
})
Put your index.html file in public folder
<!DOCTYPE html>
<html>
<head>
<title>Render index html file</title>
</head>
<body>
<h1> I am from public/index.html </h1>
</body>
</html>
Now run the following code in your terminal
node index.js
For plain html you don't require any npm package or middleware
just use this:
app.get('/', function(req, res) {
res.sendFile('index.html');
});
I wanted to allow requests to "/" to be handled by an Express route where previously they had been handled by the statics middleware. This would allow me to render the regular version of index.html or a version that loaded concatenated + minified JS and CSS, depending on application settings. Inspired by Andrew Homeyer's answer, I decided to drag my HTML files - unmodified - into a views folder, configure Express like so
app.engine('html', swig.renderFile);
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
And created a route handler like so
app.route('/')
.get(function(req, res){
if(config.useConcatendatedFiles){
return res.render('index-dist');
}
res.render('index');
});
This worked out pretty well.
In server.js, please include
var express = require("express");
var app = express();
var path = require("path");
app.get('/',function(req,res){
res.sendFile(path.join(__dirname+'/index.html'));
//__dirname : It will resolve to your project folder.
});
If you are trying to serve an HTML file which ALREADY has all it's content inside it, then it does not need to be 'rendered', it just needs to be 'served'. Rendering is when you have the server update or inject content before the page is sent to the browser, and it requires additional dependencies like ejs, as the other answers show.
If you simply want to direct the browser to a file based on their request, you should use res.sendFile() like this:
const express = require('express');
const app = express();
var port = process.env.PORT || 3000; //Whichever port you want to run on
app.use(express.static('./folder_with_html')); //This ensures local references to cs and js files work
app.get('/', (req, res) => {
res.sendFile(__dirname + '/folder_with_html/index.html');
});
app.listen(port, () => console.log("lifted app; listening on port " + port));
This way you don't need additional dependencies besides express. If you just want to have the server send your already created html files, the above is a very lightweight way to do so.
I usually use this
app.configure(function() {
app.use(express.static(__dirname + '/web'));
});
Just be careful because that'll share anything in the /web directory.
I hope it helps

Categories

Resources