Showing posts with label web. Show all posts
Showing posts with label web. Show all posts

Thursday, 29 May 2014

Debugging mocha tests

launch node-inspector in the background
$ node-inspector &

run your mocha tests in debug mode
$ mocha --debug-brk /path/to/test.js

point Chrome to node-inspector
http://localhost:8080/debug?port=5858

Wednesday, 28 May 2014

MongoDb quick reference

In the mongo shell

# show all databases
show dbs

# switch to a database
use <database>

# drop database
db.dropDatabase();


Tuesday, 13 May 2014

angular-fullstack yeoman generator - use less version of bootstrap

I use the angular-fullstack yeoman generator, but it installs the compiled bootstrap css and I want to use the less version.

Here is how I hack the yeomen generated source to change it to use the less version of bootstrap:

# install less and less grunt task:
sudo npm install -g less
npm install --save-dev grunt-contrib-less

# create app/styles/main.less file:
@import "../bower_components/bootstrap/less/bootstrap.less";
@import "inputs.less";
@import "../bower_components/bootstrap/less/utilities.less";

# rename the old app/styles/main.css to app/styles/inputs.less:
mv app/styles/main.css app/styles/inputs.less

# create less grunt tasks in Gruntfile.js:
    // build our css
    less: {
      dev: {
        files: {
          "<%= yeoman.app %>/styles/main.css": "<%= yeoman.app %>/styles/main.less"
        }
      },
      dist: {
        options: {
          cleancss: true
        },
        files: {
          "<%= yeoman.dist %>/styles/main.css": "<%= yeoman.app %>/styles/main.less"
        }
      }
    },

# add 'less' file extension to files in the styles section of the watch grunt task:
files: ['<%= yeoman.app %>/styles/{,*/}*.{css,less}'],

# add 'less:dev' to tasks in the styles section of the watch grunt task:
tasks: ['less:dev', 'newer:copy:styles', 'autoprefixer']

# also, add 'less:dev' to the debug and serve grunt tasks, and 'less:dist' to the build grunt task

# add exclude entry to the bower-install grunt task to prevent it from being injected into index.html:
exclude: [ 'bower_components/bootstrap/dist/css/bootstrap.css' ]

# add generated css to .gitignore:
echo app/styles/main.css >> .gitignore

Monday, 31 March 2014

MEAN stack build system

MEAN stack build system

The MEAN stack is [M]ongo, [E]xpress, [A]ngular, [N]ode.
Back end:
The server is built using Express, which is built on top of Node.
The database used by the server is MongoDB.
Front end:
The client is built using Angular.
The less version of Bootstrap is used for CSS.
I use Yeoman and the angular-fullstack generator to generate my MEAN stack scaffold.
yo angular-fullstack [app]
Development tools:
npm is used for the server dependencies; these are listed in package.json
Bower is used for the client dependencies; these are listed in bower.json
Grunt is used for the build system. The configuration is stored in Gruntfile.js
The file system structure is as follows:
site/
  app/            # client source code 
  lib/            # server source code
  test/           # tests
  public/         # client production build destination
  Gruntfile.js    # Grunt configuration
  package.json    # server dependencies
  bower.json      # client dependencies
  server.js       # Express server entry-point
Grunt plugins:
grunt-bower-install:
When new dependencies are added with bower, grunt-bower-install will automatically inject their css and js into index.html.
In the grunt.initConfig block of Gruntfile.js:
'bower-install': {
    app: {
        html: '<%= yeoman.app %>/index.html',
        ignorePath: '<%= yeoman.app %>/'
    }
},
grunt-file-blocks:
When new front end components added in the source tree, grunt-file-blocks will automatically inject the javascript into index.html and the less into main.less.
In the grunt.initConfig block of Gruntfile.js:
fileblocks: {
    options: {
        removeFiles: true,
        templates: {
            less: '@import \'${file}\';'
        }
    },
    js: {
        src: 'app/index.html',
        blocks: {
            components: { cwd: 'app', src: 'components/**/*.js' }
        }
    },
    less: {
        src: 'app/css/main.less',
        blocks: {
            components: { cwd: 'app', src: 'components/**/*.less' }
        }
    }
},
Development workflow:
File are monitored for changes and the front or back end are reloaded as required.
nodemon and LiveReload are run concurrently:
In the grunt.initConfig block of Gruntfile.js:
concurrent: {
    dev: {
        tasks: ['nodemon', 'watch'],
        options: {
            logConcurrentOutput: true
        }
    }
},
Back end changes are monitored by nodemon. If a file required by the server is changed, node will be relaunched, restarting the server.
In the grunt.initConfig block of Gruntfile.js:
nodemon: {
    dev: {
        options: {
            file: 'server.js',
            ignoredFiles: ['app', 'test', 'node_modules'],
            watchedExtensions: ['js']
        }
    }
},
Front end changes are monitored by LiveReload. If a file required by the client is changed, assets will be rebuild (eg less converted to css) and the browser will be refreshed
In the grunt.initConfig block of Gruntfile.js:
watch: {
    app: {
        options: { livereload: true },
        files: [
            'app/index.*',
            'app/css/*',
            'app/components/**/*.js',
            'app/images/*'
        ]
    },
    less: {
        tasks: ['less'],
        files: ['app/css/main.less', 'app/components/**/*.less']
    }
},
less: {
    build: {
        files: { 'app/css/main.css': 'app/css/main.less' }
    }
}
This article is inspired by Shawn Dahlen’s post on the build system 4dashes uses.

