JSdom append to body and render as an ejs view - node.js

I wanted to consult on what will be the best approach to achieve the following:
I'm requesting a webpage via the request module, then I throw the body to the
jsdom.env()
function.
What I want in the end is to add a few div, script, and link elements to the document,
and in the end render it to the user. (basically a proxy with modifying the requested remote server html)
What I initially did was to make an ejs that looks as follow (testenv.ejs):
<!DOCTYPE html>
<html>
<head>
<%- head %>
<link rel='stylesheet' href='/stylesheets/style.css' />
<link rel='stylesheet' href='https://code.jquery.com/ui/1.11.3/themes/smoothness/jquery-ui.css' />
</head>
<body>
<%- body %>
<div id="context-menu-container">
<div id="context-menu-header"></div>
<div id="context-menu-options"></div>
<div id="context-menu-steps"></div>
</div>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.3/jquery-ui.min.js"></script>
<script src="/javascripts/test.js"></script>
</body>
</html>
I render this view from my route as follows (proxy.js):
var express = require('express');
var router = express.Router();
var jsdom = require('jsdom');
var request = require('request');
var jar = request.jar();
/* GET users listing. */
router.get('/', function(req, res, next) {
var url = req.param('url');
if (url) {
request({
url: url,
jar: jar
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
jsdom.env({
html: body,
scripts: [
'https://code.jquery.com/jquery-2.1.4.min.js'
],
done: function (err, window) {
var $ = window.jQuery;
res.render('testenv.ejs', { head: $('head').html(), body: $('body').html() })
}
});
}
});
}
else {
res.send("No url param specified...");
}
});
module.exports = router;
The problem I have with this approach is that /stylesheets/style.css and /javascripts/test/js are not downloaded to the client, they're being requested from the remote server and not from the node server.
I tried to fiddle with the order of the javascript and css files I include with in my view and noticed that If I put the css files above the <%- head> part they're begin loaded correctly.
As to the javascript files I had to move them to the head as well (something I do not with to do for obvious reasons like delaying the rendering of the page) but as to the javascript files I encountered another problem.
After moving them to the head the /javascripts/test/js was being loaded correctly because it was requested from the node server and not from the remote server anymore but the problem is that it depends on the jquery-ui,
which for some reason was being loaded but a function of the library was not recognized as if I loaded the /javascripts/test/js only after the jquery-ui library.
Beside the problems I described, I've thought about a scenario where I request a webpage that has the same css/js file name with the ones I try to load or maybe same framework used (bootstrap/jquery but with different revision) which could lead to conflicts.
It's possible to change the name of the css/js files I load to something unique, but I don't want to leave it to the hands of luck because maybe some other website will have the same file names by chance.
That lead me to think that my approach isn't bulletproof and not the best, so I want to ask what you guys think I should do to achieve my goal.
EDIT
I pretty much got to a dead end here.
I've been searching for the last week now for what may cause my issue but couldn't find anything useful.
I also noticed while debugging when supplying the url query parameter with www.google.com, I get to the middleware that handles 404 not found routes in my express app although it succeeded in rendering the page partly.
This is how the rendered page ended up looking like:
google rendering
This is how my app.js is set like - webstorm default (app.js):
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var fxp = require('./routes/fxp')
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
app.use('/proxy', proxy); // proxy is the the js file above that exports the route that handles the requests to the path /proxy/...
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;

Related

Uppy document not defined node.js

I'm trying to implement uppy the file upload program into my website, but when i try to include it, I get an error message saying that document is not defined. This is already me using browserify to include it on my client side. However, I'm not sure what I'm doing wrong. Any help will be appreciate it. My code is below. FYI, I used IntelliJ Idea by Jet Brains as my IDE, and I had the IDE generate my node js project, so it automatically created me some pages with routing included.
app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
require('./uppy');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
index.js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
uppy.js(this is where I placed the uppy code from the documentation)
// Import the plugins
const Uppy = require('#uppy/core');
const XHRUpload = require('#uppy/xhr-upload');
const Dashboard = require('#uppy/dashboard');
const uppy = Uppy()
.use(Dashboard, {
target: '#drag-drop-area',
inline: true
})
.use(XHRUpload, { endpoint: 'https://api2.transloadit.com' });
uppy.on('complete', (result) => {
console.log('Upload complete! We’ve uploaded these files:', result.successful)
});
index.ejs
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href="../node_modules/#uppy/core/dist/style.css" />
<link rel='stylesheet' href="../node_modules/#uppy/dashboard/dist/style.css" />
</head>
<body>
<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
<div id="drag-drop-area"></div>
<script src="../bundle.js"></script>
</body>
</html>
As you can see, I used bundle.js to incorporate the code from uppy.js by using browserify. I used the cli browserify uppy.js -o bundle.js. I honestly don't know what I'm doing wrong, so if you can help me with this, I really appreciate it. Thank you!
UPDATE: On my console I am also getting the errors:
http://localhost:3000/node_modules/#uppy/core/dist/style.css (net::ERR_ABORTED 404 (Not Found))
http://localhost:3000/node_modules/#uppy/dashboard/dist/style.css (net::ERR_ABORTED 404 (Not Found))
http://localhost:3000/bundle.js (net::ERR_ABORTED 404 (Not Found))
I am 100% just guessing here because I can't see the full code/repo and full stacktrace of the error but it sounds like you're referencing document in Node.js code and that's what is throwing this error. document is something that lives in the browser DOM and can only be referenced by UI code. It's important to understand the difference between your Node/Express code which is the backend server and your presentation/UI code which is what gets rendered in the browser.

