FOR MODERN WEBAPPS
Scaffold new projects using templates
Build process.
Compile CoffeeScript & Sass.
Refresh the browser whenever a change is made.
Lint scripts for language best-practices.
Image Optimization using OptiPNG and JPEGTran.
Package management.
Unit Testing in a headless WebKit.
Built-in preview server.
# Install nvm - Node Version Manager
curl https://raw.github.com/creationix/nvm/master/install.sh | sh
# Load nvm
source ~/.nvm/nvm.sh
# Install nodejs vr 0.10
nvm install 0.10
# Load nodejs vr 0.10
nvm use 0.10
# Set version 0.10 as default
nvm alias default 0.10
# Install packages as global
npm -g install yo bower grunt-cli generator-webapp generator-angular
# Install rvm - Ruby Version Manager
curl -L https://get.rvm.io | bash -s stable
# Load rvm
source ~/.rvm/scripts/rvm
# List available ruby versions
rvm list
# Install a ruby version and set it as default
rvm install 2.0.0-p353
# Load ruby version 2.0.0-p353 and set as default
rvm use 2.0.0-p353 --default
# Install packages
gem install --pre sass compass
Check rvm and nvm are correctly installed in bashrc.
[[ -s ~/.nvm/nvm.sh ]] && . ~/.nvm/nvm.sh
[[ -s ~/.rvm/scripts/rvm ]] && . ~/.rvm/scripts/rvm
npm -g install yo bower grunt-cli
# Install a yeoman generator
npm -g install generator-webapp
Platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications.
http://s3.amazonaws.com/four.livejournal/20091117/jsconf.pdf
var result = db.query("select * from T");
What is the software doing while it queries the database?
either blocks the entire process or implies multiple execution stacks.
Other threads of execution can run while waiting.
Context switching is not free
Execution stacks take up memory
For massive concurrency, cannot use an OS thread for each connection
why isn’t everyone using event loops, callbacks, and non-blocking I/O?
For reasons both cultural and infrastructural.
We are taught to:
puts("Enter your name: ");
var name = gets();
puts("Name: " + name);
instead of:
puts("Enter your name: ");
gets(function (name) {
puts("Name: " + name);
});
db.query("select..", function (result) {
// callback
});
Allows the program to return to the event loop immediately.
This is how I/O should be done.
every I/O call must take a callback
JavaScript lacked an existing I/O API
Non-blocking I/O
Built-in support for the most important protocols
Low-level.
Stream everything; never force the buffering of data.
http://blogs.gnome.org/alexl/2008/09/09/embeddable-languages-an-implementation/
Lets look why Gnome decided to use it
The Gnome platform (Gtk+, Gio, etc) doesn’t have to fight with any “native” versions of the same functionallity.
Chances of finding someone who knows JS is far higher than finding someone who knows e.g. lua or scheme
The language continually evolves.
Competetive implementations, each trying to be best.
var object;
object = {
"a": 1,
"b": true,
"c": [1,2,3]
};
object.__proto__ = {
"a": 1,
"b": true,
"c": [1,2,3]
};
object.__proto__.__proto__ === {}.__proto__;
object.__proto__.__proto__.__proto__ === null;
var b = {
"a": 1,
"b": true,
"c": [1,2,3]
};
var object = Object.create(b);
object["a"] = 1;
object["b"] = true;
object["c"] = [1, 2, 3];
// Object.defineProperties
var a = {
"a": { value: "hello" },
"b": { value: true },
"c": {
get: function() { return true },
set: function(value) { console.log("Setting `b` to", value) }
}
};
var b = {
"a": 1,
"b": true,
"c": [1,2,3]
};
var object = Object.create(b, a);
function A() {
this["a"] = 1;
this["b"] = true;
this["c"] = [1,2,3];
}
function B() {
this["a"] = 1;
this["b"] = true;
this["c"] = [1,2,3];
}
A.prototype = new B();
var object = new A();
Functions which take a small amount of metadata that describes the environment in which they were defined.
var counter = (function () {
var count = 0;
return function () {
console.log(count++);
}
})();
counter(); // 0
counter(); // 1
Java 7 doesn't support closures
97 Things Every Programmer Should Know
Mastery of the functional programming paradigm can greatly improve the quality of the code you write in other contexts.
composable computation descriptions
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a
fail :: String -> m a
Material del curso JavaScript para Profesionales by redradix
http://slides.com/gsklee/functional-programming-in-5-minutes
The web's scaffolding tool for modern webapps
yo scaffolds out a new application
Grunt is used to build, preview and test your project
Bower is used for dependency management
yo
yo webapp # to use webapp generator directly
webapp hola ke hase
The reference generator
https://github.com/yeoman/generator-webapp
The reference generator
# Install reveal generator
npm install -g generator-webapp
# Create a dir for the project
mkdir project; cd project;
# Scaffold
yo webapp
# Start server
grunt serve
# Build project
grunt build
https://github.com/slara/generator-reveal
Create revealjs slides.
# Install reveal generator
npm install -g generator-reveal
# Create a dir for the slides
mkdir slides; cd slides;
# Scaffold
yo reveal
# Create a new slide
yo reveal:slide "Slide Title" --markdown
# Start grunt server
grunt server
# Build
grunt build
slides/list.json
[
"index.md",
[
"vertical-html.html",
"vertical-markdown.md"
],
[
"vertical-html-2.html",
"vertical-markdown-2.md"
],
"the-end.md"
]
slides/slide.md
<!-- .slide: data-background="#ff0000" -->
* item1 <!-- .element: class="fragment" data-fragment-index="2" -->
* item2 <!-- .element: class="fragment" data-fragment-index="1" -->
https://github.com/DaftMonk/generator-angular-fullstack
Yeoman generator for creating MEAN stack applications, using MongoDB, Express, AngularJS, and Node.
npm install -g generator-angular-fullstack
# Launch your express server in development mode.
grunt serve
# Launch your express server in debug-brk mode with a node-inspector tab.
grunt serve:debug
# Launch your express server in production mode, uses the minified/optimized production folder.
grunt serve:dist
A package manager for the web
npm install -g bower
Create a bower.json file
bower init
{
"name": "webapp",
"private": true,
"dependencies": {
"bootstrap-sass-official": "~3.1.0",
"modernizr": "~2.6.2",
"jquery": "~1.11.0"
},
"devDependencies": {}
}
Install the dependencies listed in the current directory's bower.json
bower install
bower search [<name>]
bower install <package> --save
# Using a different name and a specific version of a package
bower install <name>=<package>#<version> --save
Grunt bowerInstall task will install automatically js and css files in the app/index.html file if the dependency defines a main.js entry in its bower.json file.
grunt bowerInstall
Note: gruntfile.js created with latest yeoman webapp generator will install dependencies automatically.
The primary endpoints of the installed packages.
app/index.html
<!-- build:js scripts/vendor.js -->
<!-- bower:js -->
<script src="../bower_components/jquery/dist/jquery.js"></script>
<script src="../bower_components/bootstrap-sass-.../affix.js"></script>
<script src="../bower_components/bootstrap-sass-.../alert.js"></script>
...
<!-- endbower -->
<!-- endbuild -->
app/styles/main.scss
$icon-font-path: "/bower_components/bootstrap-sass-.../fonts/bootstrap/";
// bower:scss
@import '../../bower_components/bootstrap-sass-.../bootstrap.scss';
// endbower
Configurable through .bowerrc
file.
{
"directory": "public/bower_components"
}
The JavaScript Task Runner
'use strict';
// wrapper function
module.exports = function (grunt) {
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
// Define the configuration for all the tasks
grunt.initConfig({
});
// Load manually a plugin.
grunt.loadNpmTasks('grunt-contrib-uglify');
// Define custom tasks and aliases
grunt.registerTask('wait', function () {});
grunt.registerTask('default', [
'newer:jshint',
'build'
]);
};
grunt.initConfig({
concat: {
// concat task configuration goes here.
},
uglify: {
// uglify task configuration goes here.
},
// Arbitrary non-task-specific properties.
my_property: 'whatever',
my_src_files: ['foo/*.js', 'bar/*.js'],
});
grunt.initConfig({
concat: {
foo: {
// concat task "foo" target options and files go here.
},
bar: {
// concat task "bar" target options and files go here.
},
},
uglify: {
bar: {
// uglify task "bar" target options and files go here.
},
},
});
grunt concat:foo
grunt.registerTask('dist', ['concat:dist', 'uglify:dist']);
grunt.registerTask('foo', 'My "foo" task.', function() {
grunt.log.writeln('Currently running the "default" task.');
// Enqueue "bar" and "baz" tasks, to run after "foo" finishes, in-order.
grunt.task.run('bar', 'baz');
// Or:
grunt.task.run(['bar', 'baz']);
});
Example: wait untill the server is up
grunt.registerTask('wait', function () {
var interval, socket, done = this.async();
grunt.log.ok('Waiting for server reload...');
socket = new require('net').Socket();
socket.on('error', function () {});
socket.connect(grunt.config.data.yeoman.port, function () {
socket.destroy();
clearInterval(interval);
grunt.log.writeln('Done waiting!');
done();
});
interval = setInterval(function () {
socket.connect(grunt.config.data.yeoman.port);
}, 100);
});
// Compact Format
concat: {
src: ['src/bb.js', 'src/bbb.js'],
dest: 'dest/b.js',
},
// Files Object Format
concat: {
files: {
'dest/a.js': ['src/aa.js', 'src/aaa.js'],
'dest/a1.js': ['src/aa1.js', 'src/aaa1.js'],
},
},
// Files Array Format
concat: {
files: [
{src: ['src/aa.js', 'src/aaa.js'], dest: 'dest/a.js'},
{src: ['src/aa1.js', 'src/aaa1.js'], dest: 'dest/a1.js'},
],
},
files: [
{
expand: true, // Enable dynamic expansion.
cwd: 'lib/', // Src matches are relative to this path.
src: ['**/*.js'], // Actual pattern(s) to match.
dest: 'build/', // Destination path prefix.
ext: '.min.js', // Dest filepaths will have this extension.
extDot: 'first', // Extensions in filenames begin after the first dot
flatten: false // Remove all path parts from generated dest paths.
},
],
*
matches any number of characters, but not /?
matches a single character, but not /**
matches any number of characters, including /, as long as it's the only thing in a path part{}
allows for a comma-separated list of "or" expressions!
at the beginning of a pattern will negate the match// Here, bar.js is first, followed by the remaining files, in alpha order:
{src: ['foo/bar.js', 'foo/*.js'], dest: ...}
// All files except for bar.js, in alpha order:
{src: ['foo/*.js', '!foo/bar.js'], dest: ...}
Lets take a look into the plugins used by generator-webapp
https://github.com/gruntjs/grunt-contrib-copy
Copy files and folders.
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>/public',
src: [
'*.{ico,png,txt}',
'.htaccess',
'bower_components/**/*',
'images/{,*/}*.{webp}',
'fonts/**/*'
]
}]
},
},
https://github.com/stephenplusplus/grunt-bower-install
Inject your Bower dependencies right into your HTML from Grunt.
Gruntfile.js
bowerInstall: {
app: {
src: [
// html support
'<%= config.app %>/index.html'
'<%= config.app %>/**/*.html',
// jade support
'<%= config.app %>/views/**/*.jade',
// .scss & .sass support
'<%= config.app %>/styles/main.scss',
],
exclude: ['bower_components/bootstrap/dist/js/bootstrap.js']
}
},
app/index.html
<!-- bower:js -->
<script src="../bower_components/jquery/dist/jquery.js"></script>
<!-- endbower -->
app/styles/main.scss
$icon-font-path: "/bower_components/bootstrap-sass-official/...";
// bower:scss
@import '../../bower_components/.../bootstrap.scss';
// endbower
# Run the task from command line
grunt bowerInstall
# The latest webapp watches bower.json and runs bowerInstall
grunt watch
https://github.com/yeoman/grunt-usemin
Replaces references to non-optimized scripts or stylesheets.
useminPrepare.
usemin
app/index.html
<!-- build:js js/main.js -->
<script src="js/app.js"></script>
<script src="js/controllers/thing-controller.js"></script>
<script src="js/models/thing-model.js"></script>
<script src="js/views/thing-view.js"></script>
<!-- endbuild -->
Gruntfile.js
useminPrepare: {
options: {
dest: '<%= config.dist %>'
},
html: '<%= config.app %>/index.html'
},
Generated configuration for concat and uglify tasks
{
concat: {
'.tmp/concat/js/main.js': [
'app/js/app.js',
'app/js/controllers/thing-controller.js',
'app/js/models/thing-model.js',
'app/js/views/thing-view.js'
]
},
uglifyjs: {
'dist/js/main.js': ['.tmp/concat/js/main.js']
}
}
Performs rewrites based on rev and the useminPrepare configuration
usemin: {
options: {
assetsDirs: ['<%= config.dist %>', '<%= config.dist %>/images']
},
html: ['<%= config.dist %>/{,*/}*.html'],
css: ['<%= config.dist %>/styles/{,*/}*.css']
},
<!-- build:js js/main.js -->
<script src="js/app.js"></script>
<script src="js/controllers/thing-controller.js"></script>
<script src="js/models/thing-model.js"></script>
<script src="js/views/thing-view.js"></script>
<!-- endbuild -->
<script src="js/main.js"></script>
<script src="js/b6c3df09.main.js"></script>
https://github.com/nDmitry/grunt-autoprefixer
Forget about vendor prefixes and write normal CSS according to the latest W3C specs.
Avoid any special language (like Sass) or special mixins.
Uses data from Can I Use, understands which browsers are actual and popular and adds only the necessary vendor prefixes.
Lets take some CSS3
a {
background: linear-gradient(to top, black, white);
display: flex
}
::placeholder {
color: #ccc
}
Supporting the last version of each browser and IE7
autoprefixer: {
options: {
browsers: ["last 1 version", "> 1%", "Explorer 7"]
}
]
We get
a {
background: -webkit-gradient(linear, left bottom, left top,
from(black), to(white));
background: -webkit-linear-gradient(bottom, black, white);
background: linear-gradient(to top, black, white);
display: -webkit-flex;
display: -ms-flexbox;
display: flex; }
::-webkit-input-placeholder {
color: #cccccc; }
::-moz-placeholder {
color: #cccccc; }
:-ms-input-placeholder {
color: #cccccc; }
::placeholder {
color: #cccccc; }
Supporting the latest version of each browser
autoprefixer: {
options: {
browsers: ['last 1 version']
}
}
We get:
a {
background: linear-gradient(to top, black, white);
display: flex; }
::placeholder {
color: #cccccc; }
https://github.com/gruntjs/grunt-contrib-watch
Watches files for changes and runs tasks based on the changed files.
Gruntfile.js
watch: {
sass: {
files: ['<%= config.app %>/styles/{,*/}*.{scss,sass}'],
tasks: ['sass:server', 'autoprefixer']
},
js: {
files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
tasks: ['newer:jshint:all'],
options: {
livereload: true
}
},
}
https://github.com/sindresorhus/grunt-sass
Compile SCSS to CSS using node-sass (the experimental and superfast Node.js based Sass compiler)
sass: {
options: {
sourceMap: true,
loadPath: [
'bower_components'
]
},
server: {
files: [{
expand: true,
cwd: '<%= config.app %>/styles',
src: ['*.scss'],
dest: '.tmp/styles',
ext: '.css'
}]
}
},
A tool that helps to detect errors and potential problems in your JavaScript code.
http://www.jshint.com/ https://github.com/gruntjs/grunt-contrib-jshint
Gruntfile.js
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
// Check the node backend files
server: {
options: {
jshintrc: 'lib/.jshintrc'
},
src: [ 'lib/{,*/}*.js']
},
},
https://github.com/gruntjs/grunt-contrib-connect
Start a connect web server.
connect: {
options: {
port: 9000,
open: true,
livereload: 35729,
// Change this to '0.0.0.0' to access the server from outside
hostname: 'localhost'
},
livereload: {
options: {
middleware: function(connect) {
return [
// Add created files
connect.static('.tmp'),
// Add files under /bower_components prefix
connect().use('/bower_components',
connect.static('./bower_components')),
// Add content under app/
connect.static(config.app),
];
}
}
},
}
https://github.com/drewzboto/grunt-connect-proxy
Provides a http proxy as middleware for the grunt-contrib-connect plugin.
Add a proxy to avoid CORS issues when developing against a backend
connect: { ...
livereload: {
options: {
middleware: function(connect) {
return [
...
connect.static(config.app),
require('grunt-connect-proxy/lib/utils').proxyRequest,
];
}
}
},
proxies: [{
context: '/',
host: 'localhost'
}]
}
https://github.com/sindresorhus/grunt-concurrent
Run some tasks in parallel
Gruntfile.js
concurrent: {
server: [
'compass:server',
'jade:compile',
'copy:styles'
],
dist: [
'compass:dist',
'imagemin',
'svgmin',
'htmlmin'
]
},
https://github.com/btford/grunt-ngmin
Grunt plugin for pre-minifying Angular apps
Turns this
angular.module('whatever').controller('MyCtrl', function ($scope, $http) { ... });
Into
angular.module('whatever').controller('MyCtrl', ['$scope', '$http', function ($scope, $http) { ... }]);
// Allow the use of non-minsafe AngularJS files. Automatically makes it
// minsafe compatible so Uglify does not destroy the ng references
ngmin: {
dist: {
files: [{
expand: true,
cwd: '.tmp/concat/scripts',
src: '*.js',
dest: '.tmp/concat/scripts'
}]
}
},
https://github.com/assemble/assemble
A static site generator for Node.js, Grunt.js, and Yeoman.
Static generation.
Partials to create reusable fragments.
Layouts to wrap pages with commonly used elements.
Pages defined as HTML/templates, JSON or YAML.
Template data in JSON, YAML, YAML front matter, or passed directly as an object.
# Install assemble generator
npm install -g generator-assemble
# Create a dir for the slides
mkdir assemble; cd assemble;
# Scaffold
yo assemble
# Start grunt server
grunt serve
# Build
grunt build
src/
├── content
│ ├── about.md
│ └── index.md
├── data
│ └── site.yml
└── templates
├── layouts
│ ├── minisite.hbs
│ └── default.hbs
├── pages
│ ├── about.hbs
│ ├── blog.hbs
│ └── index.hbs
└── partials
├── carousel.hbs
└── navbar-fixed-top.hbs
Gruntfile.js
assemble: {
options: {
flatten: true,
assets: '<%= config.dist %>/assets',
layout: 'default.hbs',
layoutdir: '<%= config.src %>/templates/layouts/',
data: '<%= config.src %>/data/*.{json,yml}',
partials: '<%= config.src %>/templates/partials/*.hbs',
plugins: ['assemble-contrib-permalinks'],
},
// Targets
server: {
files: {
'.tmp/': ['<%= config.src %>/templates/pages/**/*.hbs']
}
},
dist: {
files: {
'<%= config.dist %>/': ['src/templates/pages/**/*.hbs']
}
}
},
Data object passed to the templates
Use the data filename to access properties
src/data/myTemplate.json
{
"title ": "Heads up!"
}
src/templates/pages/myTemplate.html
<h1 > {{alert.title }} </h1 >
Is where the data object starts
data.{json,yaml} gets loaded into the root of the context
src/data/data.json
{
"title ": "My Title"
}
src/templates/pages/myTemplate.hbs
{{title }}
This expression in any context to refer to the current context.
src/data/people.json
[
"Jon Schlinkert",
"Brian Woodward"
]
src/templates/pages/people.html
<ul>
{{#each people }}
<li> {{this }} </li >
{{/each }}
</ul>
<ul>
<li>Jon Schlinkert</li>
<li>Brian Woodward</li>
</ul>
An optional section of valid YAML that is placed at the top of a page and is used for maintaining metadata for the page and its contents.
---
title: YAML Front Matter
description: A very simple way to add structured data to a page.
---
<h1> {{ title }} </h1>
<p> {{ description }} </p>
Page content here...
Layouts are used for "wrapping" the content of individual pages with common elements
src/
└── templates
└── layouts
├── sidebar.hbs
└── default.hbs
Gruntfile.js
assemble: {
options: {
layout: 'default.hbs',
layoutdir: '<%= config.src %>/templates/layouts/',
},
// Targets with parametrized options
docs: {
options: {layout: 'docs-layout.hbs' },
files: {'docs/': ['src/docs/*.hbs' ]},
},
site: {
options: {layout: 'site-layout.hbs' },
files: {'site/': ['src/site/*.hbs' ]},
}
}
src/template/layouts/default.hbs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset ="UTF-8">
<title> {{title }} </title>
</head>
<body>
{{> body }}
</body>
</html>
src/template/layouts/sidebar.hbs
---
layout: default.hbs
---
<div class="row">
<div class="col-lg-3">
<div class="sidebar">
...
</div>
</div>
<div class="col-lg-9">
{{> body }}
</div>
</div>
src/
└── templates
└── pages
├── about.hbs
├── blog.hbs
├── showcase.hbs
└── index.hbs
Pages are automatically available through the pages object.
<ul>
{{#each pages}}
<li{{#if this.isCurrentPage}} class="active"{{/if}}>
<a href="{{relative dest this.dest}}">{{ data.title }}</a>
</li>
{{/each}}
</ul>
src/templates/pages/markdown.hbs
---
title: Introducción
---
{{md 'src/content/wiki/introduccion.md'}}
{{md 'src/content/wiki/sass.md'}}
src/templates/pages/example.hbs
---
title: Examples
description: "One Partial, Many Possibilities"
datos:
class: panel
content: Hola que tal!!?
---
<div class="page-header">
<h1>{{title}}</h1>
{{> module datos}}
</div>
src/templates/partials/module.hbs
<div class="{{class}}">
{{#if content}}<h2>{{{content}}}</h2>{{/if}}
</div>
{{#each}}, {{#if}} and {{#unless}}
{{embed 'src/code-examples/*.*'}}
{{#eachProperty object}}
{{key}} - {{value}}<br/>
{{/eachProperty }}
<a href="{{_relative "src" "dist"}}/assets/css/styles.css"></a>
<a href="../../dist/assets/css/styles.css"></a>
Reusable fragments
src/
└── templates
└── partials
├── carousel.hbs
├── modal-window.hbs
└── navbar-fixed-top.hbs
Para incrustarlo en algún lugar simplemente escribimos
\{{> navbar-fixed-top }}
src/
├── content
│ ├── about.md
│ └── index.md
├── data
│ └── site.yml
└── templates
├── layouts
│ ├── minisite.hbs
│ └── default.hbs
├── pages
│ ├── about.hbs
│ ├── blog.hbs
│ └── index.hbs
└── partials
├── carousel.hbs
└── navbar-fixed-top.hbs
src/
└── content
│ └── graficas/evolucion.html
├── about.html
└── index.md
src/data/site.yaml
title: Generator_tests
description: Irontec: Internet y Sistemas sobre GNU / LinuX
ogimage: images/Irontec.png
keywords:
- irontec
- linux
- GNU/Linux
src/templates/layouts/default.hbs
<title>{{title}} | {{site.title}}</title>
<meta name="description" content="{{site.description}}">
<meta name="keywords" content="{{site.keywords}}" />
<meta property="og:image" content="{{site.ogimage}}"/>