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

The Node.js Runtime Renaissance

Ruy Adorno
February 22, 2023

The Node.js Runtime Renaissance

Presented at ConFoo in Montreal, Canada on the February 22nd 2023.

Abstract: Last year was an exciting year for Node.js developers, with the arrival of refreshed competition the Node.js runtime has seen many new features landing under a renewed focus on developer experience. Learn more about what's new and how to use these new features today.

Ruy Adorno

February 22, 2023
Tweet

More Decks by Ruy Adorno

Other Decks in Programming

Transcript

  1. ConFoo 2023
    Node.js
    Runtime
    ruyadorno.com
    The
    Renaissance

    View Slide

  2. Ruy Adorno

    Based in Montreal


    Node.js Collaborator & Releaser.

    Working with Node.js things at Google


    @[email protected]
    The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com

    View Slide

  3. Chronology
    2022 features
    What’s next in 2023
    ToC
    ConFoo 2023 ruyadorno.com
    The Node.js Runtime
    Renaissance

    View Slide

  4. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Chronology

    View Slide

  5. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    2009
    Ryan Dahl writes the initial
    implementation of the Node.js
    runtime

    View Slide

  6. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    2010
    npm initial release

    View Slide

  7. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    2011
    npm bundled with Node.js

    View Slide

  8. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    2014
    io.js fork

    View Slide

  9. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    2015
    Node.js Foundation announced,
    Node.js and io.js merged back
    together

    View Slide

  10. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    2015
    Welcome to the
    Renaissance era!

    View Slide

  11. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    2017
    Ruy Adorno
    fi
    rst
    commit to the project

    View Slide

  12. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    2018
    Ryan Dahl announces the work on
    Deno, a new JavaScript runtime

    View Slide

  13. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    2019
    Node.js Foundation and the JS
    Foundation merge together forming
    the OpenJS Foundation

    View Slide

  14. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    2020
    Deno v1.0 is released

    View Slide

  15. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    The end of the
    small core
    Most collaborators these days are open to
    the idea of adding more features in order to
    provide a batteries-included experience in
    order to improve DX.

    View Slide

  16. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    2022
    Welcome to the
    Industrial era!

    View Slide

  17. The Node.js Runtime Renaissance Industrialization
    ConFoo 2023 ruyadorno.com
    2022
    Welcome to the
    Industrial era!

    View Slide

  18. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    5 exciting recent
    features

    View Slide

  19. Test Runner
    ConFoo 2023 ruyadorno.com
    The Node.js Runtime
    Renaissance

    View Slide

  20. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Test Runner
    Shipped initially in v18.0.0, the test runner
    was initially designed to be a minimal viable
    test runner but has been getting more and
    more features since then.

    View Slide

  21. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Test Runner
    - Mocks added in v18.13.0, v19.1.0

    - Reporters added in v19.6.0

    - Coverage added in v19.7.0 (this week!)


    View Slide

  22. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    import assert from 'node:assert';
    import test from 'node:test';
    import {splitChars} from './split-chars.mjs';
    test('test splitChars function', async t => {
    const input = 'a:b:c';
    const expected = ['a', 'b', 'c'];
    assert.deepStrictEqual(
    splitChars(input),
    expected,
    'should return expected characters'
    );
    })
    test-runner.mjs

    View Slide

  23. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    $ node test-runner.mjs
    TAP version 13
    # Subtest: test splitChars function
    ok 1 - test splitChars function
    ---
    duration_ms: 4.859125
    ...
    1..1
    # tests 1
    # pass 1
    # fail 0
    # cancelled 0
    # skipped 0
    # todo 0
    # duration_ms 59.869375
    shell

    View Slide

  24. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    $ node --test
    TAP version 13
    # Subtest: test splitChars function
    ok 1 - test splitChars function
    ---
    duration_ms: 4.859125
    ...
    1..1
    # tests 1
    # pass 1
    # fail 0
    # cancelled 0
    # skipped 0
    # todo 0
    # duration_ms 59.869375
    shell

    View Slide

  25. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    How the test runner
    finds what files to run
    - skip node_modules folders

    - if a test folder is found, recursively
    fi
    nd
    all .js .cjs .mjs
    fi
    les

    - in other folders, match:

    - Files named test: ^test$

    - Filenames that start with test-: ^test-.+

    - Filenames that ends with -test: .+[\.\-\_]test$


    View Slide

  26. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Learn more
    https://nodejs.org/dist/latest-v18.x/docs/api/test.html


    View Slide

  27. File Watcher
    ConFoo 2023 ruyadorno.com
    The Node.js Runtime
    Renaissance

    View Slide

  28. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    File Watcher
    First introduced in v18.11.0 and v16.19.0, the
    fi
    le watcher is a native way to have the node
    runtime reload anytime watched
    fi
    les are
    modi
    fi
    ed.

    View Slide

  29. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    import assert from 'node:assert';
    import test from 'node:test';
    import {splitChars} from './split-chars.mjs';
    test('test splitChars function', async t => {
    const input = 'a:b:c';
    const expected = ['a', 'b', 'c'];
    assert.deepStrictEqual(
    splitChars(input),
    expected,
    'should return expected characters'
    );
    })
    test-runner.mjs shell
    $ node --watch test-runner.mjs
    (node:42453) ExperimentalWarning: Watch mode is 

    an experimental feature and might change at any 

    time
    (Use `node --trace-warnings ...` to show where 

    the warning was created)
    TAP version 13
    # Subtest: test splitChars function
    ok 1 - test splitChars function
    ---
    duration_ms: 2.681209
    ...
    1..1
    # tests 1
    # pass 1
    # fail 0
    # cancelled 0
    # skipped 0
    # todo 0
    # duration_ms 6.377
    Completed running 'test-runner.mjs'

    View Slide

  30. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    export function splitChars(str) {
    return str.split(':');
    }
    split-chars.mjs shell
    $ node --watch test-runner.mjs
    (node:42453) ExperimentalWarning: Watch mode is 

    an experimental feature and might change at any 

    time
    (Use `node --trace-warnings ...` to show where 

    the warning was created)
    TAP version 13
    # Subtest: test splitChars function
    ok 1 - test splitChars function
    ---
    duration_ms: 2.681209
    ...
    1..1
    # tests 1
    # pass 1
    # fail 0
    # cancelled 0
    # skipped 0
    # todo 0
    # duration_ms 6.377
    Completed running 'test-runner.mjs'

    View Slide

  31. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    export function splitChars(str) {
    return str.split('d');
    }
    split-chars.mjs shell
    Restarting 'test-runner.mjs'
    TAP version 13
    # Subtest: test splitChars function
    not ok 1 - test splitChars function
    ---
    duration_ms: 3.022458
    failureType: 'testCodeFailure'
    error: 'should return expected characters'
    code: 'ERR_ASSERTION'
    0: 'a'
    1: 'b'
    2: 'c'
    0: 'a:b:c'
    operator: 'deepStrictEqual'
    ...
    1..1
    # tests 1
    # pass 0
    # fail 1
    # duration_ms 6.597791
    Failed running 'test-runner.mjs'

    View Slide

  32. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    export function splitChars(str) {
    return str.split(':');
    }
    split-chars.mjs shell
    Restarting 'test-runner.mjs'
    TAP version 13
    # Subtest: test splitChars function
    ok 1 - test splitChars function
    ---
    duration_ms: 2.054583
    ...
    1..1
    # tests 1
    # pass 1
    # fail 0
    # cancelled 0
    # skipped 0
    # todo 0
    # duration_ms 4.697125
    Completed running 'test-runner.mjs'

    View Slide

  33. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    More options
    - --watch-path specify what exact folders /
    fi
    les
    to watch, disable watching of imported modules

    - --watch-preserve-output disable clearing the
    console when watch mode restarts the process


    View Slide

  34. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Learn more
    https://nodejs.org/dist/latest-v18.x/docs/api/cli.html#--watch


    View Slide

  35. Argument
    Parser
    ConFoo 2023 ruyadorno.com
    The Node.js Runtime
    Renaissance

    View Slide

  36. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Argument Parser
    Initially added in v18.3.0 and v16.17.0, the
    argument parser is an opinionated way to
    handle command line arguments in your
    apps without the need of an extra package.

    View Slide

  37. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Argument Parser
    Made in collaboration between the
    maintainers of yargs and Commander ,
    two of the most popular argument parsers.

    View Slide

  38. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Argument Parser
    Currently an experimental API but should be
    promoted to stable soon. Unlikely to have
    changes at this point.

    View Slide

  39. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    import { parseArgs } from 'node:util';
    const { values } =
    parseArgs({
    options: {
    active: { type: 'boolean' },
    pathname: { type: 'string' },
    },
    });
    if (Object.keys(values).length) {
    console.table(values)
    }
    cli-parse-args.mjs

    View Slide

  40. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    $ node cli-parse-args.mjs --active \
    --pathname=./cli-parse-args.mjs
    ┌──────────┬────────────────────────┐
    │ (index) │ Values │
    ├──────────┼────────────────────────┤
    │ active │ true │
    │ pathname │ './cli-parse-args.mjs' │
    └──────────┴────────────────────────┘
    shell

    View Slide

  41. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Highly customizable
    The argument parser has much more options such
    as support to positional values, loose mode,
    providing default values, etc.


    View Slide

  42. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Learn more
    https://nodejs.org/dist/latest-v18.x/docs/api/util.html#utilparseargscon
    fi
    g


    View Slide

  43. Fetch
    ConFoo 2023 ruyadorno.com
    The Node.js Runtime
    Renaissance

    View Slide

  44. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Fetch
    After many years in the making, the fetch()
    method is
    fi
    nally available in Node.js starting
    at version v18.3.0 and up.

    View Slide

  45. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    const res = await fetch('https://nodejs.org/dist/index.json', {
    method: 'GET',
    headers: [
    ['Accept', 'application/json'],
    ],
    })
    const data = await res.json()
    const versions = data
    .map(i => ({ version: i.version, date: i.date }))
    .slice(0, 10)
    console.table(versions)
    fetch-something.mjs

    View Slide

  46. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    $ node fetch-something.mjs
    ┌─────────┬───────────┬──────────────┐
    │ (index) │ version │ date │
    ├─────────┼───────────┼──────────────┤
    │ 0 │ 'v19.7.0' │ '2023-02-21' │
    │ 1 │ 'v19.6.1' │ '2023-02-16' │
    │ 2 │ 'v19.6.0' │ '2023-02-01' │
    │ 3 │ 'v19.5.0' │ '2023-01-24' │
    │ 4 │ 'v19.4.0' │ '2023-01-05' │
    │ 5 │ 'v19.3.0' │ '2022-12-14' │
    │ 6 │ 'v19.2.0' │ '2022-11-29' │
    │ 7 │ 'v19.1.0' │ '2022-11-14' │
    │ 8 │ 'v19.0.1' │ '2022-11-04' │
    │ 9 │ 'v19.0.0' │ '2022-10-17' │
    └─────────┴───────────┴──────────────┘
    shell

    View Slide

  47. Stream iterator
    methods and Stream
    Web API helpers
    ConFoo 2023 ruyadorno.com
    The Node.js Runtime
    Renaissance

    View Slide

  48. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Stream iterator methods
    A variety of stream iterator methods have
    been introduced between v17.4.0 and
    v17.5.0. Some of these methods may also be
    available in v16.4.0.

    View Slide

  49. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    import { Readable } from 'node:stream';
    const s = Readable.from([1, 2, 3, 4]);
    const mapped = []
    s.on('data', data => {
    mapped.push(data * 2);
    })
    s.on('end', () => {
    for (const m of mapped) {
    console.log(m)
    }
    })
    map-stream-before.mjs map-stream-iterator.mjs
    import { Readable } from 'node:stream';
    const s = Readable.from([1, 2, 3, 4]);
    const mapped = s.map(i => i * 2);
    for await (const m of mapped) {
    console.log(m);
    }

    View Slide

  50. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Web Stream API
    Utility Consumers
    Added in v16.7.0, providing helper methods
    to help collect stream data.

    View Slide

  51. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    import { Readable } from 'node:stream';
    const s = Readable
    .from(['a', 'b', 'c', 'd']);
    let res = '';
    s.on('data', data => {
    res += data;
    });
    s.on('end', () => {
    console.log(res);
    });
    read-stream-before.mjs read-stream-utility-consumer.mjs
    import { Readable } from 'node:stream';
    import { text } from 'node:stream/consumers';
    const s = Readable
    .from(['a', 'b', 'c', 'd']);
    const res = await text(s);
    console.log(res);

    View Slide

  52. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Web Stream API
    Utility Consumers
    There are also utility consumers for
    arrayBuffer , blob , buffer and json .

    View Slide

  53. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Learn more
    https://nodejs.org/dist/latest-v18.x/docs/api/stream.html#readablemapfn-options

    https://nodejs.org/dist/latest-v18.x/docs/api/webstreams.html#utility-consumers


    View Slide

  54. ConFoo 2023 ruyadorno.com
    2023
    The Node.js Runtime Renaissance
    Coming up


    this year

    View Slide

  55. Single Executable 

    Apps
    ConFoo 2023 ruyadorno.com
    The Node.js Runtime
    Renaissance

    View Slide

  56. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Single Executable Apps
    (Just landed!) Added in v19.7.0, there’s now
    a way to package your app code along with
    the Node.js runtime so that you can
    distribute a single executable binary
    fi
    le.

    View Slide

  57. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Learn more
    https://nodejs.org/docs/latest-v19.x/api/single-executable-applications.html


    View Slide

  58. Process-based
    Permissions
    ConFoo 2023 ruyadorno.com
    The Node.js Runtime
    Renaissance

    View Slide

  59. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Process-based
    Permissions
    (Work in progress) New options to restrict
    access to speci
    fi
    c resources (such as
    fi
    le
    system, child process, workers) during
    execution.

    View Slide

  60. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Process-based
    Permissions
    Very likely to still change, this new
    permission model is going to be behind a
    fl
    ag: --experimental-permission

    View Slide

  61. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    $ node --experimental-permission index.js
    node:internal/modules/cjs/loader:171
    const result = internalModuleStat(filename);
    ^
    Error: Access to this API has been restricted
    code: 'ERR_ACCESS_DENIED',
    permission: ‘FileSystemRead'
    $ node --experimental-permission --allow-fs-read=* --allow-fs-write=./tmp index.js
    Hello world!
    (node:19836) ExperimentalWarning: Permission is an experimental feature
    (Use `node --trace-warnings ...` to show where the warning was created)
    shell

    View Slide

  62. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Learn more
    https://github.com/nodejs/node/pull/44004


    View Slide

  63. The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com
    Want to learn even more?
    Join one of the Working Groups meetings: https://nodejs.org/calendar

    Join the OpenJS Foundation Slack: https://slack-invite.openjsf.org


    Repository: https://github.com/nodejs/node

    Website: https://nodejs.org

    View Slide

  64. Merci!
    @[email protected]
    The Node.js Runtime Renaissance
    ConFoo 2023 ruyadorno.com

    View Slide