Attach static files in index.html on node.js openshift setup - node.js

I want to setup a node.js backend to serve an application I am building. I am using openshift and the setup went fine, and I had a my basic index.html showing up fine. However, when I tried to add my css, and js files, I could not.
<link rel="stylesheet" type="text/css" href="css/style.css">
I found this page, and I am having the same issue as described, with no solution yet.
https://www.openshift.com/forums/openshift/problem-linking-css-and-js-in-my-nodejs-app

I got this working by adding this code in my server.js
server.use('/static', express.static(__dirname + '/resources'));
where i saved all my static files inside resources folder.

Solved! I have my CSS and JS folders with appropriate files in them, and the server.js code now looks like this to initialize the server:
/**
* Initialize the server (express) and create the routes and register
* the handlers.
*/
self.initializeServer = function() {
self.createRoutes();
self.app = express.createServer();
self.app.configure(function(){
//self.app.use(express.cookieParser());
//self.app.use.(express.session({secret:"secret",key:"express.sid"}));
['css', 'img', 'js', 'plugin', 'lib'].forEach(function (dir){
self.app.use('/'+dir, express.static(__dirname+'/'+dir));
});
self.app.set('views', __dirname + '/views');
self.app.set('view engine', 'ejs');
});
// Add handlers for the app (from the routes).
for (var r in self.routes) {
self.app.get(r, self.routes[r]);
}
};

Related

Angular not updating html template variables when served via NodeJS server

This is a bit of a specific question, but I'm at a bit of a loss for an answer.
First, a little background. I've been trying to learn angular, and I wanted to start using Node as the backend. I currently have a working tutorial app that I can run locally that just returns data that is hard coded into the main controller.
When I moved the files to my NodeJS server, it stopped working though. Here is what works:
The files load correctly - there are no console errors, and I can view each of the files in the source (index.html, app.js, maincontroller.js)
The scope exists, and the variables are defined. I put a console.log($scope) inside the mainController.js file, and I can see all of the variables defined correctly.
Non-angular javascript works - I can place alerts outside/inside the mainController, and they all work correctly (also, console.log obviously works)
I am serving the files via a simple Node.js server. I am using express and hbs. I was originally using compression, and 0 cache length, but have since removed those with no change in the result.
The specific issue I'm having is that none of the template variables update. I've simplified it down to the following code for testing. When viewed locally, the page says 'I now understand how the scope works!', when served from Cloud 9, the structure exists, but the {{understand}} variable in the template doesn't work.
index.html
<!DOCTYPE html>
<head>
<title>Learning AngularJS</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script src="js/app.js"></script>
<script src="js/maincontroller.js"></script>
</head>
<body>
<div id="content" ng-app="MyTutorialApp" ng-controller="MainController">
{{understand}}
</div>
</body>
app.js
var app = angular.module('MyTutorialApp',[]);
maincontroller.js
app.controller("MainController", function($scope){
$scope.understand = "I now understand how the scope works!";
});
server.js (Node server on Cloud 9)
var express = require('express');
var app = express();
var hbs = require('hbs');
app.set('view engine','html');
app.engine('html',hbs.__express);
app.configure(function() {
app.set('views', __dirname);
});
//app.use(express.compress());
app.use('/js',express.static(__dirname + '/client/js'));
app.use('/css',express.static(__dirname + '/client/css'));
app.use('/img',express.static(__dirname + '/client/img'));
//router
app.get('/',function(req,res){
res.render('client/index.html');
return;
});
//404 responses
app.use(function(req, res, next){
res.status(404);
// respond with html page
if (req.accepts('html')) {
res.render('client/404.html', { url: req.url });
return;
}
// respond with json
if (req.accepts('json')) {
res.send({ error: 'Not found' });
return;
}
// default to plain-text. send()
res.type('txt').send('Not found');
});
app.listen(process.env.PORT);
console.log('listening on port '+process.env.PORT);
everythin became clear when i read
"Handlebars.js is an extension to the Mustache templating language"
what this menas is that hbs uses {{}} as delimiters as well as angular so the {{understand}} in your html never gets to angular because is first parsed and substituted by hbs. if you want to use hbs with angular youll need to change your delimiters using your angulars $interpolateProvider in your app configuration something like
$interpolateProvider.startSymbol('{/{');
$interpolateProvider.endSymbol('}/}');
You can use \{{understand}} as this will counter your hbs and put your angular on top.

How to embed ECTJS views in LocomotiveJS

