Javascript Frameworks For Modern Web Dev 1st Edition Tim Ambler download
Javascript Frameworks For Modern Web Dev 1st Edition Tim Ambler download
https://ebookbell.com/product/javascript-frameworks-for-modern-
web-dev-1st-edition-tim-ambler-50195406
Javascript Frameworks For Modern Web Dev Tim Ambler Nicholas Cloud
Auth
https://ebookbell.com/product/javascript-frameworks-for-modern-web-
dev-tim-ambler-nicholas-cloud-auth-5233896
https://ebookbell.com/product/javascript-frameworks-for-modern-web-
development-2nd-edition-2nd-edition-sufyan-bin-uzayr-50195408
https://ebookbell.com/product/javascript-simple-guide-for-concepts-
libraries-frameworks-tools-joseph-232143592
Beginning Phonegap Mobile Web Framework For Javascript And Html5 1st
Edition Rohit Ghatol
https://ebookbell.com/product/beginning-phonegap-mobile-web-framework-
for-javascript-and-html5-1st-edition-rohit-ghatol-2581586
Beginning Phonegap Mobile Web Framework For Javascript And Html5 Rohit
Ghatol
https://ebookbell.com/product/beginning-phonegap-mobile-web-framework-
for-javascript-and-html5-rohit-ghatol-2620924
https://ebookbell.com/product/sencha-touch-10-mobile-javascript-
framework-build-web-applications-for-apple-ios-and-google-android-
touchscreen-devices-with-this-first-html5-mobile-framework-1st-
edition-narasimha-rao-4107484
https://ebookbell.com/product/making-multiplayer-online-games-a-game-
development-workbook-for-any-phaser-javascript-gaming-framework-
stephen-gose-51878366
https://ebookbell.com/product/professional-javascript-frameworks-
prototype-yui-ext-js-dojo-and-mootools-leslie-m-orchard-scott-koon-et-
al-4106364
https://ebookbell.com/product/professional-javascript-frameworks-
prototypeyui-extjs-dojo-and-mootools-wrox-programmer-to-programmer-
leslie-m-orchard-1629886
I
Fa Ma Kn Re Grun nclu
ye ch oc q t, de
, Q , ko uir Ye s B
, A Mo ut eJ om o
sy ng , A S,B a we
nc o ng ro n, r,
.js ose ul w PM
, U , ar se 2
nd K n JS, rif ,
er ex, Kr y,
sco B ak
re, ook en
an she ,
d L lf,
od
as
h
www.it-ebooks.info
JavaScript Frameworks
for Modern Web Dev
Tim Ambler
Nicholas Cloud
www.it-ebooks.info
JavaScript Frameworks for Modern Web Dev
Copyright © 2015 by Tim Ambler and Nicholas Cloud
This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part of the
material is concerned, specifically the rights of translation, reprinting, reuse of illustrations, recitation,
broadcasting, reproduction on microfilms or in any other physical way, and transmission or information
storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar methodology now
known or hereafter developed. Exempted from this legal reservation are brief excerpts in connection with
reviews or scholarly analysis or material supplied specifically for the purpose of being entered and executed
on a computer system, for exclusive use by the purchaser of the work. Duplication of this publication or
parts thereof is permitted only under the provisions of the Copyright Law of the Publisher’s location, in its
current version, and permission for use must always be obtained from Springer. Permissions for use may be
obtained through RightsLink at the Copyright Clearance Center. Violations are liable to prosecution under
the respective Copyright Law.
ISBN-13 (pbk): 978-1-4842-0663-8
ISBN-13 (electronic): 978-1-4842-0662-1
Trademarked names, logos, and images may appear in this book. Rather than use a trademark symbol
with every occurrence of a trademarked name, logo, or image we use the names, logos, and images only
in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the
trademark.
The use in this publication of trade names, trademarks, service marks, and similar terms, even if they are
not identified as such, is not to be taken as an expression of opinion as to whether or not they are subject to
proprietary rights.
While the advice and information in this book are believed to be true and accurate at the date of publication,
neither the authors nor the editors nor the publisher can accept any legal responsibility for any errors or
omissions that may be made. The publisher makes no warranty, express or implied, with respect to the
material contained herein.
Managing Director: Welmoed Spahr
Lead Editor: Louise Corrigan
Technical Reviewer: Robin Hawkes
Editorial Board: Steve Anglin, Mark Beckner, Gary Cornell, Louise Corrigan, James DeWolf,
Jonathan Gennick, Robert Hutchinson, Michelle Lowman, James Markham, Matthew Moodie,
Jeffrey Pepper, Douglas Pundick, Ben Renow-Clarke, Gwenan Spearing, Matt Wade, Steve Weiss
Coordinating Editor: Kevin Walter
Copy Editor: Bill McManus
Compositor: SPi Global
Indexer: SPi Global
Artist: SPi Global
Cover Designer: Crest
Distributed to the book trade worldwide by Springer Science+Business Media New York,
233 Spring Street, 6th Floor, New York, NY 10013. Phone 1-800-SPRINGER, fax (201) 348-4505, e-mail
[email protected], or visit www.springeronline.com. Apress Media, LLC is a California LLC
and the sole member (owner) is Springer Science + Business Media Finance Inc (SSBM Finance Inc).
SSBM Finance Inc is a Delaware corporation.
For information on translations, please e-mail [email protected], or visit www.apress.com.
Apress and friends of ED books may be purchased in bulk for academic, corporate, or promotional use.
eBook versions and licenses are also available for most titles. For more information, reference our Special
Bulk Sales–eBook Licensing web page at www.apress.com/bulk-sales.
Any source code or other supplementary material referenced by the author in this text is available to
readers at www.apress.com/. For detailed information about how to locate your book’s source code, go to
www.apress.com/source-code/.
www.it-ebooks.info
There was a young lady named Laura,
Who was a beautiful señora.
Her love and assurance
Was a frequent occurrence
Which allowed me to write this book for yah.
—Tim
www.it-ebooks.info
Contents at a Glance
■
■Chapter 1: Bower��������������������������������������������������������������������������������������������������� 1
■
■Chapter 2: Grunt�������������������������������������������������������������������������������������������������� 11
■
■Chapter 3: Yeoman���������������������������������������������������������������������������������������������� 37
■
■Chapter 4: PM2���������������������������������������������������������������������������������������������������� 53
■
■Chapter 5: RequireJS������������������������������������������������������������������������������������������� 73
■
■Chapter 6: Browserify���������������������������������������������������������������������������������������� 101
■
■Chapter 7: Knockout������������������������������������������������������������������������������������������ 121
■
■Chapter 8: AngularJS���������������������������������������������������������������������������������������� 155
■
■Chapter 9: Kraken���������������������������������������������������������������������������������������������� 191
■
■Chapter 10: Mach���������������������������������������������������������������������������������������������� 251
■
■Chapter 11: Mongoose��������������������������������������������������������������������������������������� 297
■
■Chapter 12: Knex and Bookshelf����������������������������������������������������������������������� 345
■
■Chapter 13: Faye������������������������������������������������������������������������������������������������ 381
www.it-ebooks.info
■ Contents at a Glance
■
■Chapter 14: Q����������������������������������������������������������������������������������������������������� 395
■
■Chapter 15: Async.js����������������������������������������������������������������������������������������� 425
■
■Chapter 16: Underscore and Lodash����������������������������������������������������������������� 447
Index��������������������������������������������������������������������������������������������������������������������� 477
vi
www.it-ebooks.info
Contents
■
■Chapter 1: Bower��������������������������������������������������������������������������������������������������� 1
Getting Started����������������������������������������������������������������������������������������������������������������� 2
Configuring Bower������������������������������������������������������������������������������������������������������������ 2
The Manifest�������������������������������������������������������������������������������������������������������������������� 2
Creating a New Manifest������������������������������������������������������������������������������������������������������������������������ 3
Semantic Versioning��������������������������������������������������������������������������������������������������������� 6
Managing the Dependency Chain������������������������������������������������������������������������������������� 7
Creating Bower Packages������������������������������������������������������������������������������������������������ 8
Choose a Valid Name������������������������������������������������������������������������������������������������������������������������������ 8
Use Semver Git Tags������������������������������������������������������������������������������������������������������������������������������� 8
Publish Your Package to the Registry����������������������������������������������������������������������������������������������������� 9
Summary�������������������������������������������������������������������������������������������������������������������������� 9
vii
www.it-ebooks.info
■ Contents
■
■Chapter 2: Grunt�������������������������������������������������������������������������������������������������� 11
Installing Grunt��������������������������������������������������������������������������������������������������������������� 12
How Grunt Works������������������������������������������������������������������������������������������������������������ 12
Gruntfile.js�������������������������������������������������������������������������������������������������������������������������������������������� 12
Tasks���������������������������������������������������������������������������������������������������������������������������������������������������� 14
Plugins�������������������������������������������������������������������������������������������������������������������������������������������������� 14
Configuration���������������������������������������������������������������������������������������������������������������������������������������� 15
Creating Plugins������������������������������������������������������������������������������������������������������������� 32
Getting Started������������������������������������������������������������������������������������������������������������������������������������� 32
Creating the Task���������������������������������������������������������������������������������������������������������������������������������� 32
Publishing to npm��������������������������������������������������������������������������������������������������������������������������������� 35
Summary������������������������������������������������������������������������������������������������������������������������ 36
Related Resources��������������������������������������������������������������������������������������������������������� 36
viii
www.it-ebooks.info
■ Contents
■
■Chapter 3: Yeoman���������������������������������������������������������������������������������������������� 37
Installing Yeoman����������������������������������������������������������������������������������������������������������� 38
Creating Your First Project���������������������������������������������������������������������������������������������� 38
Subcommands�������������������������������������������������������������������������������������������������������������������������������������� 41
Summary������������������������������������������������������������������������������������������������������������������������ 52
Related Resources��������������������������������������������������������������������������������������������������������� 52
■
■Chapter 4: PM2���������������������������������������������������������������������������������������������������� 53
Installation���������������������������������������������������������������������������������������������������������������������� 53
Working with Processes������������������������������������������������������������������������������������������������� 54
Recovering from Errors������������������������������������������������������������������������������������������������������������������������ 56
Responding to File Changes����������������������������������������������������������������������������������������������������������������� 58
Monitoring Logs������������������������������������������������������������������������������������������������������������� 58
Monitoring Resource Usage������������������������������������������������������������������������������������������� 60
Monitoring Local Resources����������������������������������������������������������������������������������������������������������������� 60
Monitoring Remote Resources������������������������������������������������������������������������������������������������������������� 61
Advanced Process Management������������������������������������������������������������������������������������ 63
JSON Application Declarations������������������������������������������������������������������������������������������������������������� 63
Summary������������������������������������������������������������������������������������������������������������������������ 72
Related Resources��������������������������������������������������������������������������������������������������������� 72
ix
www.it-ebooks.info
■ Contents
■
■Chapter 5: RequireJS������������������������������������������������������������������������������������������� 73
Running the Examples���������������������������������������������������������������������������������������������������� 74
Working with RequireJS������������������������������������������������������������������������������������������������� 74
Installation�������������������������������������������������������������������������������������������������������������������������������������������� 75
Configuration���������������������������������������������������������������������������������������������������������������������������������������� 75
Application Modules and Dependencies����������������������������������������������������������������������������������������������� 78
Paths and Aliases��������������������������������������������������������������������������������������������������������������������������������� 81
Shims���������������������������������������������������������������������������������������������������������������������������������������������������� 84
Loader Plugins�������������������������������������������������������������������������������������������������������������������������������������� 88
Cache Busting��������������������������������������������������������������������������������������������������������������������������������������� 94
RequireJS Optimizer������������������������������������������������������������������������������������������������������� 96
Configuring r.js������������������������������������������������������������������������������������������������������������������������������������� 96
Running the r.js Command������������������������������������������������������������������������������������������������������������������� 97
Summary������������������������������������������������������������������������������������������������������������������������ 99
■
■Chapter 6: Browserify���������������������������������������������������������������������������������������� 101
The AMD API vs. CommonJS���������������������������������������������������������������������������������������� 102
Installing Browserify���������������������������������������������������������������������������������������������������� 102
Creating Your First Bundle�������������������������������������������������������������������������������������������� 103
Visualizing the Dependency Tree���������������������������������������������������������������������������������� 104
Creating New Bundles As Changes Occur�������������������������������������������������������������������� 105
Watching for File Changes with Grunt������������������������������������������������������������������������������������������������ 106
Watching for File Changes with Watchify������������������������������������������������������������������������������������������� 106
www.it-ebooks.info
■ Contents
Summary���������������������������������������������������������������������������������������������������������������������� 120
Related Resources������������������������������������������������������������������������������������������������������� 120
■
■Chapter 7: Knockout������������������������������������������������������������������������������������������ 121
Views, Models, and View Models��������������������������������������������������������������������������������� 122
The Recipe List����������������������������������������������������������������������������������������������������������������������������������� 124
Recipe Details������������������������������������������������������������������������������������������������������������������������������������� 127
xi
www.it-ebooks.info
■ Contents
■
■Chapter 8: AngularJS���������������������������������������������������������������������������������������� 155
A Declarative Approach to Building Web Applications�������������������������������������������������� 155
The Imperative Approach�������������������������������������������������������������������������������������������������������������������� 155
The Declarative Approach������������������������������������������������������������������������������������������������������������������� 157
xii
www.it-ebooks.info
■ Contents
Summary���������������������������������������������������������������������������������������������������������������������� 250
Related Resources������������������������������������������������������������������������������������������������������� 250
■
■Chapter 10: Mach���������������������������������������������������������������������������������������������� 251
Chapter Examples�������������������������������������������������������������������������������������������������������� 251
Installation�������������������������������������������������������������������������������������������������������������������� 252
Mach, the Web Server�������������������������������������������������������������������������������������������������� 252
HTTP Routes��������������������������������������������������������������������������������������������������������������������������������������� 254
Making Connections��������������������������������������������������������������������������������������������������������������������������� 260
Common Middleware�������������������������������������������������������������������������������������������������������������������������� 262
These Are Not the Routes You’re Looking for������������������������������������������������������������������������������������� 280
The Hosts with the Most��������������������������������������������������������������������������������������������������������������������� 282
Custom Middleware���������������������������������������������������������������������������������������������������������������������������� 287
xiii
www.it-ebooks.info
■ Contents
■
■Chapter 11: Mongoose��������������������������������������������������������������������������������������� 297
Basic MongoDB Concepts�������������������������������������������������������������������������������������������� 297
A Simple Mongoose Example��������������������������������������������������������������������������������������� 300
Creating a Mongoose Schema for JSON Data������������������������������������������������������������������������������������ 301
Importing Data with Mongoose���������������������������������������������������������������������������������������������������������� 302
Querying Data with Mongoose����������������������������������������������������������������������������������������������������������� 305
www.it-ebooks.info
■ Contents
Bookshelf��������������������������������������������������������������������������������������������������������������������� 361
What Is an Object-Relational Mapper?����������������������������������������������������������������������������������������������� 361
Creating Your First Bookshelf Model��������������������������������������������������������������������������������������������������� 362
Relationships�������������������������������������������������������������������������������������������������������������������������������������� 370
Summary���������������������������������������������������������������������������������������������������������������������� 379
Related Resources������������������������������������������������������������������������������������������������������� 379
■
■Chapter 13: Faye������������������������������������������������������������������������������������������������ 381
HTTP, Bayeux, and WebSockets������������������������������������������������������������������������������������ 381
WebSockets���������������������������������������������������������������������������������������������������������������������������������������� 383
The Bayeux Protocol��������������������������������������������������������������������������������������������������������������������������� 384
Summary���������������������������������������������������������������������������������������������������������������������� 393
Related Resources������������������������������������������������������������������������������������������������������� 394
■
■Chapter 14: Q����������������������������������������������������������������������������������������������������� 395
Timing Is Everything����������������������������������������������������������������������������������������������������� 395
Promises vs. Callbacks������������������������������������������������������������������������������������������������ 399
The Promise of Q���������������������������������������������������������������������������������������������������������� 401
Deferreds and Promises��������������������������������������������������������������������������������������������������������������������� 401
Values and Errors������������������������������������������������������������������������������������������������������������������������������� 406
Reporting Progress����������������������������������������������������������������������������������������������������������������������������� 412
Everything Ends���������������������������������������������������������������������������������������������������������������������������������� 415
Summary���������������������������������������������������������������������������������������������������������������������� 423
Related Resources������������������������������������������������������������������������������������������������������� 423
xv
www.it-ebooks.info
■ Contents
■
■Chapter 15: Async.js����������������������������������������������������������������������������������������� 425
Sequential Flow������������������������������������������������������������������������������������������������������������ 426
Parallel Flow����������������������������������������������������������������������������������������������������������������� 428
Pipeline Flow���������������������������������������������������������������������������������������������������������������� 430
Reusing a Pipeline������������������������������������������������������������������������������������������������������������������������������ 433
Summary���������������������������������������������������������������������������������������������������������������������� 446
■
■Chapter 16: Underscore and Lodash����������������������������������������������������������������� 447
Installation and Usage�������������������������������������������������������������������������������������������������� 449
Aggregation and Indexing�������������������������������������������������������������������������������������������� 449
countBy( )�������������������������������������������������������������������������������������������������������������������������������������������� 449
groupBy( )�������������������������������������������������������������������������������������������������������������������������������������������� 451
indexBy( )�������������������������������������������������������������������������������������������������������������������������������������������� 452
Chaining����������������������������������������������������������������������������������������������������������������������� 460
Function Timing������������������������������������������������������������������������������������������������������������ 463
defer( )������������������������������������������������������������������������������������������������������������������������������������������������ 463
debounce( )����������������������������������������������������������������������������������������������������������������������������������������� 465
throttle( )��������������������������������������������������������������������������������������������������������������������������������������������� 466
xvi
www.it-ebooks.info
■ Contents
Templates��������������������������������������������������������������������������������������������������������������������� 468
Loops and Other Arbitrary JavaScript in Templates���������������������������������������������������������������������������� 470
Living Without Gator Tags������������������������������������������������������������������������������������������������������������������� 472
Accessing the Data Object Within a Template������������������������������������������������������������������������������������ 473
Default Template Data������������������������������������������������������������������������������������������������������������������������ 474
Summary���������������������������������������������������������������������������������������������������������������������� 475
Related Resources������������������������������������������������������������������������������������������������������� 476
Index��������������������������������������������������������������������������������������������������������������������� 477
xvii
www.it-ebooks.info
About the Authors
Nicholas Cloud is a software developer who lives in the very humid city of
St. Louis. For over a decade he has forged his skills into a successful career.
He has developed web applications, web services, and desktop software on
diverse platforms with JavaScript, C#, and PHP. A strong proponent of open
source software, Nicholas contributes to userland projects and has written
several of his own open source libraries libraries. He speaks at a variety of
user groups and conferences and writes books, technical articles, and blog
posts in his spare time. He opines on Twitter at @nicholascloud.
xix
www.it-ebooks.info
About the Technical Reviewer
xxi
www.it-ebooks.info
Acknowledgments
This book would not have been possible without the encouragement and support of a number of people:
Nicholas Cloud, my friend and co-author, without whom this book would be much more limited
in scope and depth. His knowledge, experience, and steadfast dedication to this project have been
immeasurably helpful. Thank you.
Louise Corrigan, Kevin Walter, Christine Ricketts, Melissa Maldonado, and the rest of the staff at Apress
who supported us throughout the course of this project. I am grateful for the invitation that was extended to
embark upon this journey and for the ongoing support that you have provided.
Robin Hawkes, our technical reviewer. The examples and source code included with this book have
greatly benefited from his keen insight and sharp eye.
James Coglan, the creator of Faye. Thank you for taking the time to share your technical expertise
and feedback.
My friends and colleagues Greg Jones, Jeff Crump, Seth Steele, Jon Zumbrun, and Brian Hiatt. I am
grateful for your feedback and encouragement.
—Tim
Acknowledgements are slippery things. I have so many debts, and so little space to repay.
First, the debt to my co-author Tim who reached out and invited me on this journey. We’ve never met
in person but worked remotely as co-workers for about half a year—enough time for each of us to leave an
impression on each other across the miles. For his trust, encouragement, and constant effort I am grateful.
Second, my debt to the staff at Apress who guided us through the publishing process: Kevin, Louise,
Christine, and Melissa. Their patience and careful guidance spared you, the reader, from no small amount of
cringes, and kept me on my toes during the entire writing process. They are all sharp professionals with whom
I hope to work again some day.
Third, I am indebted to Robin for his excellent technical reviews; for reading and executing more code
samples than a developer should ever be tasked with groking.
Finally, I cannot repay the subject-matter expertise I gleaned from Michael Jackson (@mjackson) while
researching Mach, and Ryan Niemeyer (@RPNiemeyer) while researching Knockout—I can only pay it forward
to you, the reader.
—Nicholas
xxiii
www.it-ebooks.info
Introduction
They tell me we’re living in an information age, but none of it seems to be the information
I need or brings me closer to what I want to know. In fact (I’m becoming more and more
convinced) all this electronic wizardry only adds to our confusion, delivering inside scoops
and verdicts about events that have hardly begun: a torrent of chatter moving at the speed
of light, making it nearly impossible for any of the important things to be heard.
—Matthew Flaming, The Kingdom of Ohio
The notion that “technology moves quickly” is a well-worn aphorism, and with good reason: technology
does move quickly. But at this moment, JavaScript in particular is moving very quickly indeed—much like
that “torrent of chatter moving at the speed of light” that Matthew Flaming refers to in The Kingdom of Ohio.
The language is in the midst of what many have called a renaissance, brought about by the rapidly increasing
sophistication of browser-based applications and the rising popularity of JavaScript on the server, thanks to
Node.js.
An almost feverish pace of innovation is occurring within the JavaScript community that, while
endlessly fascinating to follow, also presents some unique challenges of its own. JavaScript’s ecosystem of
libraries, frameworks, and utilities has grown dramatically. Where once a small number of solutions for any
given problem existed, many can now be found… and the options continue to grow by the day. As a result,
developers find themselves faced with the increasingly difficult task of choosing the appropriate tools from
among many seemingly good options.
If you’ve ever found yourself wondering why JavaScript seems to be attracting so much attention lately,
as we have, it’s worth stopping for a moment to consider the fact that JavaScript, a language that was created
by one person in ten days, now serves as the foundation upon which much of the Web as we know it sits.
A language that was originally created to solve relatively simple problems is now being applied in new
and innovative ways that were not originally foreseen. What’s more, JavaScript is a beautifully expressive
language, but it’s not without its share of rough edges and potential pitfalls. While flexible, efficient, and
ubiquitous, JavaScript concepts such as the event loop and prototypal inheritance can prove particularly
challenging for those coming to the language for the first time.
For these and many other reasons, the development community at large is still coming to terms with
how best to apply the unique features that JavaScript brings to the table. We’ve no doubt only scratched
the surface of what the language and the community behind it are capable of. For those with an insatiable
appetite for knowledge and a desire to create, now is the perfect time to be a JavaScript developer.
We have written Pro JavaScript Frameworks for Modern Web Dev to serve as your guide to a wide
range of popular JavaScript tools that solve difficult problems at both ends of the development stack: in
the browser and on the server. The tutorials and downloadable code examples contained within this book
illustrate the usage of tools that manage dependencies, structure code in a modular fashion, automate
repetitive build tasks, create specialized servers, structure client side applications, facilitate horizontal
scaling, perform event logging, and interacting with disparate data stores.
The libraries and frameworks covered include Bower, Grunt, Yeoman, PM2, RequireJS, Browserify,
Knockout, AngularJS, Kraken, Mach, Mongoose, Knex, Bookshelf, Faye, Q, Async.js, Underscore, and Lodash.
xxv
www.it-ebooks.info
■ Introduction
In writing Pro JavaScript Frameworks for Modern Web Dev, our goal was to create a filter for the
“torrent of chatter” that often seems to surround JavaScript, and in so doing, to allow what we believe are
some important things to be heard. We hope the information contained within these pages proves as useful
to you as it has to us.
Grunt
Larry Wall, the creator of Perl, describes the three virtues of a great programmer as: laziness, impatience,
and hubris. In this chapter, we’ll focus on a tool that will help you strengthen the virtue of laziness - Grunt.
This popular task runner provides developers with a framework for creating command-line utilities
that automative repetitive build tasks such as running tests, concatenating files, compiling SASS / LESS
stylesheets, checking for JavaScript errors, and more. After reading this chapter, you’ll know how to use several
popular Grunt plugins, as well as how to go about creating and sharing your own plugins with the community.
xxvi
www.it-ebooks.info
■ Introduction
Yeoman
Yeoman provides JavaScript developers with a mechanism for creating reusable templates (“generators”)
that describe the overall structure of a project (initially required dependencies, Grunt tasks, etc…) in a way
that can be easily re-used over and over. Broad community support also allows you to take advantage of a
wide variety of pre-existing templates. In this chapter, we’ll walk through the process of installing Yeoman
and using several popular pre-existing generators. Finally, we’ll take a look at how we can create and share
our own templates with the community.
PM2
In this chapter, we will close out our discussion of development tools by taking a look at PM2, a command-line
utility that simplifies many of the tasks associated with running Node applications, monitoring their status,
and efficiently scaling them to meet increasing demand.
xxvii
www.it-ebooks.info
■ Introduction
Part 6: Communication
Faye
In this section, you’ll be introduced to Faye, a Node.js library that provides developers with a robust and
easy-to-use platform for building products that rely on real-time communication between servers and all
major browsers.Much of Faye’s popularity stems from the project’s goal of working everywhere the Web
works. Faye accomplishes this by providing seamless fallback support for a number of communication
protocols.
xxviii
www.it-ebooks.info
■ Introduction
Most examples are run with the Node.js runtime, which may be obtained from https://nodejs.org.
Chapters with additional prerequisites will explain the necessary procedures for downloading and
installing the examples. (For example, MongoDB is necessary to run examples in Chapter 11, which covers
Mongoose.)
Any additional steps necessary for running code examples (e.g., executing curl requests) or interacting
with a running example (e.g., opening a web browser and navigating to a specific URL) are explained
alongside each listing.
xxix
www.it-ebooks.info
Chapter 1
Bower
The concept of package management, also known as dependency management, is not new. Utilities within
this category provide developers with a mechanism for managing the various third-party libraries that a
project relies on. Widely used examples include
• npm: The package manager for Node.js
• Composer: A tool for dependency management in PHP
• pip: The PyPA recommended tool for installing Python packages
• NuGet: The package manager for the Microsoft development platform including .NET
While package management is hardly a new idea, a practice that has only recently begun to see
widespread adoption is the application of this concept to the management of front-end web assets—the
JavaScript libraries, stylesheets, fonts, icons, and images that serve as the building blocks of modern web
applications. The need for such structure has become evident as the foundations on which modern web
applications are built have grown in complexity. Web applications that once relied on a small selection of
broadly defined, “one size fits all” third-party libraries (e.g., jQuery) now find themselves using the work
of many more smaller libraries, each with a tightly defined purpose. Benefits of this approach include
smaller modules that are easier to test, as well as an enhanced degree of flexibility on the part of the
parent application, which can more easily extend third-party libraries or replace them altogether when
necessary.
This chapter is designed to get you up and running quickly with Bower, the front-end package manager
whose roots lie in open source initiatives at Twitter. Topics covered include
• Installing and configuring Bower
• Adding Bower to a project
• Finding, adding, and removing packages
• Semantic Versioning
• Managing the dependency chain
• Creating Bower packages
www.it-ebooks.info
Chapter 1 ■ Bower
Getting Started
All interaction with Bower occurs through a command-line utility that can be installed via npm. If you do not
already have Bower installed, you should install it before you continue, as shown in Listing 1-1.
■■Note Node’s package manager (npm) allows users to install packages in one of two contexts: locally
or globally. In this example, bower is installed within the global context, which is typically reserved for
command-line utilities.
Configuring Bower
Bower is configured on a per-project basis through a single (optional) JSON file that exists in your project’s
root folder, .bowerrc. For the purposes of this introduction, we’ll only look at the most frequently changed
setting within this file (see Listing 1-2).
Listing 1-2. The .bowerrc File from This Chapter’s Sample Project
// example-bootstrap/.bowerrc
{
"directory": "./public/bower_components"
}
By default, Bower will store your project’s dependencies in the bower_components folder. You will likely
want to change this location, and the directory setting allows you to do so.
The Manifest
Bower provides developers with a single point of entry from which third-party libraries can be found, added,
upgraded, and removed. As these actions occur, Bower updates a JSON file referred to as the “manifest”
with an up-to-date list of the project’s dependencies. The Bower manifest for this chapter’s sample project is
shown in Listing 1-3. In this example, Bower is aware of a single dependency, the Bootstrap CSS framework.
{
"name": "example-bootstrap",
"version": "1.0.0",
"homepage": "https://github.com/username/project",
www.it-ebooks.info
Chapter 1 ■ Bower
"authors": [
"John Doe <[email protected]>"
],
"dependencies": {
"bootstrap": "3.2.0"
}
}
If we were to accidentally delete all of our project’s dependencies by removing the public/bower_
components folder, we could easily restore our project to its previous state by issuing a single command, as
shown next. Doing so would cause Bower to compare its manifest with our project’s current file structure,
determine what dependencies are missing, and restore them.
$ bower install
As a result of this behavior, we have the option of ignoring our project’s /public/bower_components
folder within version control. By committing only Bower’s manifest, and not the dependencies themselves,
our project’s source code can be kept in a cleaner state, containing only files that pertain directly to our
own work.
■■Note Opinions differ as to whether or not keeping your project’s dependencies out of version control is
a good idea. On the one hand, doing so results in a cleaner repository. On the other hand, this also opens the
door to potential problems should you (or the Bower registry, or GitHub, etc.) encounter connection issues.
The general consensus seems to be that if you are working on a “deployable” project (i.e., an application,
not a module), committing your dependencies is the preferred approach. Otherwise, keeping your project’s
dependencies out of version control is probably a good idea.
$ bower init
Finding Packages
One of the primary ways in which Bower can improve your development workflow is by providing you with a
centralized registry from which third-party libraries can be found. To search the Bower registry, simply pass
the search argument to Bower, followed by a keyword to search for, as shown in Listing 1-4. In this example,
only a short excerpt from the returned list of search results is shown.
www.it-ebooks.info
Chapter 1 ■ Bower
Search results:
jquery git://github.com/jquery/jquery.git
jquery-ui git://github.com/components/jqueryui
jquery.cookie git://github.com/carhartl/jquery-cookie.git
jquery-placeholder git://github.com/mathiasbynens/jquery-placeholder.git
Adding Packages
Each search result includes the name under which the package was registered, along with the URL of the
GitHub repository at which it can be accessed directly. Once we have located the desired package, we can
add it to our project as shown in Listing 1-5.
jquery#2.1.3 public/bower_components/jquery
■■Note Bower does not host any of the files associated with the packages contained within its registry; it
defers to GitHub for that responsibility. While it is possible to host packages at any URL, the majority of public
packages are found on GitHub.
Take note of the fact that in Listing 1-5, we pass the --save option to Bower’s install command. By
default, the install command will add the requested package to a project without updating its manifest.
By passing the --save option, we instruct Bower to permanently store this package within its list of
dependencies.
Listing 1-6 shows the HTML from this chapter’s sample project. After adding jQuery to our project via
Bower, we can load it via a script tag as we would any other library.
www.it-ebooks.info
Chapter 1 ■ Bower
Listing 1-6. HTML from Our Sample Project That References the jQuery Package Just Added
// example-jquery/public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bower Example</title>
</head>
<body>
<div id="container"></div>
<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<script>
$(document).ready(function() {
$('#container').html('<p>Hello, world!</p>');
});
</script>
</body>
</html>
Development Dependencies
By default, any packages that Bower installs are considered to be “production” dependencies, but this
behavior can be overridden by passing the --save-dev option. Doing so will flag any installed packages as
“development” dependencies. Such packages are intended for development purposes only, not for the final
users of a project.
Once we are ready to deploy our application to a production environment, we can instruct Bower to
install only the production dependencies, as shown next, resulting in a leaner build that does not contain
extraneous files of no interest to the end user.
Removing Packages
The process of removing Bower packages is straightforward. As in previous examples, we pass the --save
argument to update Bower’s manifest to reflect this change:
www.it-ebooks.info
Chapter 1 ■ Bower
Semantic Versioning
If you were to install jQuery (as shown in Listing 1-5) and then look at the contents of your project’s Bower
manifest, you would see something that resembles Listing 1-7.
The version number 2.1.3 that we see in Listing 1-7 (ignore the ~ character for a moment) is what is
known as a semantic version number (semver for short). Semantic versioning is a standard that describes
a common format that developers can use to assign version numbers to their projects. The format is
illustrated here:
The semantic versioning format dictates that developers create clearly defined (either by
documentation or by clear, self-documenting code) APIs that provide users with a single point of entry into a
library. New projects that are just getting off the ground typically begin at version 0.0.0 and work their way up
incrementally as new releases are created. A project with a version number below 1.0.0 is considered to be
under heavy development and, as such, is allowed to make sweeping changes to its API without altering its
major version number. A project with a version number at or above 1.0.0, however, is guided by the following
set of rules that determines how version numbers should be changed:
• A project’s major version number should change when updates occur that result in
breaking changes with how users have interacted with a project’s API in previous
versions.
• A project’s minor version number should change when new features are added to a
project in a way that is backward-compatible (i.e., the existing API is not broken).
• A project’s patch version number should change when backward-compatible bug
fixes are introduced.
These rules provide developers with insight into the extent of changes that have occurred between any
two versions. Such insight will prove useful as our Bower manifest grows and we begin adding more and
more dependencies to our project.
■■Note The ~ character shown in Listing 1-7 tells Bower that whenever the install command is run, it is
allowed to automatically install future versions of jQuery that are “relatively close to” version 2.1.3. If the use of
the phrases “relatively close to” and “automatically install” within the same sentence makes your skin crawl,
you’re not alone. Best practices suggest that you avoid the “~X.Y.Z” format when referencing dependencies
with Bower. Instead, you are better off specifying the exact version of the dependency that you wish to include
within your project. As future updates are released, you can then manually review them and make your own
decisions regarding if and when to update. Subsequent examples within this chapter will follow this advice.
www.it-ebooks.info
Chapter 1 ■ Bower
Listing 1-8. Installing and Listing the Various Bower Packages Required by Our Sample Project
$ bower install
bower bootstrap#3.2.0 cached git://github.com/twbs/bootstrap.git#3.2.0
bower bootstrap#3.2.0 validate 3.2.0 against git://github.com/twbs/bootstrap.git#3.2.0
bower jquery#>= 1.9.0 cached git://github.com/jquery/jquery.git#2.1.3
bower jquery#>= 1.9.0 validate 2.1.3 against git://github.com/jquery/jquery.git#>= 1.9.0
bower bootstrap#3.2.0 install bootstrap#3.2.0
bower jquery#>= 1.9.0 install jquery#2.1.3
bootstrap#3.2.0 public/bower_components/bootstrap
└── jquery#2.1.3
jquery#2.1.3 public/bower_components/jquery
$ bower list
bower check-new Checking for new versions of the project dependencies..
example-bootstrap#1.0.0 /opt/example-bootstrap
└─┬ bootstrap#3.2.0 (latest is 3.3.2)
└── jquery#2.1.3
Thanks to Bower, we now have a simple graph that describes the external dependencies that our project
relies on, as well as the relationships between them. We can see that we have a Bootstrap dependency,
which in turn has its own dependency on jQuery. Bower also prints the specific version of each component
that is currently installed.
■■Note Many third-party libraries are not entirely self-contained—they have dependencies of their own.
Bootstrap (with its reliance on jQuery) is one such example. When adding such a package, Bower is smart
enough to recognize these additional dependencies and will proactively add them to your project if they don’t
already exist. It is important to note, however, that unlike more sophisticated package managers (e.g., npm),
Bower stores all of its packages within a flat folder structure, which means you will occasionally run into version
conflicts, if you’re not careful.
In Listing 1-8, Bower has informed us that a version of Bootstrap (3.3.2) newer than the version currently
relied upon by our project (3.2.0) is available. We can update this dependency by modifying our project’s
manifest to refer to this newer version and rerunning the install command, as shown in Listing 1-9.
www.it-ebooks.info
Chapter 1 ■ Bower
Listing 1-9. Installing Bower Packages After Having Updated the Version of jQuery Our Project Relies On
$ bower install
bower bootstrap#3.3.2 cached git://github.com/twbs/bootstrap.git#3.3.2
bower bootstrap#3.3.2 validate 3.3.2 against git://github.com/twbs/bootstrap.git#3.3.2
bower bootstrap#3.3.2 install bootstrap#3.3.2
bootstrap#3.3.2 public/bower_components/bootstrap
└── jquery#2.1.3
www.it-ebooks.info
Chapter 1 ■ Bower
■■Note Bear in mind that Bower is intended to serve as a centralized registry for libraries and components
that other developers can use within their own projects. It is not intended to serve as a distribution mechanism
for entire applications.
Summary
Bower is a simple command-line utility that eases some of the tedious tasks associated with managing
front-end assets. Unlike well-known package managers from other platforms (e.g., Node’s npm), Bower
was not designed to handle the specific needs of any one platform or language; instead, it favors a rather
generic approach to the concept of package management. The developers who created Bower intentionally
set out to create a very simple tool for managing a wide variety of front-end assets—not just code, but also
stylesheets, fonts, images, and other, unforeseen future dependencies.
Developers working on trivial web applications with few external dependencies may find little value
in the benefits that Bower brings to the table. That said, trivial web applications have a tendency to quickly
evolve into complex web applications, and as that process occurs, developers often come to appreciate
Bower’s benefits.
Regardless of how complex (or simple) you consider your project to be, we would encourage you to
consider integrating Bower into your workflow sooner rather than later. As bitter experience has taught
us—the project itself. Err on the side of too little structure, and you risk creating an ever-increasing burden
of “technical debt” for which you must eventually pay a price. The process of striking a delicate balance
between these undesired alternatives is as much an art as it is a science. It is also a process that is never fully
learned, but must continuously be adapted as the tools of our trade change.
www.it-ebooks.info
Chapter 2
Grunt
I’m lazy. But it’s the lazy people who invented the wheel and the bicycle because they didn’t
like walking or carrying things.
—Lech Walesa, former president of Poland
In his book Programming Perl, Larry Wall (the well-known creator of the language) puts forth the idea that
all successful programmers share three important characteristics: laziness, impatience, and hubris. At first
glance, these traits all sound quite negative, but dig a little deeper, and you’ll find the hidden meaning in his
statement:
Laziness: Lazy programmers hate to repeat themselves. As a result, they tend to
put a lot of effort into creating useful tools that perform repetitive tasks for them.
They also tend to document those tools well, to spare themselves the trouble of
answering questions about them later.
Impatience: Impatient programmers have learned to expect much from their
tools. This expectation teaches them to create software that doesn’t just react to
the needs of its users, but that actually attempts to anticipate those needs.
Hubris: Good programmers take great pride in their work. It is this pride that
compels them to write software that others won’t want to criticize—the type of
work that we should all be striving for.
In this chapter, we’ll focus on the first of these three characteristics, laziness, along with Grunt, a
popular JavaScript “task runner” that supports developers in nurturing this trait by providing them with a
toolkit for automating the repetitive build tasks that often accompany software development, such as:
• Script and stylesheet compilation and minification
• Testing
• Linting
• Database migrations
• Deployments
11
www.it-ebooks.info
Chapter 2 ■ Grunt
In other words, Grunt helps developers who strive to work smarter, not harder. If that idea appeals to
you, read on. After you have finished this chapter, you will be well on your way toward mastering Grunt.
You’ll learn how to do the following in this chapter:
• Create configurable tasks that automate the repetitive aspects of software
development that accompany nearly every project
• Interact with the file system using simple yet powerful abstractions provided
by Grunt
• Publish Grunt plugins from which other developers can benefit and to which they
can contribute
• Take advantage of Grunt’s preexisting library of community-supported plugins, of
which over 4,400 examples exist at the time of writing
Installing Grunt
Before continuing, you should ensure that you have installed Grunt’s command-line utility. Available as an
npm package, the installation process is shown in Listing 2-1.
Gruntfile.js
At Grunt’s core lies the Gruntfile, a Node module saved as Gruntfile.js (see Listing 2-2) at the root of
your project. It’s within this file that we can load Grunt plugins, create our own custom tasks, and configure
them according to the needs of our project. Each time Grunt is run, its first order of business is to retrieve its
marching orders from this module.
12
www.it-ebooks.info
Chapter 2 ■ Grunt
module.exports = function(grunt) {
/**
* Configure the various tasks and plugins that we'll be using
*/
grunt.initConfig({
/* Grunt's 'file' API provides developers with helpful abstractions for
interacting with the file system. We'll take a look at these in greater
detail later in the chapter. */
'pkg': grunt.file.readJSON('package.json'),
'uglify': {
'development': {
'files': {
'build/app.min.js': ['src/app.js', 'src/lib.js']
}
}
}
});
/**
* Grunt plugins exist as Node packages, published via npm. Here, we load the
* 'grunt-contrib-uglify' plugin, which provides a task for merging and minifying
* a project's source code in preparation for deployment.
*/
grunt.loadNpmTasks('grunt-contrib-uglify');
/**
* Here we create a Grunt task named 'default' that does nothing more than call
* the 'uglify' task. In other words, this task will serve as an alias to
* 'uglify'. Creating a task named 'default' tells Grunt what to do when it is
* run from the command line without any arguments. In this example, our 'default'
* task calls a single, separate task, but we could just as easily have called
* multiple tasks (to be run in sequence) by adding multiple entries to the array
* that is passed.
*/
grunt.registerTask('default', ['uglify']);
/**
* Here we create a custom task that prints a message to the console (followed by
* a line break) using one of Grunt's built-in methods for providing user feedback.
* We'll look at these in greater detail later in the chapter.
*/
grunt.registerTask('hello-world', function() {
grunt.log.writeln('Hello, world.');
});
};
13
www.it-ebooks.info
Chapter 2 ■ Grunt
Tasks
Tasks are the basic building blocks of Grunt and are nothing more than functions that are registered with
assigned names via Grunt’s registerTask() method. In Listing 2-2, a simple hello-world task is shown that
prints a message to the console. This task can be called from the command line as shown in Listing 2-3.
Multiple Grunt tasks can also be run in sequence with a single command, as shown in Listing 2-4.
Each task will be run in the order in which it was passed.
The hello-world task that we’ve just seen serves as an example of a basic, stand-alone Grunt task. Such
tasks can be used to implement simple actions specific to the needs of a single project that you don’t intend
to re-use or share. Most of the time, however, you will find yourself interacting not with stand-alone tasks,
but instead with tasks that have been packaged as Grunt plugins and published to npm so that others can
reuse them and contribute to them.
Plugins
A Grunt plugin is a collection of configurable tasks (published as an npm package) that can be reused across
multiple projects. Thousands of such plugins exist. In Listing 2-2, Grunt’s loadNpmTasks() method is used to
load the grunt-contrib-uglify Node module, a Grunt plugin that merges a project’s JavaScript code into a
single, minified file that is suitable for deployment.
■■Note A list of all available Grunt plugins can be found at http://gruntjs.com/plugins. Plugins whose
names are prefixed with contrib- are officially maintained by the developers behind Grunt.
14
www.it-ebooks.info
Chapter 2 ■ Grunt
Configuration
Grunt is known for emphasizing “configuration over code”: the creation of tasks and plugins whose
functionality is tailored by configuration that is specified within each project. It is this separation of code
from configuration that allows developers to create plugins that are easily reusable by others. Later in the
chapter, we’ll take a look at the various ways in which Grunt plugins and tasks can be configured.
Our project’s package.json file should now contain a grunt entry similar to that shown in Listing 2-5.
{
"name": "example-tasks",
"version": "1.0.0",
"devDependencies": {
"grunt": "0.4.5"
}
}
The final step toward integrating Grunt with our project is the creation of a Gruntfile (see Listing 2-6),
which should be saved within the root folder of the project. Within our Gruntfile, a single method is called,
loadTasks(), which is discussed in the upcoming section.
module.exports = function(grunt) {
grunt.loadTasks('tasks');
};
15
www.it-ebooks.info
Chapter 2 ■ Grunt
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
options: {
separator: ';'
},
dist: {
src: ['src/**/*.js'],
dest: 'dist/<%= pkg.name %>.js'
}
},
uglify: {
options: {
banner: '/*! <%= grunt.template.today("dd-mm-yyyy") %> */\n'
},
dist: {
files: {
'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
}
}
},
qunit: {
files: ['test/**/*.html']
},
jshint: {
files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
options: {
// options here to override JSHint defaults
globals: {
jQuery: true,
console: true,
module: true,
document: true
}
}
},
watch: {
files: ['<%= jshint.files %>'],
tasks: ['jshint', 'qunit']
}
});
16
www.it-ebooks.info
Chapter 2 ■ Grunt
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
};
The Gruntfile shown in Listing 2-7 is for a relatively simple project. We already find this example to be
slightly unwieldy, but within larger projects we have seen this file balloon to many times this size. The result
is an unreadable and difficult-to-maintain mess. Experienced developers would never write their code in a
way that combines functionality from across unrelated areas into a single, monolithic file, so why should we
approach our task runner any differently?
The secret to maintaining a sane Grunt structure lies with Grunt’s loadTasks() function, as shown in
Listing 2-6. In this example, the tasks argument refers to a tasks folder relative to our project’s Gruntfile.
Once this method is called, Grunt will load and execute each Node module it finds within this folder,
passing along a reference to the grunt object each time. This behavior provides us with the opportunity to
organize our project’s Grunt configuration as a series of separate modules, each responsible for loading and
configuring a single task or plugin. An example of one of these smaller modules is shown in Listing 2-8. This
task can be executed by running grunt uglify from the command line.
Listing 2-8. Example Module (uglify.js) Within Our New tasks Folder
// example-tasks/tasks/uglify.js
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.config('uglify', {
'options': {
'banner': '/*! <%= grunt.template.today("dd-mm-yyyy") %> */\n'
},
'dist': {
'files': {
'dist/app.min.js': ['src/index.js']
}
}
});
};
17
www.it-ebooks.info
Chapter 2 ■ Grunt
Managing Configuration
Grunt’s config() method serves as both a “getter” and a “setter” for configuration. In Listing 2-9, we see how
a basic Grunt task can access its configuration through the use of this method.
grunt.config('basic-task', {
'message': 'Hello, world.'
});
grunt.registerTask('basic-task', function() {
grunt.log.writeln(grunt.config('basic-task.message'));
});
};
■■Note In Listing 2-9, “dot notation” is used for accessing nested configuration values. In the same way,
dot notation can be used to set nested configuration values. If at any point Grunt encounters a path within the
configuration object that does not exist, Grunt will create a new, empty object without throwing an error.
Task Descriptions
Over time, projects have a tendency to grow in complexity. With this additional complexity often comes
new Grunt tasks. As new tasks are added, it’s often easy to lose track of what tasks are available, what they
do, and how they are called. Fortunately, Grunt provides us with a way to address this problem by assigning
descriptions to our tasks, as shown in Listing 2-10.
module.exports = function(grunt) {
grunt.config('basic-task', {
'message': 'Hello, world.'
});
18
www.it-ebooks.info
Chapter 2 ■ Grunt
};
Asynchronous Tasks
By default, Grunt tasks are expected to run synchronously. As soon as a task’s function returns, it
is considered finished. There will be times, however, when you find yourself interacting with other
asynchronous methods within a task, which must first complete before your task can hand control back over
to Grunt. The solution to this problem is shown in Listing 2-12. Within a task, a call to the async() method
will notify Grunt that it executes asynchronously. The method will return a callback function to be called
when our task has completed. Until this is done, Grunt will hold the execution of any additional tasks.
module.exports = function(grunt) {
grunt.registerTask('list-files', function() {
/**
* Grunt will wait until we call the `done()` function to indicate that our
* asynchronous task is complete.
*/
var done = this.async();
19
www.it-ebooks.info
Chapter 2 ■ Grunt
});
};
Task Dependencies
Complicated Grunt workflows are best thought of as a series of steps that work together to produce a final
result. In such situations, it can often be helpful to specify that a task requires one or more separate tasks to
precede it, as shown in Listing 2-13.
module.exports = function(grunt) {
grunt.registerTask('step-two', function() {
grunt.task.requires('step-one');
});
};
In this example, the step-two task requires that the step-one task run first before it can proceed. Any
attempt to call step-two directly will result in an error, as shown in Listing 2-14.
Listing 2-14. Grunt Reporting an Error When a Task Is Called Before Any Tasks on Which
It Depends Have Run
$ grunt step-two
Running "step-two" task
Warning: Required task "step-one" must be run first. Use --force to continue.
Multi-Tasks
In addition to basic tasks, Grunt offers support for what it calls “multi-tasks.” Multi-tasks are easily the most
complicated aspect of Grunt, so if you find yourself confused at first, you’re not alone. After reviewing a few
examples, however, their purpose should start to come into focus—at which point you’ll be well on your way
toward mastering Grunt.
Before we go any further, let’s take a look at a brief example (see Listing 2-15) that shows a Grunt
multi-task, along with its configuration.
20
www.it-ebooks.info
Chapter 2 ■ Grunt
module.exports = function(grunt) {
/**
* Our multi-task's configuration object. In this example, 'mammals'
* and 'birds' each represent what Grunt refers to as a 'target.'
*/
grunt.config('list-animals', {
'mammals': {
'animals': ['Cat', 'Zebra', 'Koala', 'Kangaroo']
},
'birds': {
'animals': ['Penguin', 'Sparrow', 'Eagle', 'Parrot']
}
});
grunt.registerMultiTask('list-animals', function() {
grunt.log.writeln('Target:', this.target);
grunt.log.writeln('Data:', this.data);
});
};
Multi-tasks are extremely flexible, in that they are designed to support multiple configurations (referred
to as “targets”) within a single project. The multi-task shown in Listing 2-15 has two targets: mammals and
birds. This task can be run against a specific target as shown in Listing 2-16.
Listing 2-16. Running the Grunt Multi-Task Shown in Listing 2-15 Against a Specific Target
$ grunt list-animals:mammals
Running "list-animals:mammals" (list-animals) task
Target: mammals
Data: { animals: [ 'Cat', 'Zebra', 'Koala', 'Kangaroo' ] }
Multi-tasks can also be called without any arguments, in which case they are executed multiple times,
once for each available target. Listing 2-17 shows the result of calling this task without specifying a target.
Listing 2-17. Running the Multi-Task Shown in Listing 2-15 Without Specifying a Target
$ grunt list-animals
Running "list-animals:mammals" (list-animals) task
Target: mammals
Data: { animals: [ 'Cat', 'Zebra', 'Koala', 'Kangaroo' ] }
21
www.it-ebooks.info
Chapter 2 ■ Grunt
In this example, our multi-task ran twice, once for each available target (mammals and birds). Notice
in Listing 2-15 that within our multi-task we referenced two properties: this.target and this.data. These
properties allow our multi-task to fetch information about the target that it is currently running against.
Multi-Task Options
Within a multi-task’s configuration object, any values stored under the options key (see Listing 2-18) receive
special treatment.
module.exports = function(grunt) {
grunt.config('list-animals', {
'options': {
'format': 'array'
},
'mammals': {
'options': {
'format': 'json'
},
'animals': ['Cat', 'Zebra', 'Koala', 'Kangaroo']
},
'birds': {
'animals': ['Penguin', 'Sparrow', 'Eagle', 'Parrot']
}
});
grunt.registerMultiTask('list-animals', function() {
switch (options.format) {
case 'array':
grunt.log.writeln(this.data.animals);
break;
case 'json':
grunt.log.writeln(JSON.stringify(this.data.animals));
break;
default:
grunt.fail.fatal('Unknown format: ' + options.format);
break;
}
});
};
22
www.it-ebooks.info
Chapter 2 ■ Grunt
Multi-task options provide developers with a mechanism for defining global options for a task, which
can then be overridden at the target level. In this example, a global format in which to list animals ('array')
is defined at the task level. The mammals target has chosen to override this value ('json'), while the birds
task has not. As a result, mammals will be displayed as JSON, while birds will be shown as an array due to its
inheritance of the global option.
The vast majority of Grunt plugins that you will encounter are configurable as multi-tasks. The flexibility
afforded by this approach allows you to apply the same task differently under different circumstances. A
frequently encountered scenario involves the creation of separate targets for each build environment. For
example, when compiling an application, you may want to modify the behavior of a task based on whether
you are compiling for a local development environment or in preparation for release to production.
Configuration Templates
Grunt configuration objects support the embedding of template strings, which can then be used to reference
other configuration values. The template format favored by Grunt follows that of the Lodash and Underscore
utility libraries, which are covered in further detail in a later chapter. For an example of how this feature can
be put to use, see Listing 2-19 and Listing 2-20.
Listing 2-19. Sample Gruntfile That Stores the Contents of Its Project’s package.json
File Under the pkg Key Within Grunt’s Configuration Object
// example-templates/Gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
'pkg': grunt.file.readJSON('package.json')
});
grunt.loadTasks('tasks');
grunt.registerTask('default', ['test']);
};
Listing 2-20. A Subsequently Loaded Task with Its Own Configuration That Is Able to Reference
Other Configuration Values Through the Use of Templates
// example-templates/tasks/test.js
module.exports = function(grunt) {
grunt.config('test', {
'banner': '<%= pkg.name %>-<%= pkg.version %>'
});
grunt.registerTask('test', function() {
grunt.log.writeln(grunt.config('test.banner'));
});
};
Listing 2-19 shows a sample Gruntfile that loads the contents of the project’s package.json file using
one of several built-in methods for interacting with the file system that are discussed in further detail later
in the chapter. The contents of this file are then stored under the pkg key of Grunt’s configuration object. In
Listing 2-20, we see a task that is able to directly reference this information through the use of configuration
templates.
23
www.it-ebooks.info
Chapter 2 ■ Grunt
Command-Line Options
Additional options can be passed to Grunt using the following format:
The example shown in Listing 2-21 demonstrates how a Grunt task can access this information via the
grunt.option() method. The result of calling this task is shown in Listing 2-22.
Listing 2-21. Simple Grunt Task That Counts to the Specified Number
// example-options/tasks/count.js
module.exports = function(grunt) {
grunt.registerTask('count', function() {
var limit = parseInt(grunt.option('limit'), 10);
if (isNaN(limit)) grunt.fail.fatal('A limit must be provided (e.g. --limit=10)');
console.log('Counting to: %s', limit);
for (var i = 1; i <= limit; i++) console.log(i);
});
};
Providing Feedback
Grunt provides a number of built-in methods for providing feedback to users during the execution of tasks,
a few of which you have already seen used throughout this chapter. While we won’t list all of them here,
several useful examples can be found in Table 2-1.
24
www.it-ebooks.info
Chapter 2 ■ Grunt
Table 2-1. Useful Grunt Methods for Displaying Feedback to the User
Method Description
grunt.log.write() Prints a message to the console
grunt.log.writeln() Prints a message to the console, followed by a newline character
grunt.log.oklns() Prints a success message to the console, followed by a newline character
grunt.log.error() Prints an error message to the console, followed by a newline character
grunt.log.subhead() Prints a bold message to the console, following by a newline character
grunt.log.debug() Prints a message to the console only if the --debug flag was passed
Handling Errors
During the course of task execution, errors can occur. When they do, it’s important to know how to
appropriately handle them. When faced with an error, developers should make use of Grunt’s error API,
which is easy to use, as it provides just two methods, shown in Table 2-2.
Method Description
grunt.fail.warn() Displays a warning and aborts Grunt immediately. Tasks will continue to run
if the --force option is passed.
grunt.fail.fatal() Displays a warning and aborts Grunt immediately.
Table 2-3. Useful Grunt Methods for Interacting with the File System
Method Description
grunt.file.read() Reads and returns file’s contents
grunt.file.readJSON() Reads a file’s contents, parsing the data as JSON, and returns the result
grunt.file.write() Writes the specified contents to a file, creating intermediate directories, if necessary
grunt.file.copy() Copies a source file to a destination path, creating intermediate directories, if
necessary
grunt.file.delete() Deletes the specified file path; deletes files and folders recursively
grunt.file.mkdir() Creates a directory, along with any missing intermediate directories
grunt.file.recurse() Recurses into a directory, executing a callback for every file that is found
25
www.it-ebooks.info
Chapter 2 ■ Grunt
Source-Destination Mappings
Many Grunt tasks that interact with the file system rely heavily on the concept of source-destination mappings,
a format that describes a set of files to be processed and a corresponding destination for each. Such mappings
can be tedious to construct, but thankfully Grunt provides helpful shortcuts that address this need.
Imagine for a moment that you are working on a project with a public folder located at its root. Within
this folder are the files to be served over the Web once the project is deployed, as shown in Listing 2-23.
.
└── public
└── images
├── cat1.jpg
├── cat2.jpg
└── cat3.png
As you can see, our project has an images folder containing three files. Knowing this, let’s take a look at
a few ways in which Grunt can help us iterate through these files.
In Listing 2-24, we find a Grunt multi-task similar to those we’ve recently been introduced to. The key
difference here is the presence of an src key within our task’s configuration. Grunt gives special attention
to multi-task configurations that contain this key, as we’ll soon see. When the src key is present, Grunt
provides a this.files property within our task that provides an array containing paths to every matching
file that is found via the node-glob module. The output from this task is shown in Listing 2-25.
Listing 2-24. Grunt Multi-Task with a Configuration Object Containing an src Key
// example-iterate1/tasks/list-files.js
module.exports = function(grunt) {
grunt.config('list-files', {
'images': {
'src': ['public/**/*.jpg', 'public/**/*.png']
}
});
grunt.registerMultiTask('list-files', function() {
this.files.forEach(function(files) {
grunt.log.writeln('Source:', files.src);
});
});
};
26
www.it-ebooks.info
Random documents with unrelated
content Scribd suggests to you:
humanity, and they are mere things and animals. Keep your
eye upon it, throttle it, kill it, stab it, do everything you can to
wound it—to impede its progress. Remember, before trusting
them to do anything for yourself, prepare to do it yourself.
Don’t turn over your business to anybody else. No man
deserves anything unless he is man enough to make an effort
to lift himself from oppression.’
“Then there was an interruption on account of some
storm-clouds. Everybody started to go away. Mr. Parsons
suggested that they adjourn over to Zepf’s Hall. Fielden said
no, the people were trying to get information, and he would
go on. And he went on: ‘Is it not a fact that we have no
choice as to our existence, for we can’t dictate what our labor
is worth? He that has to obey the will of another is a slave.
Can we do anything except by the strong arm of resistance?
The Socialists are not going to declare war, but I tell you war
has been declared upon us; and I ask you to get hold of
anything that will help to resist the onslaught of the enemy
and the usurper. The skirmish lines have met. People have
been shot. Men, women and children have not been spared by
the capitalists and minions of private capital. It has no mercy
—so ought you. You are called upon to defend yourselves,
your lives, your future. What matters it whether you kill
yourselves with work to get a little relief, or die on the battle-
field resisting the enemy? What is the difference? Any animal,
however loathsome, will resist when stepped upon. Are men
less than snails or worms? I have some resistance in me; I
know that you have, too. You have been robbed, and you will
be starved into a worse condition.’
“That is all I have. At that time some one alongside of me
asked if the police were coming. I was facing northeast,
looked down the street, and saw a file of police about the
middle of Randolph Street. At once I put my paper in my
pocket and ran right over to the northwest corner of Randolph
and Desplaines. Just when I reached the sidewalk, the front
rank of the police got to the southwest corner of Randolph
and Desplaines. I stood there until some of the police
marched by, and the first thing I knew I heard an explosion;
and the next thing there was a volley of fifteen or twenty or
thirty shots, and I thought it was about time to leave, so I
skinned down Randolph Street. While I was running I heard a
great lot of shots, and somebody tumbled right in front of me,
but I didn’t stop to see whether he was hurt. I didn’t see who
shot first. As to the temper of the crowd, it was just an
ordinary meeting.”
M. M. Thompson testified:
“I am at present employed in the dry-goods business of
Marshall Field & Co. Prior to the 4th of May last I was running
a grocery store at 108 South Desplaines. I was at the
Haymarket Square on the evening of May 4th. I walked west
on Randolph Street about half past seven o’clock, and
somebody handed me a circular headed ‘Revenge,’ and signed
‘Your Brothers.’ About twenty-five minutes to eight I got to the
corner of Desplaines and Randolph. I met Mr. Brazleton of the
Inter-Ocean. We talked about fifteen minutes. I asked the
time. It was ten minutes of eight. Brazleton pointed out to me
Mr. Schwab, who came rushing along Desplaines Street in a
great hurry. I then went over to the east side of Desplaines
Street. I walked up Desplaines Street near the corner of Lake,
and came back again to the alley back of Crane Bros’. and
stood just back of that alley. Then I saw Spies get up on the
wagon and he asked for Parsons. Parsons didn’t respond. He
then got down, and Schwab and Spies walked into that alley
at Crane Bros’., near which the wagon was situated. The first
word I heard between Schwab and Spies was ‘pistols;’ the
next word was ‘police.’ I think I heard ‘police’ twice, or ‘pistols’
twice. I then walked just a little nearer the edge of the alley,
and just then Spies said: ‘Do you think one is enough, or
hadn’t we better go and get more?’ I could hear no answer to
that. They then walked out of the alley and south on
Desplaines Street, and west on the north side of Randolph to
Halsted, and cut across the street and went over to the
southwest corner; they were there about three minutes, came
out of that crowd again and came back. On the way back, as
they neared Union Street, I heard the word ‘police’ again. Just
then I went past them, and Schwab said: ‘Now, if they come,
we will give it to them.’ Spies replied he thought they were
afraid to bother with them. They came on, and before they
got up near the wagon they met a third party, and they
bunched right together there, south of the alley, and appeared
to get right in a huddle; and there was something passed
between Spies and the third man—what it was I could not
say. This here (indicating picture of Schnaubelt, heretofore
identified) is, I think, the third man; I think his beard was a
little longer than in this picture; this is the picture of the third
man. I saw the third man on the wagon afterwards. Whatever
it was that Spies gave him, he stuck it in his pocket on the
right-hand side. Spies got up on the wagon, and I think that
third man got up right after him. I noticed him afterwards
sitting on the wagon, and that he kept his hands in his
pockets. I stayed there until Mr. Fielden commenced to speak;
then I left.
Louis Mahlendorf
testified as follows:
“I am a tinner by trade, at
292 Milwaukee Avenue, since
two years. I know the
defendant Engel since about
eight years. I made this
machine (referring to blasting-
machine) for Engel over a year
ago. I cut off the iron and
formed it up. Another
gentleman, a kind of heavy-set
man with long beard, was with
him when he ordered it. Mr.
Engel waited for it. He took it
away with him.”
ENGEL’S BLAST FURNACE.
From a Photograph.
Hermann Schuettler, a
detective connected with
the East Chicago Avenue Station, gave the facts with
reference to his arrest of Lingg, and his search of the
room on Sedgwick Street, with Officers Stift,
Loewenstein and Whalen:
“We searched a trunk and found a round lead bomb in a
stocking. The trunk was in the southeast room. In another
stocking I found a large navy revolver. Both revolver and
bomb were loaded. I turned them over to Capt. Schaack. We
found a ladle and some tools, a cold chisel and other articles.
This here (indicating) is the trunk I found in the room. The
letters ‘L. L.’ were on it at the time. I recollect a round
porcelain-lined blue cup made out of china that I found, and I
believe a file. In the closet underneath the baseboard we
found a lot of torn-off plaster. The lathing was sawed so you
could get your hand between the floor and the bottom of the
laths underneath. I saw those lead pipes (indicating) lying
between the house Lingg lived in and the next house to it, in
a small gangway. On the way to the Chicago Avenue Station I
asked Lingg why he wanted to kill me. He said: ‘Personally, I
have nothing against you, but if I had killed you and your
partner I would have been satisfied. I would have killed
myself if I had got away with you and your partner.”
ebookbell.com