NoDent - Asynchronous Javascript language extensions
npm install nodent
NoDent
======
NoDent is a small module for Nodejs that implements the JavaScript ES7 keywords async and await. These make writing, reading and understanding asynchronous and callback methods more implicit and embedded in the language. It works by (optionally) transforming JavaScript when it is loaded into Node.
This README assumes you're using Nodent v3.x.x - see Upgrading if your upgrading from an earlier version, and keep an eye out for the asides that look like..
> v2.x users - changes between NoDent v2 and v3 are highlighted like this
Contents
--------
* Online demo
* Basic Use and Syntax
* Why Nodent?
* Installation
* Command\-Line usage
* Node.js usage
* ES7 and Promises
* Use within a browser
* async and await syntax
* Gotchas and ES7 compatibility
* Advanced Configuration
* API
* Built\-in conversions and helpers
* Testing
* Upgrading
* Changelog
* Credits
Online demo
===========
You can now see what Nodent does to your JS code with an online demo at here. Within the examples in this README, click on _TRY-IT_ to see the code live.
Basic Use and Syntax
====================
Declare an asynchronous function (one that returns "later").
async function tellYouLater(sayWhat) {
// Do something asynchronous and terminal, such as DB access, web access, etc.
return result ;
}
_TRY-IT_%20%7B%0A%20%20%2F%2F%20Do%20something%20asynchronous%20and%20terminal%2C%20such%20as%20DB%20access%2C%20web%20access%2C%20etc.%0A%20%20return%20result%20%3B%0A%7D%0A)
Call an async function:
result = await tellYouLater("Hi there") ;
_TRY-IT_%20%3B)
To use NoDent, you need to:
require('nodent')() ;
This must take place early in your app, and need only happen once per app - there is no need to require('nodent') in more than one file, once it is loaded it will process any files ending in use nodent directive at the top of a .js file.
> v2.x users, the '.njs' extension is still supported, but not recommended
You can't use the directive, or any other Nodent features in the file that initially require("nodent")(). If necessary, have a simple "loader.js" that requires Nodent and then requires your first Nodented file, or start your app with nodent from the command line:
./nodent.js myapp.js
That's the basics.
Why Nodent?
===========
* _Performance_ - on current JS engines, Nodent is between 2x and 5x faster than other solutions in common cases, and up to 10x faster on mobile browsers.
* Simple, imperative code style. Avoids callback pyramids in while maintaining 100% compatibility with existing code.
* No dependency on ES6, "harmony"
* No run-time overhead for Promises, Generators or any other feature beyond ES5 - works on most mobile browsers & IE (although Nodent can use Promises and Generators if you want it to!)
* No execution framework needed as with traceur, babel or regenerator
* No 'node-gyp' or similar OS platform requirement for threads or fibers
* ES7 async and await on ES5 (most browsers and nodejs)
* Compatible with ES6 too - nodent passes ES6 constructs unchanged for use with other transpilers and Node > 4.x
* For more about ES7 async functions and await see:
* http://wiki.ecmascript.org/doku.php?id=strawman:async_functions
* http://jakearchibald.com/2014/es7-async-functions/
* https://github.com/lukehoban/ecmascript-asyncawait
Installation
======================
npm install --save nodent
Command-Line usage
==================
You can invoke and run a nodented JavaScript file from the command line (although for Node apps it's much easier using the JS transpiler). To load, compile and run your JS file (containing async and await), use:
./nodent.js myNodentedFile.js
You can also simply compile and display the output, without running it. This is useful if you want to pre-compile your scripts:
./nodent.js --out myNodentedFile.js
If you are using nodent as part of a toolchain with another compiler, you can output the ES5 or ES6 AST is ESTree format:
./nodent.js --ast myNodentedFile.js
...or read an AST from another tool
./nodent.js --fromast --out estree.json // Read the JSON file as an ESTree AST, and output the nodented JS code
To generate a source-map in the output, use --sourcemap.
./nodent.js --sourcemap --out myNodentedFile.js
The testing options --parseast and --minast output the source as parsed into the AST, before transformation and the minimal AST (without position information) respectively. The option --pretty outputs the source formatted by nodent before any syntax transformation. You can read the Javascript or JSON from stdin (i.e. piped) by omitting or replacing the filename with -.
The full list of options is:
|option |Description |
|-------------------|---------------------------------------|
| --fromast | Input is a JSON representation of an ESTree
| --parseast | Parse the input and output the ES7 specification ESTree as JSON
| --pretty | Parse the input and output the JS un-transformed
| --out | Parse the input and output the transformed ES5/6 JS
| --ast | Parse the input and output the transformed ES5/6 ESTree as JSON
| --minast | Same as --ast, but omit all the source-mapping and location information from the tree
| --exec | Execute the transformed code
| --sourcemap | Produce a source-map in the transformed code
| --runtime | Include the nodent runtime in the output
Code generation options:
|option |Description |
|-------------------|---------------------------------------|
| --use=_mode_ | Ignore any "use nodent" directive in the source file, and force compilation _mode_ to be es7,promises,generators. engine or default
| --wrapAwait | Allow await with a non-Promise expression more info...
| --lazyThenables | Evaluate async bodies lazily in 'es7' mode. See the Changelog for 2.4.0 for more information
| --noruntime | Compile code (in -promises or -engine mode) for execution with no runtime requirement at all
| --es6target | Compile code assuming an ES6 target (as of v3.0.8, this only requires support for arrow functions)
| --noextensions | Don't allow nodent's extensions to the ES7 specification more info...
Node.js usage
============================
Automatic transpilation
------------
There is no need to use the command line at all if you want to do is use async and await in your own scripts then just require('nodent')(). Files are transformed if they have a use nodent directive at the top, or have the extension ".njs". Existing files ending in '.js' _without_ a use nodent... directive are untouched and are loaded and executed unchanged.
Nodent can generate code that implements async and await using basic ES5 JavaScript, Promises (via Nodent's built-in library, a third party library or module, or an ES5+/6 platform) or Generators (ES6). Using the directive:
'use nodent';
The use nodent directive uses a default set of compilation options called 'default', which can be modifed in your package.json.
Within your package.json, you can have named sets of pre-defined options, which individual files can refer to if necessary. There are four pre-defined sets of options: promises, es7, generators and engine.
'use nodent-promises';
'use nodent-es7';
'use nodent-generators';
'use nodent-engine';
#### Which one should you use?
All the implementations work with each other - you can mix and match. If you're unsure as to which will suit your application best, or want to try them all out 'use nodent'; will use a 'default' configuration you can determine in your application's package.json. See Advanced Configuration for details.
##### Shipping a self-contained app to a browser, Node <=0.10.x or other unknown environmentuse nodent-es7 - it's the most compatible as it doesn't require any platform support such as Promises or Generators, and works on a wide range of desktop and mobile browsers.
##### Shipping an app or module within Node, npm or modern browsers supporting Promisesuse nodent-promises provides the most compatibility between modules and apps. If your module or library targets Node earlier than v4.1.x, you should install a Promise library (e.g. rsvp, when, bluebird) or use nodent.Thenable to expose the Promise API. In promises mode, there is no need for a runtime at all. Specifying the option use nodent-promises {"noRuntime":true} will generate pure ES5 code at the cost of some loss in performance and increase in code size.
> v2.x users: nodent.EagerThenable() is still defined, but as of v3 is the same as the Thenable implementation.
##### Generatorsuse nodent-generators generates code which is reasonably easy to follow, but is best not used for anything beyond experimentation as it requires an advanced browser on the client-side, or Node v4.x.x. The performance and memory overhead of generators is poor - currently (Node v6.6.0) averaging 3.5 times slower compared to the es7 with 'lazyThenables'.
##### Engineuse nodent-engine does _not_ transpile standard ES7 async/await constructs, but only transpiles the additional non-standard features provided by nodent - await anywhere, async getters, async return and throw. At the time of writing, not many runtimes implement async and await - Chrome v53 does with command line flags, and Edge 14 are examples. On Chrome, performance is better than generators, but not quite as good as Promises, and still less than half the speed of ES7 mode. In promises mode, there is no need for a runtime at all. Specifying the option use nodent-engine {"noRuntime":true} will generate pure ES5 code at the cost of some loss in performance and increase in code size.
Programmatical usage within scripts
-------------
To compile code programmatically you should use require(nodent-compiler). This module is a standalone compiler that has:
- no require hook (it does not intercept .js files as they are loaded into Node)
- no runtime (it does not implement any functions required to run transpiled code)
- no pollution (because it has no runtime, it does not add async-specific bindings on Function.prototype, a global error handler, stack source-mapping)
Example usage:
``javascript`
var NodentCompiler = require('nodent-compiler');
var compiler = new NodentCompiler() ;
var es5ReadySourceCode = compiler.compile(sourceCode, filename, { sourcemap:false, promises: true, noRuntime: true, es6target: true });
Use within a browser
====================
You can use async and await within a browser by auto-parsing your scripts when Nodejs serves them to your clients.
The exported function generateRequestHandler(path, matchRegex, options) creates a node/connect/express compatible function for handling requests for nodent-syntax files that are then parsed and served for use within a stanadrd browser environment, complete with a source map for easy debugging.
For example, with connect:
var nodent = require('nodent')() ;
...
var app = connect() ;
...
app.use(nodent.generateRequestHandler(
"./static-files/web", // Path to where the files are located
/\.njs$/, // Only parse & compiles ending in ".njs"
options // Options (see below)
)) ;
The regex can be omitted, in which case it has the value above.
The currently supported options are:
enableCache:
runtime:
extensions:
htmlScriptRegex: