$30 off During Our Annual Pro Sale. View Details »

npm ftw

npm ftw

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

Dominykas Blyžė

December 11, 2013
Tweet

More Decks by Dominykas Blyžė

Other Decks in Programming

Transcript

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  5. Solution
    micro JS
    browserify
    grunt
    npm

    View Slide

  6. Result
    Efficient workflow and LOTS OF FUN!

    View Slide

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

    View Slide

  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
    (
    ) { /
    *
    .
    .
    .
    *
    / }
    )
    ;

    View Slide

  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
    }
    )

    View Slide

  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
    .
    .
    .
    ) { .
    .
    . }
    )
    ;

    View Slide

  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
    .

    View Slide

  12. DOM manipulation
    Use standards
    insertAdjacentHTML() ftw (IE4+)
    Study caniuse.com, MDN and Kangax's compat tables

    View Slide

  13. CSS
    Do not modify style properties directly
    Use c
    l
    a
    s
    s
    L
    i
    s
    t
    , polyfill available

    View Slide

  14. Data
    Use standard DOM methods (get/setAttr)
    Polyfill is trivial

    View Slide

  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
    '
    )
    )
    ;

    View Slide

  16. Dimensions
    g
    e
    t
    B
    o
    u
    n
    d
    i
    n
    g
    C
    l
    i
    e
    n
    t
    R
    e
    c
    t
    (
    )

    View Slide

  17. Effects
    Use CSS transitions, transforms, animations
    Side note: don't animate just because you can

    View Slide

  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

    View Slide

  19. Forms
    IDK, but H5F.js is ~5kB
    Also n
    e
    w F
    o
    r
    m
    D
    a
    t
    a
    (
    )
    ; (IE10+)

    View Slide

  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
    )
    ;

    View Slide

  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

    View Slide

  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

    View Slide

  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
    )
    ;
    }
    )
    ;
    }
    ;

    View Slide

  24. Where were we?..
    Oh. Right. ~15kB

    View Slide

  25. Glue everything together

    View Slide

  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
    .

    View Slide

  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
    " ]
    )
    ;

    View Slide

  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
    "
    )
    ;

    View Slide

  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
    "
    ]
    }
    }
    }

    View Slide

  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
    " ]
    }
    }

    View Slide

  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
    "
    )
    ;
    }
    )
    ;

    View Slide

  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
    "
    }
    )
    ;

    View Slide

  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
    )
    ;

    View Slide

  34. Problems

    View Slide

  35. Sync script loading
    Requires pre-compilation.

    View Slide

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

    View Slide

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

    View Slide

  38. Maintainers forget to
    n
    p
    m p
    u
    b
    l
    i
    s
    h
    Get used to this:

    View Slide

  39. Old browsers
    jQuery has man-aeons of experience and infrastructure
    Your average module author does not

    View Slide

  40. Dependency tree
    Node allows multiple versions of libs
    Must manage
    Must dedupe
    Hard to grok
    Long file paths

    View Slide

  41. Duplication
    No way to share, e.g., a common promises library between
    dependencies.

    View Slide

  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

    View Slide

  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)

    View Slide

  44. Slides:
    ;
    http://dominykas.net/19
    @dymonaz

    View Slide