Tuesday, 28 January 2014

Angular configuration - default http headers

Help prevent CSRF attacks by setting the X-Requested-By / X-Posted-By header

angular.module('myApp')
    .config(function($httpProvider) {
        $httpProvider.defaults.headers.common['X-Requested-By'] = 'myApp';
    });

angular.module('myApp')
    .config(function($httpProvider) {
        $httpProvider.defaults.headers.post['X-Posted-By'] = 'myApp';
    });

angular.module('myApp')
    .config(function($httpProvider) {
        $httpProvider.defaults.headers.put['X-Posted-By'] = 'myApp';
    });

Change the default headers at runtime:

$http.defaults.common['X-Auth'] = "foobar";

Security.StackExchange discussion

Monday, 27 January 2014

Angular directives - require

If we want to expose an API to other directives, we should require a controller on the directive.

We can bind a controller to the directive with require. Multiple controllers can be required by using an array of strings.

app.directive('foo', function() {
  return {
    require: 'bar',
  }
});

Link function

When a controller is required, it will be passed as the 4th argument to the link function:

app.directive('foo', function() {
  return {
    require: 'bar',
    link: function (scope, element, attrs, bar) {
    }
  }
});

When multiple controllers are required, they will be passed as an array to the link function:

app.directive('foo', function() {
  return {
    require: ['bar, baz'],
    link: function (scope, element, attrs, controllers) {
      var bar = controllers[0];
      var baz = controllers[1];
    }
  }
});

Controller location

We can control where the controller can be found by prefixing the controller name as follows:

no prefix

The required controller must be specified on the directive itself. An exception is thrown if no controller is found.

?

Make the controller optional - if it is not found in the directive provided, null is passed as the 4th argument to
the link function.

ˆ

Walk up the parent chain until the controller is found



Combine the previous two options - walk up the parent chain until the controller is found, and pass null if none is found


Wednesday, 22 January 2014

Angular directives - isolate scope

If you don't want a directive to use its parent's scope, create isolate scope:

