Let's build!
This creates a lot of output
It runs jshint, tests (karma), sass compilation, manages your javascript file inclusion, minifies javascript, concatentates javascript, CDNifies scripts, compresses images, revisions assets... wow that's a lot! Amazingly, we didn't have to set up a single one of these ourselves!
$> grunt
Running "newer:jshint" (newer) task
Running "newer:jshint:all" (newer) task
No newer files to process.
Running "newer:jshint:test" (newer) task
No newer files to process.
Running "clean:server" (clean) task
Cleaning .tmp...OK
Running "concurrent:test" (concurrent) task
Running "compass:dist" (compass) task
directory .tmp/styles/
create .tmp/styles/main.css (0.024s)
Compilation took 0.06s
Running "compass:server" (compass) task
unchanged app/styles/main.scss
Compilation took 0.002s
Done, without errors.
Execution Time (2014-06-21 02:33:34 UTC)
compass:dist 685ms ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 64%
compass:server 388ms ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 36%
Total 1.1s
Running "autoprefixer:dist" (autoprefixer) task
File .tmp/styles/main.css created.
Running "connect:test" (connect) task
Started connect web server on http://localhost:9001
Running "karma:unit" (karma) task
WARN [karma]: Port 8080 in use
WARN [karma]: Port 8081 in use
INFO [karma]: Karma v0.12.16 server started at http://localhost:8082/
INFO [launcher]: Starting browser PhantomJS
WARN [watcher]: Pattern "/srv/faq/test/mock/**/*.js" does not match any file.
INFO [PhantomJS 1.9.7 (Linux)]: Connected on socket R02YDLcekOs04-sTRZau with id 39748897
PhantomJS 1.9.7 (Linux): Executed 2 of 2 SUCCESS (0.04 secs / 0.022 secs)
Running "clean:dist" (clean) task
Cleaning .tmp...OK
Running "wiredep:app" (wiredep) task
Running "wiredep:sass" (wiredep) task
app/styles/main.scss modified.
Running "useminPrepare:html" (useminPrepare) task
Going through app/index.html to update the config
Looking for build script HTML comment blocks
Configuration is now:
concat:
{ generated:
{ files:
[ { dest: '.tmp/concat/scripts/vendor.js',
src:
[ 'bower_components/jquery/dist/jquery.js',
'bower_components/angular/angular.js',
'bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap/affix.js',
'bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap/alert.js',
'bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap/button.js',
'bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap/carousel.js',
'bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap/collapse.js',
'bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap/dropdown.js',
'bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap/tab.js',
'bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap/transition.js',
'bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap/scrollspy.js',
'bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap/modal.js',
'bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap/tooltip.js',
'bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap/popover.js',
'bower_components/angular-resource/angular-resource.js',
'bower_components/angular-cookies/angular-cookies.js',
'bower_components/angular-sanitize/angular-sanitize.js',
'bower_components/angular-animate/angular-animate.js',
'bower_components/angular-touch/angular-touch.js',
'bower_components/angular-route/angular-route.js' ] },
{ dest: '.tmp/concat/scripts/scripts.js',
src:
[ '{.tmp,app}/scripts/app.js',
'{.tmp,app}/scripts/controllers/main.js',
'{.tmp,app}/scripts/controllers/about.js' ] } ] } }
uglify:
{ generated:
{ files:
[ { dest: 'dist/scripts/vendor.js',
src: [ '.tmp/concat/scripts/vendor.js' ] },
{ dest: 'dist/scripts/scripts.js',
src: [ '.tmp/concat/scripts/scripts.js' ] } ] } }
cssmin:
{ generated:
{ files:
[ { dest: 'dist/styles/vendor.css', src: [] },
{ dest: 'dist/styles/main.css',
src: [ '.tmp/styles/main.css' ] } ] } }
Running "concurrent:dist" (concurrent) task
>> Warning: There are more tasks than your concurrency limit. After this limit
>> is reached no further tasks will be run until the current tasks are
>> completed. You can adjust the limit in the concurrent task options
Running "imagemin:dist" (imagemin) task
✔ app/images/yeoman.png (saved 5 kB - 37%)
Minified 1 image (saved 5 kB)
Done, without errors.
Execution Time (2014-06-21 02:33:53 UTC)
loading tasks 12ms ▇ 2%
imagemin:dist 559ms ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 98%
Total 573ms
Running "svgmin:dist" (svgmin) task
Total saved: 0 B
Done, without errors.
Execution Time (2014-06-21 02:33:59 UTC)
svgmin:dist 792ms ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 99%
Total 797ms
Running "compass:dist" (compass) task
directory .tmp/styles/
create .tmp/styles/main.css (6.137s)
Compilation took 6.182s
Done, without errors.
Execution Time (2014-06-21 02:33:53 UTC)
compass:dist 9.7s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 100%
Total 9.7s
Running "autoprefixer:dist" (autoprefixer) task
File .tmp/styles/main.css created.
Running "concat:generated" (concat) task
File .tmp/concat/scripts/vendor.js created.
File .tmp/concat/scripts/scripts.js created.
Running "ngmin:dist" (ngmin) task
ngminifying .tmp/concat/scripts/scripts.js, .tmp/concat/scripts/vendor.js
Running "copy:dist" (copy) task
Copied 11 files
Running "cdnify:dist" (cdnify) task
Going through dist/404.html, dist/index.html to update script refs
Running "cssmin:generated" (cssmin) task
>> Destination not written because minified CSS was empty.
File dist/styles/main.css created: 283.65 kB → 104.35 kB
Running "uglify:generated" (uglify) task
File dist/scripts/vendor.js created: 1.24 MB → 262.8 kB
File dist/scripts/scripts.js created: 1.19 kB → 576 B
Running "filerev:dist" (filerev) task
✔ dist/scripts/scripts.js changed to scripts.673b06a2.js
✔ dist/scripts/vendor.js changed to vendor.4c4a35b4.js
✔ dist/styles/main.css changed to main.e40f8f97.css
✔ dist/images/yeoman.png changed to yeoman.5cff96e1.png
Running "usemin:html" (usemin) task
Processing as HTML - dist/404.html
Update the HTML to reference our concat/min/revved script files
Update the HTML with the new css filenames
Update the HTML with the new img filenames
Update the HTML with the new video filenames
Update the HTML with the new poster filenames
Update the HTML with the new source filenames
Update the HTML with data-main tags
Update the HTML with data-* tags
Update the HTML with background imgs, case there is some inline style
Update the HTML with anchors images
Update the HTML with reference in input
Update the HTML with the new img filenames in meta tags
Processing as HTML - dist/index.html
Update the HTML to reference our concat/min/revved script files
<script src="scripts/vendor.js" changed to <script src="scripts/vendor.4c4a35b4.js"
<script src="scripts/scripts.js" changed to <script src="scripts/scripts.673b06a2.js"
Update the HTML with the new css filenames
<link rel="stylesheet" href="styles/main.css" changed to <link rel="stylesheet" href="styles/main.e40f8f97.css"
Update the HTML with the new img filenames
Update the HTML with the new video filenames
Update the HTML with the new poster filenames
Update the HTML with the new source filenames
Update the HTML with data-main tags
Update the HTML with data-* tags
Update the HTML with background imgs, case there is some inline style
Update the HTML with anchors images
Update the HTML with reference in input
Update the HTML with the new img filenames in meta tags
Processing as HTML - dist/views/about.html
Update the HTML to reference our concat/min/revved script files
Update the HTML with the new css filenames
Update the HTML with the new img filenames
Update the HTML with the new video filenames
Update the HTML with the new poster filenames
Update the HTML with the new source filenames
Update the HTML with data-main tags
Update the HTML with data-* tags
Update the HTML with background imgs, case there is some inline style
Update the HTML with anchors images
Update the HTML with reference in input
Update the HTML with the new img filenames in meta tags
Processing as HTML - dist/views/main.html
Update the HTML to reference our concat/min/revved script files
Update the HTML with the new css filenames
Update the HTML with the new img filenames
<img src="images/yeoman.png" changed to <img src="images/yeoman.5cff96e1.png"
Update the HTML with the new video filenames
Update the HTML with the new poster filenames
Update the HTML with the new source filenames
Update the HTML with data-main tags
Update the HTML with data-* tags
Update the HTML with background imgs, case there is some inline style
Update the HTML with anchors images
Update the HTML with reference in input
Update the HTML with the new img filenames in meta tags
Running "usemin:css" (usemin) task
Processing as CSS - dist/styles/main.e40f8f97.css
Update the CSS to reference our revved images
Running "htmlmin:dist" (htmlmin) task
Minified dist/404.html 3.53 kB → 3.39 kB
Minified dist/index.html 1.94 kB → 1.73 kB
Minified dist/views/about.html 31 B → 30 B
Minified dist/views/main.html 700 B → 656 B
Done, without errors.
Execution Time (2014-06-21 02:33:31 UTC)
concurrent:test 3.8s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 7%
karma:unit 4.5s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 8%
wiredep:app 5.8s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 11%
concurrent:dist 17.6s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 33%
ngmin:dist 15.2s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 28%
cdnify:dist 1.8s ▇▇▇▇▇▇▇ 3%
uglify:generated 3.7s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 7%
Total 53.5s
Let's test it out!
We'll let grunt spin up an instance and let it open our browser for us. A dev could really get used to this.
Oh, and it has live reload so as we work, it'll refresh automagically.
$grunt serve
Running "serve" task
Running "clean:server" (clean) task
Cleaning .tmp...OK
Running "wiredep:app" (wiredep) task
Running "wiredep:sass" (wiredep) task
Running "concurrent:server" (concurrent) task
Running "compass:server" (compass) task
directory .tmp/styles/
create .tmp/styles/main.css (2.517s)
Compilation took 2.595s
Done, without errors.
Execution Time (2014-06-21 02:40:15 UTC)
compass:server 3.4s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 100%
Total 3.4s
Running "autoprefixer:dist" (autoprefixer) task
File .tmp/styles/main.css created.
Running "connect:livereload" (connect) task
Started connect web server on http://localhost:9000
Running "watch" task
Waiting...
Angularjs directive
A directive is the encapsulation of DOM and scripts to manipulate that DOM. It exists as a user-defined 'tag' for use in angularjs templates. They are replaced with real DOM that we define. This is similar to shadow DOM.
$>yo angular:directive hello-world
create app/scripts/directives/hello-world.js
create test/spec/directives/hello-world.js
This generated our javascript for our directive and a test for it
angularjs directive (cont)
$> vim app/scripts/directives/hello-world.js
1 'use strict';
2
3 /**
4 * @ngdoc directive
5 * @name faqApp.directive:helloWorld
6 * @description
7 * # helloWorld
8 */
9 angular.module('faqApp')
10 .directive('helloWorld', function () {
11 return {
12 template: '<div></div>',
13 restrict: 'E',
14 link: function postLink(scope, element, attrs) {
15 element.text('this is the helloWorld directive');
16 }
17 };
18 });
angularjs directive
9 angular.module('faqApp')
Defines that this is part of the faqApp module
10 .directive('helloWorld', function () {
Defines a directive called helloWorld
11 return {
12 template: '<div></div>',
13 restrict: 'E',
14 link: function postLink(scope, element, attrs) {
15 element.text('this is the helloWorld directive');
16 }
17 };
Defines a template (I usually use templateUrl instead to map to an html file)
Restricts the usage to an element (this can be C for class, A for attribute, or any combination thereof)
Creates a link function. Let's discuss this further.
angularjs directive
Directives have functions that run at different times in their life cycle. This is one of the more complex ideas in angularjs and is especially important to transclusion (accessing scopes outside of your own)
Compile - This is a function that runs at compile time. We have the raw template at this step, it only runs once.
Controller - Runs once per instance. Contains scope and simple element with no data bindings. Scope is not yet set up
PreLink - Rarely used.
PostLink - Place where DOM manipulation should happen, event listeners bound. Last function to execute. Scope is now set up.