I have typical installation of locomotive JS. I want to use ECTJS for views. I have successfully installed ECTJS by using following command:
npm install ect --save
I have following controller:
var locomotive = require('locomotive')
, Controller = locomotive.Controller;
var roseController = new Controller();
roseController.thorne = function(){
this.render();
}
module.exports = roseController;
I have created following 'thorne.html.ect' file in directory '/app/views/rose'
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
<link rel="stylesheet" href="/stylesheets/screen.css" />
</head>
<body>
<h1>Rose Controller - Thorne Action from ECT</h1>
<p></p>
</body>
</html>
I have made changes in '02_views.js' file in 'initializers' folder. File is as below:
module.exports = function() {
// Configure view-related settings. Consult the Express API Reference for a
// list of the available [settings](http://expressjs.com/api.html#app-settings).
var ECT = require('ect');
var renderer = ECT({ root : __dirname + '/app/views', ext : '.ect' });
//var renderer = ECT({ watch: true, root: __dirname + '/app/views'});
this.set('view engine', 'ect');
this.engine('ect', renderer.render);
// // this.set('views', __dirname + '/../../app/views');
// // this.set('view engine', 'ejs');
// Register EJS as a template engine.
// //this.engine('ejs', require('ejs').__express);
// Override default template extension. By default, Locomotive finds
// templates using the `name.format.engine` convention, for example
// `index.html.ejs` For some template engines, such as Jade, that find
// layouts using a `layout.engine` notation, this results in mixed conventions
// that can cause confusion. If this occurs, you can map an explicit
// extension to a format.
/* this.format('html', { extension: '.jade' }) */
// Register formats for content negotiation. Using content negotiation,
// different formats can be served as needed by different clients. For
// example, a browser is sent an HTML response, while an API client is sent a
// JSON or XML response.
/* this.format('xml', { engine: 'xmlb' }); */
}
When I run
http://localhost:3000/rose/thorne
I get following error :
500 Error: Failed to lookup view "rose/thorne.html.ect"
If I use:
this.res.send('Test');
in rose/thorne action, it shows without any problem.
Can some one guide me how can I embed ECTJS in locomotiveJS.
Thanks
It seems that you configuration in 02_views.js is broken.
Try the following configuration:
// Creating ECT renderer
var ectRenderer = ECT({
watch: false,
gzip: true,
root: __dirname + '/../../app/views'
});
// Register ECT as a template engine.
this.engine('.ect', ectRenderer.render);
// Configure application settings. Consult the Express API Reference for a
// list of the available [settings](http://expressjs.com/api.html#app-settings).
this.set('views', __dirname + '/../../app/views');
this.set('view engine', 'ect');
// Override default template extension. By default, Locomotive finds
// templates using the `name.format.engine` convention, for example
// `index.html.ect` For some template engines, such as ECT, that find
// layouts using a `layout.engine` notation, this results in mixed conventions
// that can cuase confusion. If this occurs, you can map an explicit
// extension to a format.
this.format('html', {
extension: '.ect'
});
With this configuration my view files are named filename.ect. So if filename.html.ect doesnt work you can rename it to filename.ect

hogan.js with master pages or layouts

Is it possible in any way to use hogan.js as template engine with layouts something like
"Razor or master pages in .NET"?
I would get a result like this:
layout.hjs:
contains "header" & "footer"
and
index.hjs:
will include layout.hjs and contain only page content.
sure:
layout.hjs:
{{> header}}
{{$content}}
default content
{{/content}}
{{> footer}}
index.hjs:
{{<layout}}
{{$content}}
your content goes here
{{/content}}
{{/layout}}
see the hogan test file for all it can do:
https://github.com/twitter/hogan.js/blob/master/test/index.js
btw. this is Hogan#3.0.0, get it with a git url with mpn
I'm not sure what you mean, "Razor or master pages in .NET"? What are you looking to do, use view partials?
But the basic way of setting up Hogan.js for Express is as follows:
var express = require('express');
var app = express();
app.set('views', __dirname + '/views');
app.set('view engine', 'hjs');
app.use(app.router);
app.use(express.static( __dirname + '/public' ));
app.get('/', function( req, res, next ) {
res.render('index');
});
app.listen(3000);
You will have to npm install express [--save], npm install hjs [--save], depending if it's inside your package.json already or not.
Then you just make a views directory and throw an index.hjs file and you're set.
Let me know what you want to do with your templates and we can work from there.

How do I use Node and Express with coffeescript and requirejs?