How to use a .js file outside of the public folder in Node Express App?

I am new to node express and would like some help to get below resolved.
Below is my project structure for Node express Application
Folder structure:
Below is my app.js code
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
I have a controller.js file which currently resides in the public folder (see folder structure)
I have an index.hbs file which uses the controller.js (code shown below)
<!DOCTYPE html>
<html ng-app="test">
<head>
<title>{{title}}</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-route.min.js"></script>
<script src="controller.js"></script>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body ng-app="test">
{{{body}}}
<!--
<div ng-view></div>
-->
</body>
</html>
When I run the application this works fine.
I need to remove the controller.js file from public folder and dump it in the controller folder (see folder structure image) and then when I run the program I get the below error,
GET http://localhost:3000/controller.js 404 (Not Found)
I have changed my <script src="controller.js"></script> in index.hbs file so many ways so that I can run it without any errors but without luck.
Any suggestions would be much appreciated.
You have to serve everything that you want to reference in HTML.
So you can move your code to some other directory and serve it as well, you can move it to another server, but you cannot move it to any place that is not served at all or otherwise you will not be able to load it in HTML.
All client-side JavaScript code must be available for the client to download or it won't work. So it is not only OK to have it in a public directory - it is necessary. Of course you may want to serve it only to some of the clients but you have to serve it to anyone who gets the HTML that uses it and there is pretty much no way around it.

ExpressJs View helpers do not work

