Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Browserify All The Things

Browserify All The Things

This talk is about how to use browserify to develop front-end modular code using Common.JS, and how those modules should be documented, designed, and released using an automated build system. In order to explain these concepts I'll walk you through a few of my own open-source creations, highlighting interesting points as we go along.

Nicolás Bevacqua

August 28, 2014
Tweet

More Decks by Nicolás Bevacqua

Other Decks in Technology

Transcript

  1. ~function (window) { function sum (a, b) { return a

    + b; } window.math = {sum: sum}; }(this);
  2. Closures - Abuse global variables - Fine for tiny projects

    - Modularity is up to you - Manual dependency management
  3. define([], function () { function sum (a, b) { return

    a + b; } return { sum: sum }; }); math.js
  4. AMD Modules - Resolves dependency graph - Lacks a straightforward

    API - Drastic changes after you build - So. Much. Clutter.
  5. function sum (a, b) { return a + b; }

    ! export default {sum: sum}; math.js
  6. ES6 Modules - The Way Forward ™ - To use

    today, add a transpilation step
  7. ES6 Modules - The Way Forward ™ - To use

    today, add a transpilation step - Hard to interact with CJS modules
  8. ES6 Modules - The Way Forward ™ - To use

    today, add a transpilation step - Hard to interact with CJS modules - Not generally available / popular yet
  9. function sum (a, b) { return a + b; }

    module.exports = {sum:sum}; math.js
  10. var camel = /([a-z])([A-Z])/g; var hyphens = '$1-$2'; function parseStyles

    (styles) { if (typeof styles === 'string') { return styles; } return Object.keys(styles).map(function (key) { var prop = key.replace(camel, hyphens).toLowerCase(); return prop + ':' + styles[key]; }).join(';'); }
  11. var camel = /([a-z])([A-Z])/g; var hyphens = '$1-$2'; function parseStyles

    (styles) { if (typeof styles === 'string') { return styles; } return Object.keys(styles).map(function (key) { var prop = key.replace(camel, hyphens).toLowerCase(); return prop + ':' + styles[key]; }).join(';'); }
  12. var camel = /([a-z])([A-Z])/g; var hyphens = '$1-$2'; function parseStyles

    (styles) { if (typeof styles === 'string') { return styles; } return Object.keys(styles).map(function (key) { var prop = key.replace(camel, hyphens).toLowerCase(); return prop + ':' + styles[key]; }).join(';'); }
  13. var camel = /([a-z])([A-Z])/g; var hyphens = '$1-$2'; function parseStyles

    (styles) { if (typeof styles === 'string') { return styles; } return Object.keys(styles).map(function (key) { var prop = key.replace(camel, hyphens).toLowerCase(); return prop + ':' + styles[key]; }).join(';'); }
  14. var camel = /([a-z])([A-Z])/g; var hyphens = '$1-$2'; function parseStyles

    (styles) { if (typeof styles === 'string') { return styles; } return Object.keys(styles).map(function (key) { var prop = key.replace(camel, hyphens).toLowerCase(); return prop + ':' + styles[key]; }).join(';'); }
  15. var camel = /([a-z])([A-Z])/g; var hyphens = '$1-$2'; function parseStyles

    (styles) { if (typeof styles === 'string') { return styles; } return Object.keys(styles).map(function (key) { var prop = key.replace(camel, hyphens).toLowerCase(); return prop + ':' + styles[key]; }).join(';'); }
  16. module.exports = function (selector, styles) { var css = parseStyles(styles);

    var sheets = document.styleSheets; var s = sheets[sheets.length - 1]; var key = s.cssRules ? s.cssRules: s.rules; if (s.insertRule) { sheet.insertRule(selector + '{' + css + '}', key.length); } else if (sheet.addRule) { sheet.addRule(selector, css, key.length); } };
  17. module.exports = function (selector, styles) { var css = parseStyles(styles);

    var sheets = document.styleSheets; var s = sheets[sheets.length - 1]; var key = s.cssRules ? s.cssRules: s.rules; if (s.insertRule) { sheet.insertRule(selector + '{' + css + '}', key.length); } else if (sheet.addRule) { sheet.addRule(selector, css, key.length); } };
  18. module.exports = function (selector, styles) { var css = parseStyles(styles);

    var sheets = document.styleSheets; var s = sheets[sheets.length - 1]; var key = s.cssRules ? s.cssRules: s.rules; if (s.insertRule) { sheet.insertRule(selector + '{' + css + '}', key.length); } else if (sheet.addRule) { sheet.addRule(selector, css, key.length); } };
  19. module.exports = function (selector, styles) { var css = parseStyles(styles);

    var sheets = document.styleSheets; var s = sheets[sheets.length - 1]; var key = s.cssRules ? s.cssRules: s.rules; if (s.insertRule) { sheet.insertRule(selector + '{' + css + '}', key.length); } else if (sheet.addRule) { sheet.addRule(selector, css, key.length); } };
  20. module.exports = function (selector, styles) { var css = parseStyles(styles);

    var sheets = document.styleSheets; var s = sheets[sheets.length - 1]; var key = s.cssRules ? s.cssRules: s.rules; if (s.insertRule) { sheet.insertRule(selector + '{' + css + '}', key.length); } else if (sheet.addRule) { sheet.addRule(selector, css, key.length); } };
  21. function build () { var pkg = require('./package.json'); return browserify('./src/lib.js')

    .bundle({ debug: true, standalone: 'lib' }) .pipe(source('lib.js')) .pipe(streamify(header(ext, { pkg: pkg }))) .pipe(gulp.dest('./dist')) .pipe(streamify(rename('lib.min.js'))) .pipe(streamify(uglify())) .pipe(streamify(header(min, { pkg: pkg }))) .pipe(streamify(size())) .pipe(gulp.dest('./dist')); }
  22. function build () { var pkg = require('./package.json'); return browserify('./src/lib.js')

    .bundle({ debug: true, standalone: 'lib' }) .pipe(source('lib.js')) .pipe(streamify(header(ext, { pkg: pkg }))) .pipe(gulp.dest('./dist')) .pipe(streamify(rename('lib.min.js'))) .pipe(streamify(uglify())) .pipe(streamify(header(min, { pkg: pkg }))) .pipe(streamify(size())) .pipe(gulp.dest('./dist')); }
  23. function build () { var pkg = require('./package.json'); return browserify('./src/lib.js')

    .bundle({ debug: true, standalone: 'lib' }) .pipe(source('lib.js')) .pipe(streamify(header(ext, { pkg: pkg }))) .pipe(gulp.dest('./dist')) .pipe(streamify(rename('lib.min.js'))) .pipe(streamify(uglify())) .pipe(streamify(header(min, { pkg: pkg }))) .pipe(streamify(size())) .pipe(gulp.dest('./dist')); }
  24. function build () { var pkg = require('./package.json'); return browserify('./src/lib.js')

    .bundle({ debug: true, standalone: 'lib' }) .pipe(source('lib.js')) .pipe(streamify(header(ext, { pkg: pkg }))) .pipe(gulp.dest('./dist')) .pipe(streamify(rename('lib.min.js'))) .pipe(streamify(uglify())) .pipe(streamify(header(min, { pkg: pkg }))) .pipe(streamify(size())) .pipe(gulp.dest('./dist')); }
  25. function build () { var pkg = require('./package.json'); return browserify('./src/lib.js')

    .bundle({ debug: true, standalone: 'lib' }) .pipe(source('lib.js')) .pipe(streamify(header(ext, { pkg: pkg }))) .pipe(gulp.dest('./dist')) .pipe(streamify(rename('lib.min.js'))) .pipe(streamify(uglify())) .pipe(streamify(header(min, { pkg: pkg }))) .pipe(streamify(size())) .pipe(gulp.dest('./dist')); }
  26. function build () { var pkg = require('./package.json'); return browserify('./src/lib.js')

    .bundle({ debug: true, standalone: 'lib' }) .pipe(source('lib.js')) .pipe(streamify(header(ext, { pkg: pkg }))) .pipe(gulp.dest('./dist')) .pipe(streamify(rename('lib.min.js'))) .pipe(streamify(uglify())) .pipe(streamify(header(min, { pkg: pkg }))) .pipe(streamify(size())) .pipe(gulp.dest('./dist')); }
  27. function build () { var pkg = require('./package.json'); return browserify('./src/lib.js')

    .bundle({ debug: true, standalone: 'lib' }) .pipe(source('lib.js')) .pipe(streamify(header(ext, { pkg: pkg }))) .pipe(gulp.dest('./dist')) .pipe(streamify(rename('lib.min.js'))) .pipe(streamify(uglify())) .pipe(streamify(header(min, { pkg: pkg }))) .pipe(streamify(size())) .pipe(gulp.dest('./dist')); }
  28. function build () { var pkg = require('./package.json'); return browserify('./src/lib.js')

    .bundle({ debug: true, standalone: 'lib' }) .pipe(source('lib.js')) .pipe(streamify(header(ext, { pkg: pkg }))) .pipe(gulp.dest('./dist')) .pipe(streamify(rename('lib.min.js'))) .pipe(streamify(uglify())) .pipe(streamify(header(min, { pkg: pkg }))) .pipe(streamify(size())) .pipe(gulp.dest('./dist')); }
  29. function build () { var pkg = require('./package.json'); return browserify('./src/lib.js')

    .bundle({ debug: true, standalone: 'lib' }) .pipe(source('lib.js')) .pipe(streamify(header(ext, { pkg: pkg }))) .pipe(gulp.dest('./dist')) .pipe(streamify(rename('lib.min.js'))) .pipe(streamify(uglify())) .pipe(streamify(header(min, { pkg: pkg }))) .pipe(streamify(size())) .pipe(gulp.dest('./dist')); }
  30. function build () { var pkg = require('./package.json'); return browserify('./src/lib.js')

    .bundle({ debug: true, standalone: 'lib' }) .pipe(source('lib.js')) .pipe(streamify(header(ext, { pkg: pkg }))) .pipe(gulp.dest('./dist')) .pipe(streamify(rename('lib.min.js'))) .pipe(streamify(uglify())) .pipe(streamify(header(min, { pkg: pkg }))) .pipe(streamify(size())) .pipe(gulp.dest('./dist')); }
  31. function build () { var pkg = require('./package.json'); return browserify('./src/lib.js')

    .bundle({ debug: true, standalone: 'lib' }) .pipe(source('lib.js')) .pipe(streamify(header(ext, { pkg: pkg }))) .pipe(gulp.dest('./dist')) .pipe(streamify(rename('lib.min.js'))) .pipe(streamify(uglify())) .pipe(streamify(header(min, { pkg: pkg }))) .pipe(streamify(size())) .pipe(gulp.dest('./dist')); }
  32. gulp.task('watch', function() { var pattern = { glob: 'src/**/*.js' };

    watch(pattern, function () { gulp.start('build'); }); });
  33. gulp.task('watch', function() { var pattern = { glob: 'src/**/*.js' };

    watch(pattern, function () { gulp.start('build'); }); });
  34. gulp.task('watch', function() { var pattern = { glob: 'src/**/*.js' };

    watch(pattern, function () { gulp.start('build'); }); });
  35. gulp.task('watch', function() { var pattern = { glob: 'src/**/*.js' };

    watch(pattern, function () { gulp.start('build'); }); });
  36. gulp.task('bump-only', function () { // major.minor.patch var bumpType = process.env.BUMP

    || 'patch'; ! return gulp.src(['./package.json', './bower.json']) .pipe(bump({ type: bumpType })) .pipe(gulp.dest('./')); }); ! gulp.task('bump', ['bump-only'], build);
  37. gulp.task('bump-only', function () { // major.minor.patch var bumpType = process.env.BUMP

    || 'patch'; ! return gulp.src(['./package.json', './bower.json']) .pipe(bump({ type: bumpType })) .pipe(gulp.dest('./')); }); ! gulp.task('bump', ['bump-only'], build);
  38. gulp.task('bump-only', function () { // major.minor.patch var bumpType = process.env.BUMP

    || 'patch'; ! return gulp.src(['./package.json', './bower.json']) .pipe(bump({ type: bumpType })) .pipe(gulp.dest('./')); }); ! gulp.task('bump', ['bump-only'], build);
  39. gulp.task('bump-only', function () { // major.minor.patch var bumpType = process.env.BUMP

    || 'patch'; ! return gulp.src(['./package.json', './bower.json']) .pipe(bump({ type: bumpType })) .pipe(gulp.dest('./')); }); ! gulp.task('bump', ['bump-only'], build);
  40. gulp.task('bump-only', function () { // major.minor.patch var bumpType = process.env.BUMP

    || 'patch'; ! return gulp.src(['./package.json', './bower.json']) .pipe(bump({ type: bumpType })) .pipe(gulp.dest('./')); }); ! gulp.task('bump', ['bump-only'], build);
  41. gulp.task('bump-only', function () { // major.minor.patch var bumpType = process.env.BUMP

    || 'patch'; ! return gulp.src(['./package.json', './bower.json']) .pipe(bump({ type: bumpType })) .pipe(gulp.dest('./')); }); ! gulp.task('bump', ['bump-only'], build);
  42. gulp.task('tag', ['bump'], function () { var pkg = require('./package.json'); var

    v = 'v' + pkg.version; var message = 'Release ' + v; ! return gulp.src('./') .pipe(git.commit(message)) .pipe(git.tag(v, message)) .pipe(git.push('origin', 'master', '--tags')) .pipe(gulp.dest('./')); });
  43. gulp.task('tag', ['bump'], function () { var pkg = require('./package.json'); var

    v = 'v' + pkg.version; var message = 'Release ' + v; ! return gulp.src('./') .pipe(git.commit(message)) .pipe(git.tag(v, message)) .pipe(git.push('origin', 'master', '--tags')) .pipe(gulp.dest('./')); });
  44. gulp.task('tag', ['bump'], function () { var pkg = require('./package.json'); var

    v = 'v' + pkg.version; var message = 'Release ' + v; ! return gulp.src('./') .pipe(git.commit(message)) .pipe(git.tag(v, message)) .pipe(git.push('origin', 'master', '--tags')) .pipe(gulp.dest('./')); });
  45. gulp.task('tag', ['bump'], function () { var pkg = require('./package.json'); var

    v = 'v' + pkg.version; var message = 'Release ' + v; ! return gulp.src('./') .pipe(git.commit(message)) .pipe(git.tag(v, message)) .pipe(git.push('origin', 'master', '--tags')) .pipe(gulp.dest('./')); });
  46. gulp.task('tag', ['bump'], function () { var pkg = require('./package.json'); var

    v = 'v' + pkg.version; var message = 'Release ' + v; ! return gulp.src('./') .pipe(git.commit(message)) .pipe(git.tag(v, message)) .pipe(git.push('origin', 'master', '--tags')) .pipe(gulp.dest('./')); });
  47. gulp.task('tag', ['bump'], function () { var pkg = require('./package.json'); var

    v = 'v' + pkg.version; var message = 'Release ' + v; ! return gulp.src('./') .pipe(git.commit(message)) .pipe(git.tag(v, message)) .pipe(git.push('origin', 'master', '--tags')) .pipe(gulp.dest('./')); });
  48. gulp.task('tag', ['bump'], function () { var pkg = require('./package.json'); var

    v = 'v' + pkg.version; var message = 'Release ' + v; ! return gulp.src('./') .pipe(git.commit(message)) .pipe(git.tag(v, message)) .pipe(git.push('origin', 'master', '--tags')) .pipe(gulp.dest('./')); });
  49. var cp = require('child_process'); var spawn = cp.spawn; ! gulp.task('npm',['tag'],function(done){

    spawn('npm', ['publish'], { stdio: 'inherit' }).on('close', done); });
  50. var cp = require('child_process'); var spawn = cp.spawn; ! gulp.task('npm',['tag'],function(done){

    spawn('npm', ['publish'], { stdio: 'inherit' }).on('close', done); });
  51. var cp = require('child_process'); var spawn = cp.spawn; ! gulp.task('npm',['tag'],function(done){

    spawn('npm', ['publish'], { stdio: 'inherit' }).on('close', done); });
  52. var cp = require('child_process'); var spawn = cp.spawn; ! gulp.task('npm',['tag'],function(done){

    spawn('npm', ['publish'], { stdio: 'inherit' }).on('close', done); });
  53. var doc = global.document; var tag = 'iframe'; function poser

    (type) { var frame = doc.createElement(tag); frame.style.display = 'none'; doc.body.appendChild(frame); return frame.contentWindow[type]; } module.exports = poser;
  54. var doc = global.document; var tag = 'iframe'; function poser

    (type) { var frame = doc.createElement(tag); frame.style.display = 'none'; doc.body.appendChild(frame); return frame.contentWindow[type]; } module.exports = poser;
  55. var doc = global.document; var tag = 'iframe'; function poser

    (type) { var frame = doc.createElement(tag); frame.style.display = 'none'; doc.body.appendChild(frame); return frame.contentWindow[type]; } module.exports = poser;
  56. var doc = global.document; var tag = 'iframe'; function poser

    (type) { var frame = doc.createElement(tag); frame.style.display = 'none'; doc.body.appendChild(frame); return frame.contentWindow[type]; } module.exports = poser;
  57. var doc = global.document; var tag = 'iframe'; function poser

    (type) { var frame = doc.createElement(tag); frame.style.display = 'none'; doc.body.appendChild(frame); return frame.contentWindow[type]; } module.exports = poser;
  58. var vm = require('vm'); function poser (type) { var box

    = {}; var code = 'stolen=' + type; vm.runInNewContext(code, box, 'vm'); return box.stolen; } module.exports = poser;
  59. var vm = require('vm'); function poser (type) { var box

    = {}; var code = 'stolen=' + type; vm.runInNewContext(code, box, 'vm'); return box.stolen; } module.exports = poser;
  60. var vm = require('vm'); function poser (type) { var box

    = {}; var code = 'stolen=' + type; vm.runInNewContext(code, box, 'vm'); return box.stolen; } module.exports = poser;
  61. var vm = require('vm'); function poser (type) { var box

    = {}; var code = 'stolen=' + type; vm.runInNewContext(code, box, 'vm'); return box.stolen; } module.exports = poser;
  62. var vm = require('vm'); function poser (type) { var box

    = {}; var code = 'stolen=' + type; vm.runInNewContext(code, box, 'vm'); return box.stolen; } module.exports = poser;
  63. Client Side On first load GET request established by the

    browser Server-side renders layout and view Client-side controller gets executed
  64. Client Side On navigation - after first load AJAX request

    for partial model Client-side renders view Client-side controller gets executed