Here's what I want.
A node application using the express webserver
Using coffeescript on the server and more importantly the client
Using require.js on the client (and eventually on the server)
The recommended way I've been able to find of hooking up coffeescript for the client is to use connect-assets. This seems to require using jade helpers to actually compile coffeescript eg.
!=js('monalisa.js')
seems to compile monalisa.coffee and generate the correct <script> tag. Now I want to use require.js and here I stumble. How do I ensure that connect-assets compiles everything correctly without using the jade helpers?
Here's my fairly simple app.js:
require('coffee-script');
var express = require('express')
, http = require('http')
, path = require('path')
, connectAssets = require('connect-assets');
var publicDir = path.join(__dirname, 'public');
var app = express();
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use( connectAssets() );
app.use('/public', express.static(publicDir));
app.use(express.logger());
app.use(express.methodOverride());
app.use(app.router);
});
app.configure('development', function(){
app.use(express.errorHandler({
dumpExceptions: true,
showStack: true
}));
});
app.get('/', require('./routes').index);
app.get('/monalisa', require('./routes/monalisa').monalisa);
http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});
I've created a package to help solve this problem; it's called connect-assets-jspaths.
From the readme:
Installation
npm install connect-assets-jspaths
Note, there is a dependency on CoffeeScript.
Server Side Usage
assets = require "connect-assets"
jsPaths = require "connect-assets-jspaths"
# Snip ...
app.use assets()
# Exports the global function exportPaths() and jsUrl(); see below in View Helpers.
jsPaths assets
# Optionally, pass a log function to see progress
# jsPaths assets, console.log
Watch changes and re-compile
Now you can pass some additional callbacks in and it will monitor your connect assets directories for changes.
fileChangedCallback = (err, filePath) ->
console.log "File Changed: #{filePath}"
jsPaths assets, console.log, fileChangedCallback, (err, watcher) ->
console.log "Watcher initialized"
NOTE You'll probably want to disable this for production mode.
View Usage
This module exports two global functions exportPaths() and jsUrl().
// Using this in your view
!= exportPaths("jsPaths")
// Turns into this when rendered in production
<script type="text/javascript">
var jsPaths = { "main", "/builtAssets/js/main.13819282742.js" /* snip all the other file paths */ };
</script>
// Using this in your view
- var mainJsPath = jsUrl("/js/main.js")
script(type="text/javascript", data-main="#{mainJsPath}", src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.0.2/require.min.js")
// Turns into this when rendered in production
<script type="text/javascript" data-main="/builtAssets/js/main.13819282742.js" src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.0.2/require.min.js"></script>
Dynamic RequireJS Paths
Now that we have a variable with our requireJS friendly paths in it, we can set those paths in the RequireJS config
# Example main.coffee file in /assets/js folder
requirePaths =
paths:
jquery: "//cdnjs.cloudflare.com/ajax/libs/jquery/1.7.2/jquery.min"
underscore: "//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min"
backbone: "//cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min"
text: "/js/lib/text"
handlebars: "/js/lib/handlebars"
if jsPaths
for own key, value of jsPaths
# Fix up the lib references
key = key.slice 4 if key.slice(0, 4) == "lib/"
requirePaths.paths[key] = value
require.config
paths: requirePaths.paths
shim:
jquery:
exports: "$"
underscore:
exports: "_"
backbone:
deps: ["underscore", "jquery"]
exports: "Backbone"
require ['app'], (App) ->
new App().initialize()
Try mimosa, it'll help you with each one of those things out of the box. http://www.mimosajs.com
mimosa new [name] will give you a starter project with all of it.
Sorry for the new answer, but I decided to go make an account. =)
Mimosa will give you a small Express application if you choose Express as part of the mimosa new workflow. And if you choose CoffeeScript it'll give you an Express app in CoffeeScript. And it'll have RequireJS included in the scaffolded application. So you should not need to rewrite anything. You just need to plug your stuff in. If anything the Express app it gives you will serve as an example for you to do it yourself without using Mimosa.

Can not get CSS file

My directory set up is like this :
app.js
vews
home.html
css
style.css
My home file is like this :
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="css/style.css" />
</head>
<body>
</body>
</html>
My app is like this :
var io = require('socket.io'),
url = require('url'),
sys = require('sys'),
express = require('express'),
http=require('http');
var app = express();
var server = http.createServer(app);
var socket = io.listen(server);
app.engine('.html', require('ejs').__express);
app.set('views', __dirname + '/views');
app.set('view engine', 'html');
app.get('/', function(req, res){
res.render('home');
});
app.listen(4000);
sys.puts('server running ' + 'now ' + Date.now());
The problem is when i run the app, css file can not be loaded.
Since .css files are static files you have to serve them to the clients. However, you do not serve static files as a express middleware. Add the following middleware to your express app and move the css folder under the public directory (you should create a public directory)
app.use(express.static(path.join(__dirname, 'public')));
So your final directory structure should look like this
app.js
views
home.html
public
css
style.css
And do not forget to require path module
var path = require('path')
In one of my apps, I have these relevant files in this file structure:
/
index.js
/public
/stylesheets
main.css
/views
/partials
header.ejs
The index.js includes app.use(express.static(path.join(__dirname, '/public')));
Note the /public.
The header.ejs partial includes <link rel='stylesheet' type='text/css' href='/stylesheets/main.css' />
Note the lack of public, it’s implied by the middleware.
In your example, your current directory for static files doesn’t match where you are keeping static files.
Try this:
<link rel="stylesheet" type="text/css" href="/css/style.css" />
This might solve the problem.

Resources