It's probably a newbie question. I'm trying to setup my very first expressjs application and I need to use a view helpers that doesn't work for some reason.
Here is my server.js
var express = require('express');
var app = express();
var test = function(req, res, next) {
res.myLog = function(){
console.log("res");
return "Hello";
}
next();
}
app.use(test);
app.get("*", function(req, res) {
res.sendfile('./dist/index.html');
})
app.listen(5000);
And index.html
<html>
<head>
<title>Test application</title>
<link rel="stylesheet" href="main.css" />
<script src='<%=myLog()%>'></script>
</head>
<body>
<h1>Yo World!</h1>
</body>
</html>
myLog function is not call during rendering. Originally I was trying to use some third part helpers and they didn't work as well.
I haven't found any documentation of how to use the helpers on expressjs site. I'm clearly doing something wrong here.
Express version 4.3.14
To send file using express, correct ways is:
//sending html files
var express = require('express');
var app = express();
var path = require('path');
// viewed at http://localhost:5000
app.get('/', showClientRequest, function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
function showClientRequest(req, res, next) {
var request = {
REQUEST : {
HEADERS: req.headers,
BODY : req.body
}
}
console.log(request)
return next();
}
app.listen(5000);
Use ejs template engine:
var express = require('express');
var ejs = require('ejs');
var app = express();
app.set('view engine', 'ejs');
var path = require('path');
// viewed at http://localhost:5000
app.get('/', showClientRequest, function(req, res) {
res.render('index',{message:"Hello World!"});
});
function showClientRequest(req, res, next) {
console.log('Something Here...');
return next();
}
app.listen(5000);
Node-Cheat Available:
For complete code, get working node-cheat at express_server run node app followed by npm install express ejs.
Use res.locals.myLog instead of res.myLog to set locals. If you don't need req within your helper function you can also use app.locals.myLog.
res.sendfile will not render your view but just send a file as it is. You will have to use res.render and move your dist/index.html to views/index.ejs.

Keep getting undefined body when submitting POST request on a form

As the title says, I've been working at this for about 3 hours trying to figure out why the POST body for this is always undefined - no matter what I do. Could anyone look at my JADE/JS and help me figure out my issue?
JADE
doctype html
html(lang="en" ng-app)
head
meta(charset="utf-8")
meta(http-equiv="X-UA-Compatible", content="IE=edge")
meta(name="viewport", content="width=device-width, initial-scale=1")
// The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags
meta(name="description", content="")
meta(name="author", content="")
link(rel="icon", href="favicon.ico")
title Signin Template for Bootstrap
// Bootstrap core CSS
link(href="css/bootstrap.min.css", rel="stylesheet")
// Custom styles for this template
link(href="css/signin.css", rel="stylesheet")
// Just for debugging purposes. Don't actually copy these 2 lines!
//if lt IE 9
script(src="assets/js/ie8-responsive-file-warning.js")
// <script src="assets/js/ie-emulation-modes-warning.js"></script>
// HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries
//if lt IE 9
script(src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js")
script(src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js")
body
.container
form.form-signin(method="post", action="/")
h2.form-signin-heading(style="text-align:center;") Please sign in
label.sr-only(for="inputEmail") Student ID
input#inputID.form-control(type="text", name="userID", placeholder="User ID", required="", autofocus="")
label.sr-only(for="inputPassword") PIN:
input#inputPIN.form-control(type="password", name="userPIN", placeholder="Password", required="")
button.btn.btn-lg.btn-primary.btn-block(type="submit") Sign in
// /container
// IE10 viewport hack for Surface/desktop Windows 8 bug
script(src="assets/js/ie10-viewport-bug-workaround.js")
//AngularJS CDN
script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js")
server.js
//Add necessary dependencies (Express and MongoJS)
var express = require('express');
var app = express();
var mongojs = require('mongojs');
var db = mongojs('advisingApp',['advisingApp']); //sets the database for the project
//Test to make sure server is properly configured
/*app.get('/', function (request, response) {
response.send("Hello world from server.js!");
});*/
//Tell web app where to look for "static" files in directory - (it's looking in the default parent directory)
app.use(express.static(__dirname));
// app.get("/", function (request, response) {
// console.log("GET Request Received")
// db.advisingApp.find(function (err, docs) {
// console.log(docs);
// response.json(docs);
// });
// });
app.post("/", function (req, res) {
console.log("POST Request Received");
console.log(req.body);
});
app.listen(3000);
console.log("Server running smoothly on port 3000");
try this
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
//var mongoose=require('mongoose');
//mongoose.connect('mongodb://localhost/test');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.get("/",function(req,res){
res.render('view'); //i named ur given jade as view.jade
})
app.post("/", function (req, res) {
console.log("POST Request Received");
console.log(req.body);
});
// app.use('/', routes);
// app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
//
app.listen('3000',console.log('listening'));
// module.exports = app;

NodeJs application not executing code of clientside Js Files

I have just created a nodejs application(that uses expressjs and jade). I tried to implement jQuery but noticed it wasn't working. I then tried a simple test creating a javascript file with a simple function and call it from my view. For some reason I get a ReferenceError exception.
The browser does not complain that the Js file is missing, however it doesn't appear in the source list.
This is the code from the simple javascript file(The alert also doesn't work)
//index.js
alert('foo');
function foo(){
alert('javascript!!');
};
Here is the code of the app.js file:
var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
// Database setup
var mongo = require('mongodb');
var monk = require('monk');
var db = monk('localhost:27017/myApplication');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// Make our db accessible to our router
app.use(function(req,res,next){
req.db = db;
next();
});
app.use('/', routes);
app.use('/users', users);
/// catch 404 and forwarding to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
and this the code of my view
doctype html
html
head
title My Application
link(rel='stylesheet', href='/stylesheets/style.css')
link(rel='stylesheet', href='/stylesheets/style-desktop.css')
link(rel='stylesheet', href='/stylesheets/jquery-ui-1.10.4.min.css')
link(rel='stylesheet', href='/stylesheets/style-desktop.css')
link(rel='stylesheet', href='//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css')
//script(type='text/javascript' href='/javascripts/jquery-1.10.2.js')
//script(type='text/javascript' href='/javascripts/jquery-ui-1.10.4.min.js')
script(type='text/javascript' href='/javascripts/index.js')
script(type='text/javascript').
foo();
/*
$(function() {
console.log('test');
alert('foo');
});
*/
body.homepage
div#tabs
ul
li
a(href="#tabs-1") Nunc tincidunt
li
a(href="#tabs-1") Nunc tincidunt
li
a(href="#tabs-1") Nunc tincidunt
div#tabs-1
p LOL
div#tabs-2
p LOL2
div#tabs-3
p LOL3
This is a screenshot of the sources and console in chrome. Please note that if I click on the url of the javascript file in the elements tab It directs me to the file. So the path appears to be correct.
This is a screenshot of my file structure
As jedigo said in the comments, the issue was that I used "href" instead of "src" to refer to my javascript files which caused the issue.
Silly mistake from my part

Resources