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

npm ftw

npm ftw

I've had a ton of fun with npm+grunt+browserify lately - some reflections on that.

760ee07e2a7c2a05ac35a981276c6a29?s=128

Dominykas Blyžė

December 11, 2013
Tweet

Transcript

  1. npm ftw By ( ), 2013-12-12 Dominykas Blyžė @dymonaz

  2. Disclaimer This is not a jQuery bashing talk! I am

    grateful for jQuery
  3. Use case Purely client side Widget on a 3rd party

    site Need small footprint Can't rely on libraries Note: small needs to be before gzip
  4. Options Structuring the code: 1. Use globals and namespacing mishmash

    2. AMD: Try to make node.js behave like the browser 3. Browserify: Try to make the browser behave like node.js
  5. Solution micro JS browserify grunt npm

  6. Result Efficient workflow and LOTS OF FUN!

  7. Small modules aka "replacing jQuery" Empty browserified script: 461B

  8. $() n p m i n s t a l

    l d o m r e a d y Total footprint: ~1700B r e q u i r e ( " d o m r e a d y " ) ( f u n c t i o n o n D o m R e a d y ( ) { / * . . . * / } ) ;
  9. AJAX n p m i n s t a l

    l x h r ...or any of the other gazillion libs Total footprint: ~3.9k v a r x h r = r e q u i r e ( " x h r " ) x h r ( { b o d y : s o m e J S O N S t r i n g , u r i : " / f o o " , h e a d e r s : { " C o n t e n t - T y p e " : " a p p l i c a t i o n / j s o n " } } , f u n c t i o n ( e r r , r e s p , b o d y ) { / / r e s p = = = x h r / / c h e c k r e s p . b o d y o r r e s p . s t a t u s C o d e } )
  10. node.js callback pattern m e t h o d (

    p 1 , p 2 , p 3 . . . , f u n c t i o n c a l l b a c k ( e r r , r 1 , r 2 , r 3 . . . ) { . . . } ) ;
  11. Callbacks object Use a s y n c , promises

    (q , w h e n , r s v p ), E v e n t E m i t t e r .
  12. DOM manipulation Use standards insertAdjacentHTML() ftw (IE4+) Study caniuse.com, MDN

    and Kangax's compat tables
  13. CSS Do not modify style properties directly Use c l

    a s s L i s t , polyfill available
  14. Data Use standard DOM methods (get/setAttr) Polyfill is trivial

  15. Deferred Do not use even if you use jQuery! n

    p m i n s t a l l r s v p Total footprint: ~15kB (ouch) v a r x h r p = r e q u i r e ( ' r s v p ' ) . d e n o d e i f y ( r e q u i r e ( ' x h r ' ) ) ;
  16. Dimensions g e t B o u n d i

    n g C l i e n t R e c t ( )
  17. Effects Use CSS transitions, transforms, animations Side note: don't animate

    just because you can
  18. Events a d d E v e n t L

    i s t e n e r ( ) (IE9+) Custom DOM events EventEmitter RSVP Delegation: ~1kB
  19. Forms IDK, but H5F.js is ~5kB Also n e w

    F o r m D a t a ( ) ; (IE10+)
  20. Manipulation v a r t o A r r a

    y = F u n c t i o n . p r o t o t y p e . c a l l . b i n d ( [ ] . s l i c e ) ; [ ] . s l i c e . c a l l ( n o d e L i s t ) ;
  21. Selectors d o c u m e n t .

    q u e r y S e l e c t o r A l l ( ) ftw E l e m e n t . m a t c h e s ( ) (prefixed) Use Sizzle if you have to
  22. Traversing / Utilities ES5 Array methods (f o r E

    a c h ( ) , m a p ( ) et al) Watch Zakas' video: JS APIs you've never heard of Use l o d a s h if you have to
  23. Attach an event handler to every element Not as expressive,

    but...: Less than 200B $ ( p a r e n t ) . f i n d ( s e l e c t o r ) . o n ( e v e n t , c a l l b a c k ) ; m o d u l e . e x p o r t s = f u n c t i o n ( p a r e n t , s e l e c t o r , e v e n t , c a l l b a c k ) { [ ] . f o r E a c h . c a l l ( p a r e n t . q u e r y S e l e c t o r A l l ( s e l e c t o r ) , f u n c t i o n ( e l ) { e l . a d d E v e n t L i s t e n e r ( e v e n t , c a l l b a c k , t r u e ) ; } ) ; } ;
  24. Where were we?.. Oh. Right. ~15kB

  25. Glue everything together

  26. Private / unpublished modules " r i c k s

    h a w " : " g i t : / / g i t h u b . c o m / s h u t t e r s t o c k / r i c k s h a w . g i t # v 1 . 4 .
  27. grunt g r u n t . r e g

    i s t e r T a s k ( " t e s t " , [ " b r o w s e r i f y " , " _ c o p y - b u n d l e - t o - m i n " , " b u s t e r " ] ) ; g r u n t . r e g i s t e r T a s k ( " r e l e a s e " , [ " l e s s : d i s t " , " b r o w s e r i f y " , " u g l i f y " , " b u s t e r " ] ) ;
  28. grunt-browserify src/index.js: b r o w s e r i

    f y : { d i s t : { f i l e s : { " b u i l d / b u n d l e . j s " : [ " s r c / i n d e x . j s " ] } , o p t i o n s : { t r a n s f o r m : [ " e s 6 i f y " , " e j s i f y " ] } } } v a r r s v p = r e q u i r e ( " r s v p " ) , m y M o d u l e = r e q u i r e ( " . / m y M o d u l e " ) ;
  29. grunt-contrib-uglify u g l i f y : { d

    i s t : { f i l e s : { " b u i l d / b u n d l e . m i n . j s " : [ " b u i l d / b u n d l e . j s " ] } } }
  30. grunt-contrib-watch w a t c h : { s c

    r i p t s : { f i l e s : [ " * * / * . j s " , " * * / * . e j s " , " * * / * . j s o n " , " ! n o d e _ m o d u l e s / * * / * " ] , t a s k s : [ " t e s t " ] } , l e s s : { f i l e s : [ " * * / * . l e s s " ] , t a s k s : [ " l e s s : d e v " ] } }
  31. Custom l o d a s h g r u

    n t . r e g i s t e r T a s k ( " l o d a s h i f y " , f u n c t i o n ( ) { v a r i n c l u d e s = [ " c l o n e " , " c o n t a i n s " , " e a c h " , " e x t e n d " , " f i l t e r " , " f o r E a c h " , " i s A r r a y " , " i s D a t e " , " i s O b j e c t " , " i s U n d e f i n e d " , " m a p " , " o b j e c t " , " p a i r s " , " p i c k " , " t o A r r a y " , " u n i q u e I d " ] ; r e q u i r e ( " s h e l l j s " ) . e x e c ( " . / n o d e _ m o d u l e s / . b i n / l o d a s h i n c l u d e = " + i n c l u d e s . j o i n ( " , " ) + " e x p o r t s = a m d - d - o b r o w s e r _ m o d u l e s / l o d a s h . j s " ) ; } ) ;
  32. Templating: ejs n p m i n s t a

    l l e j s i f y index.ejs view.js < % v a r i 1 8 n = r e q u i r e ( " . / i 1 8 n " ) ; % > < p > < % - i 1 8 n . h e l l o % > , < % = n a m e % > < / p > r e q u i r e ( ' . / i n d e x . e j s ' ) ( { n a m e : " V i l n i u s J S " } ) ;
  33. Use new stuff: es6ify Generators (yield), iterators, let, for..of, etc

    [ " o n e " , " t w o " ] . m a p ( ( i t e m ) = > " v a l u e : " + i t e m ) ;
  34. Problems

  35. Sync script loading Requires pre-compilation.

  36. LOOOOOOTS of modules Hard to chose Not all of them

    on npm
  37. Some modules think require() implies node.js

  38. Maintainers forget to n p m p u b l

    i s h Get used to this:
  39. Old browsers jQuery has man-aeons of experience and infrastructure Your

    average module author does not
  40. Dependency tree Node allows multiple versions of libs Must manage

    Must dedupe Hard to grok Long file paths
  41. Duplication No way to share, e.g., a common promises library

    between dependencies.
  42. What next (for me)? Live reload Source maps n p

    m i n s t a l l b e e f y Continuous integration
  43. Resources http://microjs.com/ http://caniuse.com/ ES5 compatibility tables (by @kangax) JavaScript APIs

    you've never heard of (by @slicknet) You're Missing the Point of Promises (by @domenic)
  44. Slides: ; http://dominykas.net/19 @dymonaz