0
Dependencies & Modules

Wednesday, January 8, 14

To handle dependencies and modules in a simple way we need some proper t...
Wednesday, January 8, 14

Then talk a bit about Browserify.
Wednesday, January 8, 14

I’ve been writing JS for quite a while, then I was off doing mostly backend & Android for while....
Web Sites vs Web Apps
What’s the difference?

Wednesday, January 8, 14

I find this quite interesting. And is there a diffe...
We’re all building sites that people visit, do
something, and leave. Differentiating websites vs. web
apps is no good to a...
Why do you want to make that distinction?
What benefit do you gain by arbitrarily dividing
the entire web into two classes?...
A lot of people ignore new JavaScript tools, methods
or approaches because those are just for “web apps.”
– Jack Franklin
...
Dev Environment
•

Module System: A way to programmatically load scripts when they’re
needed.

•

Package Manager: Fetch s...
Modules
A way to programmatically load scripts when they’re needed

Wednesday, January 8, 14

Let’s start with modules.
Wh...
<script
<script
<script
<script
<script
<script
<script
<script
<script
<script

type="text/javascript"
type="text/javascr...
SRC_DIR = src
BUILD_DIR = build
JS_SERVER_FILES = $(SRC_DIR)/js/namespace.js
! $(SRC_DIR)/js/vendor/buffer-loader.js
! $(S...
<% if (production) { %>
<script type="text/javascript"
<% } else { %>
<script type="text/javascript"
<script type="text/ja...
The Problem
•
•
•
•

Code complexity grows as the site gets bigger
Assembly gets harder
Developer wants discrete JS files/m...
Current Landscape
•
•
•
•
•
•

Globals
Globals + Namespace
AMD (Asynchronous Module Definition)
CommonJS
UMD (Universal Mod...
var isEven = function(i) {
return i % 2 === 0;
};

Wednesday, January 8, 14

I like small bits of code that can be separat...
Globals

Wednesday, January 8, 14
even.js

var isEven = function(i) {
return i % 2 === 0;
};

Wednesday, January 8, 14
app.js
console.log(1,
console.log(2,
console.log(3,
console.log(4,

Wednesday, January 8, 14

isEven(1));
isEven(2));
isEv...
index.html
<!doctype html>
<script src="even.js"></script>
<script src="app.js"></script>

Wednesday, January 8, 14
Globals + Namespace

Wednesday, January 8, 14
app-even.js
var App = App || {};
App.isEven = function(i) {
return i % 2 === 0;
};

Wednesday, January 8, 14
app.js
var App = App || {};
console.log(1,
console.log(2,
console.log(3,
console.log(4,

Wednesday, January 8, 14

App.isE...
index.html

<!doctype html>
<script src="app-even.js"></script>
<script src="app.js"></script>

Wednesday, January 8, 14
AMD
Asynchronous Module Definition
With Require.JS

Wednesday, January 8, 14
even.js
define([], function() {
var isEven = function(i) {
return i % 2 === 0;
};
return isEven;
});

Wednesday, January 8...
app.js
require(['even'], function(even){
console.log(1, even(1));
console.log(2, even(2));
console.log(3, even(3));
consol...
index.html

<!doctype html>
<script data-main="js/app.js"
src="js/require.js"></script>

Wednesday, January 8, 14
//Allow for anonymous modules
if (typeof name !== 'string') {
//Adjust args appropriately
callback = deps;
deps = name;
na...
Makefile / Build step

build:
! node r.js -o name=app out=js/app-built.js baseUrl=./js
build-even:
! node r.js -o name=even...
CommonJS / Node.js

Wednesday, January 8, 14
even.js
var isEven = function(i) {
return i % 2 === 0;
};
module.exports = isEven;

Wednesday, January 8, 14
app.js
var isEven = require('./even');
console.log(1,
console.log(2,
console.log(3,
console.log(4,

Wednesday, January 8, ...
UMD
Universal Module Definition

Wednesday, January 8, 14
var shim = {};
if (typeof(exports) === 'undefined') {
if(typeof define == 'function' && typeof define.amd == 'object' && d...
var shim = {};
if (typeof(exports) === 'undefined') {
if(typeof define == 'function' && typeof define.amd == 'object' && d...
Makefile / Build step
build:
! cat header.js even.js footer.js > even-lib.js

Wednesday, January 8, 14
ES6
export function isEven() {}
import { isEven } from 'even';

Wednesday, January 8, 14

It’s not here yet.
AMD & CommonJS

Wednesday, January 8, 14

For me, there’s really only two options here. AMD or CommonJS. Both of these sol...
Wednesday, January 8, 14

Various alternatives around for common js, as far as I know there is only require js for AMD
CommonJS

Wednesday, January 8, 14

Various alternatives around for common js, as far as I know there is only require js f...
CommonJS

AMD

Wednesday, January 8, 14

Various alternatives around for common js, as far as I know there is only require...
CommonJS

AMD

Wednesday, January 8, 14

Various alternatives around for common js, as far as I know there is only require...
What I want
•
•
•
•
•
Wednesday, January 8, 14

Simple
Active community
No complicated build environment
Works with existi...
require('modules') in the browser

Wednesday, January 8, 14

http://browserify.org/, substack
Demo

Wednesday, January 8, 14
Browserify
•
•
•

Wednesday, January 8, 14

require & npm modules in the browser
Browser versions of core node modules (ev...
How does it work?
•
•
•
•
Wednesday, January 8, 14

Small wrapper for the require function
Build process that keeps track ...
;
(function e(t, n, r) {
function s(o, u) {
if (!n[o]) {
if (!t[o]) {
var a = typeof require == "function" && require;
if ...
voxel.js
http://voxeljs.com/

Wednesday, January 8, 14
Dependencies
Package Manager
Fetch scripts, taking dependencies into account

Wednesday, January 8, 14
Current Landscape
•
•
•
•
•
•

Ender (http://ender.jit.su/)
Volo (http://volojs.org/)
Jam (http://jamjs.org/)
Bower (http:...
Transformations
•
•
•
•
•

AMD via deamdify
Bower via debowerify
Global via deglobalify
ES6 via es6ify
& more

Wednesday, ...
{
"name": "bower-demo",
"version": "0.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo "Error: no t...
{
"name": "bower-demo",
"main": "index.js",
"version": "0.0.0",
"authors": [
"Johan Nilsson <johan@markupartist.com>"
],
"...
var $ = require('jquery');
$('body').append('<p>bla bla</p>');

Wednesday, January 8, 14
browserify index.js -t debowerify > bundle.js

Wednesday, January 8, 14
Additional Tools
•
•
•
•
Wednesday, January 8, 14

Watchify – Watch mode for browserify builds
Beefy – Local development s...
Johan Nilsson
johan@markupartist.com
@johanni

Wednesday, January 8, 14
Upcoming SlideShare
Loading in...5
×

JavaScript Dependencies, Modules & Browserify

6,146

Published on

JavaScript dependencies & modules

Introduction to Browserify and how to use CommonJS/Node.js modules in the browser. We'll start with a brief look at the current landscape of handling dependencies and modules.

Talk at sthlm.js 2014-01-07, http://www.meetup.com/sthlm-js/events/156429912/

Demos & code examples; https://github.com/johannilsson/sthlmjs-1401

Published in: Technology, Design
0 Comments
16 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
6,146
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
32
Comments
0
Likes
16
Embeds 0
No embeds

No notes for slide

Transcript of "JavaScript Dependencies, Modules & Browserify"

  1. 1. Dependencies & Modules Wednesday, January 8, 14 To handle dependencies and modules in a simple way we need some proper tooling.
  2. 2. Wednesday, January 8, 14 Then talk a bit about Browserify.
  3. 3. Wednesday, January 8, 14 I’ve been writing JS for quite a while, then I was off doing mostly backend & Android for while. This is Theo, I felt like him here towards JS for a while I feel that the tools around for JS has increased and grown in complexity quite fast. It also feels like it is changing quite rapid. This is also what attracts me to JS, for me it feels like this is where a lot of creativity and innovation is happening. But picking the right tools is a/has been challenge.
  4. 4. Web Sites vs Web Apps What’s the difference? Wednesday, January 8, 14 I find this quite interesting. And is there a difference and why do we make a difference?
  5. 5. We’re all building sites that people visit, do something, and leave. Differentiating websites vs. web apps is no good to anyone. – Jack Franklin https://speakerdeck.com/jackfranklin/port80-practical-javascripting Wednesday, January 8, 14
  6. 6. Why do you want to make that distinction? What benefit do you gain by arbitrarily dividing the entire web into two classes? – Jeremy Keith http://adactio.com/journal/6246/ Wednesday, January 8, 14
  7. 7. A lot of people ignore new JavaScript tools, methods or approaches because those are just for “web apps.” – Jack Franklin https://speakerdeck.com/jackfranklin/port80-practical-javascripting Wednesday, January 8, 14 I’ve done this for too long.
  8. 8. Dev Environment • Module System: A way to programmatically load scripts when they’re needed. • Package Manager: Fetch scripts from online sources like GitHub, taking dependencies into account. • Build Tool: Combine scripts and other assets together into something usable by browsers. http://dailyjs.com/2013/01/28/components/ Wednesday, January 8, 14 And to handle modules and dependencies properly we need to use proper tools to cope with a modern development environment
  9. 9. Modules A way to programmatically load scripts when they’re needed Wednesday, January 8, 14 Let’s start with modules. What is a module? Keep it simple, it’s basically just a script that we can load whenever we need it.
  10. 10. <script <script <script <script <script <script <script <script <script <script type="text/javascript" type="text/javascript" type="text/javascript" type="text/javascript" type="text/javascript" type="text/javascript" type="text/javascript" type="text/javascript" type="text/javascript" type="text/javascript" src="/js/namespace.js"></script> src="/js/vendor/buffer-loader.js"></script> src="/js/vendor/requestanimframe.js"></script> src="/js/vendor/stats.min.js"></script> src="/js/vendor/minpubsub.js"></script> src="/js/app.js"></script> src="/js/utils.js"></script> src="/js/sound.js"></script> src="/js/shape.js"></script> src="/js/main.js"></script> Wednesday, January 8, 14 We can easily do this by separating our code into various scripts. It gets a bit troublesome to manage this though. For me this way hinders me from playing around and prototyping and testing things out while developing.
  11. 11. SRC_DIR = src BUILD_DIR = build JS_SERVER_FILES = $(SRC_DIR)/js/namespace.js ! $(SRC_DIR)/js/vendor/buffer-loader.js ! $(SRC_DIR)/js/vendor/requestanimframe.js ! $(SRC_DIR)/js/vendor/stats.min.js ! $(SRC_DIR)/js/vendor/minpubsub.js ! $(SRC_DIR)/js/app.js ! $(SRC_DIR)/js/utils.js ! $(SRC_DIR)/js/sound.js ! $(SRC_DIR)/js/shape.js ! $(SRC_DIR)/js/main.js JS_BUNDLE = $(BUILD_DIR)/app.js BUILD_BUNDLE = $(BUILD_DIR)/app-min.js .DEFAULT_GOAL := all all: bundle ! java -jar $(GCC_COMPRESSOR) $(GCC_OPTION) --js=$(JS_BUNDLE) -js_output_file=$(BUILD_BUNDLE) debug: bundle ! cat $(JS_FILES) >> $(JS_BUNDLE) Wednesday, January 8, 14 To assemble this for production we would need a build script. This is a Makefile from an old project of mine. Sure we can have grunt but it is still configuration clean: we need to add. ! rm -Rf $(BUILD_DIR)/* For me this isn’t really prototyping friendly.
  12. 12. <% if (production) { %> <script type="text/javascript" <% } else { %> <script type="text/javascript" <script type="text/javascript" <script type="text/javascript" <script type="text/javascript" <script type="text/javascript" <script type="text/javascript" <script type="text/javascript" <script type="text/javascript" <script type="text/javascript" <script type="text/javascript" <% } %> src="/js/app-min.js"></script> src="/js/namespace.js"></script> src="/js/vendor/buffer-loader.js"></script> src="/js/vendor/requestanimframe.js"></script> src="/js/vendor/stats.min.js"></script> src="/js/vendor/minpubsub.js"></script> src="/js/app.js"></script> src="/js/utils.js"></script> src="/js/sound.js"></script> src="/js/shape.js"></script> src="/js/main.js"></script> Wednesday, January 8, 14 And we add a conditional to check if we are in production. Personally I don’t like this since it means that we’re during development will most likely run a different version of the site than we will in production.
  13. 13. The Problem • • • • Code complexity grows as the site gets bigger Assembly gets harder Developer wants discrete JS files/modules Deployment wants optimized code in just one or a few HTTP calls http://requirejs.org/docs/why.html#1 Wednesday, January 8, 14 Why do we want modules. Require.JS outlines a few arguments on there website. We basically want it because we need better structure in our code.
  14. 14. Current Landscape • • • • • • Globals Globals + Namespace AMD (Asynchronous Module Definition) CommonJS UMD (Universal Module Definition) (ES6) Wednesday, January 8, 14 Alternatives for modules, not taking framework specific ones like Angular into account.
  15. 15. var isEven = function(i) { return i % 2 === 0; }; Wednesday, January 8, 14 I like small bits of code that can be separated and re-used. Here’s a quite simple re-usable bit of code but is short enough to fit a slide. Simple re-usable code
  16. 16. Globals Wednesday, January 8, 14
  17. 17. even.js var isEven = function(i) { return i % 2 === 0; }; Wednesday, January 8, 14
  18. 18. app.js console.log(1, console.log(2, console.log(3, console.log(4, Wednesday, January 8, 14 isEven(1)); isEven(2)); isEven(3)); isEven(4));
  19. 19. index.html <!doctype html> <script src="even.js"></script> <script src="app.js"></script> Wednesday, January 8, 14
  20. 20. Globals + Namespace Wednesday, January 8, 14
  21. 21. app-even.js var App = App || {}; App.isEven = function(i) { return i % 2 === 0; }; Wednesday, January 8, 14
  22. 22. app.js var App = App || {}; console.log(1, console.log(2, console.log(3, console.log(4, Wednesday, January 8, 14 App.isEven(1)); App.isEven(2)); App.isEven(3)); App.isEven(4));
  23. 23. index.html <!doctype html> <script src="app-even.js"></script> <script src="app.js"></script> Wednesday, January 8, 14
  24. 24. AMD Asynchronous Module Definition With Require.JS Wednesday, January 8, 14
  25. 25. even.js define([], function() { var isEven = function(i) { return i % 2 === 0; }; return isEven; }); Wednesday, January 8, 14
  26. 26. app.js require(['even'], function(even){ console.log(1, even(1)); console.log(2, even(2)); console.log(3, even(3)); console.log(4, even(4)); }); Wednesday, January 8, 14
  27. 27. index.html <!doctype html> <script data-main="js/app.js" src="js/require.js"></script> Wednesday, January 8, 14
  28. 28. //Allow for anonymous modules if (typeof name !== 'string') { //Adjust args appropriately callback = deps; deps = name; name = null; } //This module may not have dependencies if (!isArray(deps)) { callback = deps; deps = null; } require.js //If no name, and callback is a function, then figure out if it a //CommonJS thing with dependencies. if (!deps && isFunction(callback)) { deps = []; //Remove comments from the callback string, //look for require calls, and pull them into the dependencies, //but only if there are function args. if (callback.length) { callback .toString() .replace(commentRegExp, '') .replace(cjsRequireRegExp, function (match, dep) { deps.push(dep); }); //May be a CommonJS thing even without require calls, but still //could use exports, and module. Avoid doing exports and module //work though if it just needs require. //REQUIRES the function to expect the CommonJS variables in the //order listed below. deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps); } } //If in IE 6-8 and hit an anonymous define() call, do the interactive //work. if (useInteractive) { node = currentlyAddingScript || getInteractiveScript(); if (node) { if (!name) { name = node.getAttribute('data-requiremodule'); } context = contexts[node.getAttribute('data-requirecontext')]; } } //Always save off evaluating the def call until the script onload handler. //This allows multiple modules to be in a file without prematurely //tracing dependencies, and allows for anonymous module support, //where the module name is not known until the script onload event //occurs. If no context, use the global queue, and get it processed //in the onscript load callback. (context ? context.defQueue : globalDefQueue).push([name, deps, callback]); }; define.amd = { jQuery: true }; Wednesday, January 8, 14 /** * Executes the text. Normally just uses eval, but can be modified * to use a better, environment-specific call. Only used for transpiling * loader plugins, not for plain JS modules. * @param {String} text the text to execute/evaluate. */ req.exec = function (text) { /*jslint evil: true */ return eval(text); }; Quite a massive file that is required //Set load these files. Not sure exactly what goes on here, but it works. to up with config info. req(cfg); }(this));
  29. 29. Makefile / Build step build: ! node r.js -o name=app out=js/app-built.js baseUrl=./js build-even: ! node r.js -o name=even out=js/even-built.js baseUrl=./js Wednesday, January 8, 14 For production you might want to bundle your files into one bundle. You still depend on require.js though. And you will have one setup for development and another one for production.
  30. 30. CommonJS / Node.js Wednesday, January 8, 14
  31. 31. even.js var isEven = function(i) { return i % 2 === 0; }; module.exports = isEven; Wednesday, January 8, 14
  32. 32. app.js var isEven = require('./even'); console.log(1, console.log(2, console.log(3, console.log(4, Wednesday, January 8, 14 isEven(1)); isEven(2)); isEven(3)); isEven(4));
  33. 33. UMD Universal Module Definition Wednesday, January 8, 14
  34. 34. var shim = {}; if (typeof(exports) === 'undefined') { if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) { // we are in amd. shim.exports = {}; define(function() { return shim.exports; }); } else { // we are in a browser, define its namespaces in global shim.exports = typeof(window) !== 'undefined' ? window : _global; } } else { // we are in commonjs, define its namespaces in exports shim.exports = exports; } even-lib.js (function(exports) { var isEven = function(i) { return i % 2 === 0; }; if (typeof(exports) !== 'undefined') { exports.isEven = isEven; } })(shim.exports); })(this); header.js Wednesday, January 8, 14 This approach has been quite popular for library developers to be able to meet end users requirements.
  35. 35. var shim = {}; if (typeof(exports) === 'undefined') { if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) { // we are in amd. shim.exports = {}; define(function() { return shim.exports; }); } else { // we are in a browser, define its namespaces in global shim.exports = typeof(window) !== 'undefined' ? window : _global; } } else { // we are in commonjs, define its namespaces in exports shim.exports = exports; } even-lib.js header.js (function(exports) { even.js footer.js header.js var isEven = function(i) { return i % 2 === 0; }; if (typeof(exports) !== 'undefined') { exports.isEven = isEven; } })(shim.exports); })(this); Wednesday, January 8, 14 This approach has been quite popular for library developers to be able to meet end users requirements.
  36. 36. Makefile / Build step build: ! cat header.js even.js footer.js > even-lib.js Wednesday, January 8, 14
  37. 37. ES6 export function isEven() {} import { isEven } from 'even'; Wednesday, January 8, 14 It’s not here yet.
  38. 38. AMD & CommonJS Wednesday, January 8, 14 For me, there’s really only two options here. AMD or CommonJS. Both of these solves the issue of loading modules.
  39. 39. Wednesday, January 8, 14 Various alternatives around for common js, as far as I know there is only require js for AMD
  40. 40. CommonJS Wednesday, January 8, 14 Various alternatives around for common js, as far as I know there is only require js for AMD
  41. 41. CommonJS AMD Wednesday, January 8, 14 Various alternatives around for common js, as far as I know there is only require js for AMD
  42. 42. CommonJS AMD Wednesday, January 8, 14 Various alternatives around for common js, as far as I know there is only require js for AMD
  43. 43. What I want • • • • • Wednesday, January 8, 14 Simple Active community No complicated build environment Works with existing libraries, with none or minimal adaption Prototype friendly
  44. 44. require('modules') in the browser Wednesday, January 8, 14 http://browserify.org/, substack
  45. 45. Demo Wednesday, January 8, 14
  46. 46. Browserify • • • Wednesday, January 8, 14 require & npm modules in the browser Browser versions of core node modules (events, stream, path, url, ...) Extendable
  47. 47. How does it work? • • • • Wednesday, January 8, 14 Small wrapper for the require function Build process that keeps track of dependencies Bundles to one file No global leakage
  48. 48. ; (function e(t, n, r) { function s(o, u) { if (!n[o]) { if (!t[o]) { var a = typeof require == "function" && require; if (!u && a) return a(o, !0); if (i) return i(o, !0); throw new Error("Cannot find module '" + o + "'") } var f = n[o] = { exports: {} }; t[o][0].call(f.exports, function (e) { var n = t[o][1][e]; return s(n ? n : e) }, f, f.exports, e, t, n, r) } return n[o].exports } var i = typeof require == "function" && require; for (var o = 0; o < r.length; o++) s(r[o]); return s })({ 1: [ function (require, module, exports) { var isEven = function (i) { return i % 2 === 0; }; module.exports = isEven; }, {} ], 2: [ function (require, module, exports) { var isEven = require('./even'); console.log(isEven(2)); }, { "./even": 1 } ] }, {}, [2]); Wednesday, January 8, 14
  49. 49. voxel.js http://voxeljs.com/ Wednesday, January 8, 14
  50. 50. Dependencies Package Manager Fetch scripts, taking dependencies into account Wednesday, January 8, 14
  51. 51. Current Landscape • • • • • • Ender (http://ender.jit.su/) Volo (http://volojs.org/) Jam (http://jamjs.org/) Bower (http://bower.io/) 7 000+ Component (http://component.io/) npm (http://npmjs.org) 53 000+ Wednesday, January 8, 14 Quite a few alternatives around. Not likely that all of these will survive. Currently it seems like Bower is the one getting more and more attraction for front end developers
  52. 52. Transformations • • • • • AMD via deamdify Bower via debowerify Global via deglobalify ES6 via es6ify & more Wednesday, January 8, 14
  53. 53. { "name": "bower-demo", "version": "0.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "author": "Johan Nilsson", "license": "BSD-2-Clause", "devDependencies": { "debowerify": "~0.5.1" } } Wednesday, January 8, 14
  54. 54. { "name": "bower-demo", "main": "index.js", "version": "0.0.0", "authors": [ "Johan Nilsson <johan@markupartist.com>" ], "license": "BSD-2-Clause", "private": true, "dependencies": { "jquery": "~2.0.3" } } Wednesday, January 8, 14
  55. 55. var $ = require('jquery'); $('body').append('<p>bla bla</p>'); Wednesday, January 8, 14
  56. 56. browserify index.js -t debowerify > bundle.js Wednesday, January 8, 14
  57. 57. Additional Tools • • • • Wednesday, January 8, 14 Watchify – Watch mode for browserify builds Beefy – Local development server grunt-browserify gulp-browserify
  58. 58. Johan Nilsson johan@markupartist.com @johanni Wednesday, January 8, 14
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×