Dave's evolution: Backbone → Angular → Shopify’s Batman.
Dave has quit job and became independent consultant.
Try different jobs before settling down.

Frontend devs feel stuck and dependent on backend logic and opinions.
Gain independence with your own tools.

Library has to hit critical mass to be successful.
Ember & Angular did it, CanJS sadly did not.

Job opportunity has to excite you.

Shopify uses Coffeescript and Sass.
Even big company can use new radical tools.

Working at Shopify is experience on massive project.
Try to get experience on project of different size.

Server-side frameworks often try to manage everything, not just server-side assets.
Rather aim for most modular workflow.

Heavy vs light server-side frameworks.

Split responsibilities between frontend and backend.
Backend can become just service-oriented.

Templates, MV*, building, … can be moved to frontend.

Separation of concerns is nowadays possible – browsers are becoming platforms instead of just browsers.
Utilize browser as whole platform, not just stupid browser.

HTML5 especially is becoming real platform and deployment target.

Switching between languages requires re-learning of whole server-side concepts.

Promote frontend tooling as first-class citizen in dev process.

Node is really awesome as tooling platform.

Node requires mental-shift, we need to consider where JS is run (browser or server).

RequireJS and Node overload semantics of require keyword.

Node Packaged Modules, not Node Package Manager.

Enables to download and publish packages.

package.json is metadata.

npm install will install dependencies defined in package.json

Shortcuts working with package.json

npm install —save, npm install —save-dev

Grunt is split into 2 packages – grunt & grunt-cli

Grunt CLI is runner, should be installed globally.

Gruntfile.js is set of configuration.

module.exports is node way of saying, that if someone will require this file, this is what he will get back.

When you run grunt from a command line, it will look for a Gruntfile and it will inject itself as a first argument.

Grunt supports coffeescript, JS is extra verbose for configuration files.

Typically, an artifact of web app is compressed, minified, cleaned source-code.

Grunt enables to write custom tasks.

registerTask is one-time task.
registerMultiTask – single configuration, multiple targets.

You can load tasks (plugins) from NPM or local file-system.

Use git crawl for tutorials.

GitX – nice git gui.

alias next – git crawl master

If you are going back in git history, git doesn’t delete files from working directory.

Tell a story with commits.

Rather observe than trying to keep up.

Typical dependency management for frontend apps.

When jQuery is loaded before Angular, it is used in Angular.

Practice pragmatism – use RequireJS only if its required.

Use default task.

Easy integrating libraries into one concenated file.

If you use Angular, you don’t have to use RequireJS, you can use smart concatenation.

Coffeescript not popular

When using Coffeescript, make a smart setup to integrate it.

Sneak Coffeescript for configuration files, then tests and then into whole app.

Use watch to auto live-reload.

Self-referential – <%= %>

Task can modify config at runtime, so understand when interpolation happens.

Tasks can use Node’s event emitter and avoid callback hell.

Less has speed benefits in Node environment.

Every task can has top level key options, and can be moved to target to override global options.

Multiple ways of defining files

You can override package source to your Github fork

Less can generate Data-URI – use both with SVG.

Evergreen browser - browser that continuously updates.

Sprites saves HTTP request, but tradeoff on creating. Solved by Compass – but still pain.

JSHint is customizable version on JSLint.

npm repo grunt-contrib-copy – open github repo

Write your own tasks

Express is simple HTTP server, something like Sinatra in Ruby.

Failing faster – know about errors in concenation, minification, …

Super reload by holding shift and clicking Reload button.

Base64 are highly compressible by gzip

Use Grunt to avoid tedious tasks.



No need to add grunt plugins to Gruntfile after installing them.

git checkout . – clear local changes

Integrate early for no surprises in production.

Separate concerns between vendor and app.

Bower is like npm for browser – dependencies live in bower.json – same structure as package.json.

.bowerrc – Where you want to place bower components.

ignore stuff is relevant for package authors.

Precompiling templates – best practice.


Max number of request per domain

Firefox 2:  2  
Firefox 3+: 6
Opera 9.26: 4
Opera 12:   6
Safari 3:   4
Safari 5:   6
IE 7:       2
IE 8:       6
IE 10:      8
Chrome:     6

Source maps

Debug as we have separate files, but use minified and concatenated file as in production.

Doesn’t impact performance, only opened when Devtools are opened.

Security vulnerabilities – anybody can look at the source code. BUT security through obscurity is not a real security. Benefits are much better.

Pushing source to production isn’t for everyone – has to meet company policy.


Lineman originated as a project in test-double.

Difference between Lineman and Yeoman

Lineman is focused on rich-client apps, yeoman has generators for broad range of web pages.

Test’em – like Karma, but simpler config file and light-weight.

Easily run on SauceLabs or BrowserStack.

lineman new your_project
cd new your_project
lineman run
lineman spec

Coffeescript is great for testing.

Fun-driven development

Expect style assertions come with Jasmine by default.

Lineman doesn’t do code generators – it uses templates instead of scaffolds.

Set Log XMLHttpRequest in Chrome DevTools Console

Test cases written in Coffeescript.

Protractor for E2E testing (replaced Angular Scenario Runner)

brew install chromedriver – alternative for selenium web-driver.

brew install selenium-standalone-server

Will run selenium host in the background, you can connect any test-suite.

Don’t write over assertive test for E2E.

Stub out your API

PushState simulation

Any request that isn’t catched by our server.js go to this apiProxy

Prefixing API is a best practice – detects if request is made by search engine and renders the page with PhantomJS.