app.directive("widget", function() {
    return {
        scope : {},    // creates isolate scope
        ...
}

When using isolate scope, obtain access to the parent scope by binding some members:

app.directive("widget", function() {
    return {
        scope : {
            foo: '@' // binds to parent's $scope.foo
        },
        ...
}

3 bindings to parent scope exist:

    '@': 1-way, by value, as a string (updates in the directive are not propagated to the parent scope)
    '=': 2-way, by reference (updates in the directive will update the parent scope)
    '&': expression (the expression is executed in the context of the parent scope)

1-way binding:

app.directive("widget", function() {
    return {
        restrict: 'E', // can only be used as an element
        scope: {
            foo: '@'   // imports $scope.foo by value
        },
        link: function(scope, element, attrs) {
            // do something with attrs.foo
        }


<widget foo="blah"></widget>

In the directive's link function, attrs.foo === "blah".

Model expressions can be parsed too:

<widget foo="{{ model }}"></widget>

In the directive's link function, attrs.foo is a string containing the value in $scope.model.

2-way binding:

app.directive("widget", function() {
    return {
        restrict: 'E', // can only be used as an element
        scope: {
            foo: '='   // imports $scope.foo by reference
        },
        link: function(scope, element, attrs) {
            // do something with attrs.foo
        }


<widget foo="bar"></widget>

In the directive's link function, attrs.foo === $scope.bar. Updating attrs.foo will result in $scope.bar being updated too.

expression binding:

app.directive("widget", function() {
    return {
        restrict: 'E', // can only be used as an element
        scope: {
            foo: '&'   // foo() executed as expression on $scope
        },
        link: function(scope, element, attrs) {
            // attrs.foo() will execute the expression
        }


<widget foo="bar()"></widget>

In the directive's link function, attrs.foo() will execute $scope.bar()

pass parameters to expression:

Special syntax is required to pass parameters to the expression.

In the directive, foo({p1: val}) will pass val to expression foo, which is function bar(p1) on $scope

Sunday, 8 December 2013

Debugging node servers with node-inspector

Install node inspector

$ npm install -g node-inspector

Run node in debug mode

$ node --debug your/node/program.js

Send USR1 signal to node

$ pkill -USR1 node

Launch node-inspector in background mode

$ node-inspector &

Open up the debugger in your browser by navigating to http://localhost:8080/debug?port=5858

If you have something like livereload restarting your node server when you change a source file, then re-launching node-inspector can be done with something like this:

$ PID=`ps -ef | grep node-inspector | grep -v grep | awk '{print $2}'`; if [[ $PID -ne '' ]]; then echo "Killing node-inspector (pid $PID)"; kill $PID; wait $PID; fi; echo "Sending USR1 signal to node"; pkill -USR1 node; echo "Launching node-inspector"; node-inspector&

Node inspector GitHub page: https://github.com/node-inspector/node-inspector

Monday, 21 October 2013

Create angular app and express server / mongodb with yeoman

install (or update) yeoman
npm install -g yo 
npm update -g yo

install (or update) yeoman angular fullstack generator (angular frontend / express server)
npm install -g generator-angular-fullstack
npm update -g generator-angular-fullstack

create angular app
yo angular-fullstack [name] // creates ng-app="nameApp", if blank uses curdir
I chose yes to add bootstrap, no for scss authoring, angular-resource (ngResource) and angular-route (ngRoute) and yes for mongoose/mongodb

add angular-bootstrap (angular directives for twitter bootstrap)
bower install angular-bootstrap --save

run karma tests
grunt karma

get rid of the missing file warning by commenting out the following line from the files array:
    'test/mock/**/*.js',

grab phantom.js for headless testing
http://phantomjs.org/download.html

configure karma to run Phantom.js instead of Chrome to
in karma.conf.js change browsers array to PhantomJS

run karma tests again to validate there are no warnings, and we're running through Phantom.js
grunt karma

serve angular app
grunt server


Github page for the angular-fullstack generator here:
https://github.com/DaftMonk/generator-angular-fullstack

Great blog entry with more details here:

Wednesday, 16 October 2013

MongoDb on Fedora 19

Install and start server

yum install mongodb-server
systemctl start mongod
systemctl enable mongod
systemctl status mongod

Install client and verify it can connect to the server

yum install mongodb
mongo

You should now be in the mongo shell - test you can save and retrieve an object

db.test.save( { a: 1 } )
db.test.find()

Should display something like this:

{ "_id" : ObjectId("525f2fb01ec8e4af43c529c0"), "a" : 1 }

Thursday, 3 October 2013

hello world app with node.js and express.js

requires node and express to be installed (see here for instructions)

go to the root directory where your hello world app will be created
$ cd ~/src/web

create an express app called 'helloWorld' (and use the less css tool)
$ express helloWorld -c less

obtain  the required dependencies and install
$ cd helloWorld
$ npm install

run the server
$ npm start # npm calls 'node app'

add nodemon to our devDependencies so the server gets restarted automatically during development
$ vim package.json  

add the following
"devDependencies": {
    "nodemon": "*"
}

change the scripts / start value:    
"start": "nodemon app.js"

download dependency nodemon
$ npm install

start the server via nodemon
$ npm start

Wednesday, 2 October 2013

node.js / express.js / yeoman / angular installation on Fedora 19

download the prebuilt binary:
http://nodejs.org/dist/v0.10.20/node-v0.10.20-linux-x64.tar.gz

download and build from source
cd /tmp
wget 
http://nodejs.org/dist/v0.10.20/node-v0.10.20.tar.gz
tar -xf node-v0.10.20-linux-x64.tar.gz
cd node-v0.10.20-linux-x64/

configure, build and install
export PREFIX=/usr/local # or whatever your prefix is
./configure --prefix=$PREFIX
export LINK=g++ # only required if you're building on NFS
make
make install


clean up temporary files
rm -rf /tmp/node-v0.10.20-linux-x64*

add node to your path
export PATH=$PREFIX/bin:$PATH

display node and npm versions
node --version
v0.10.20
npm --version
1.3.11


install express.js
npm install -g express

display express version
express --version
3.4.0


install yeoman
npm install -g yo

install yeoman angular generator
npm install -g generator-angular

create angular app
yo angular app-name

serve angular app
grunt server