The new version of JavaScript, known as EcmaScript 6 or simply ES6, introduces the notion of modules and new syntax specific for them. This guide explores a combination of tools and conventions that help you author your code using these new primitives on top of the YUI infrastructure.
ES6 module syntax
Modules in EcmaScript 6 are based on two main keywords: import
and export
.
This contrasts to YUI modules because in ES6 the export side is composed of a
series of exports instead of additions made to a common object, the Y
object.
Modules also introduce the concept of "default" exports as the main entry point
to a module.
Export declarations
export
is followed by one of:
- A variable declaration, ie:
export var foo = bar
. - A function declaration, ie:
export function foo() {}
. - A list of named exports wrapped in curly brackets. Each export may be
bound with a new name using
as
. For example:export { foo as bar, baz }
.
A module without imports would look like this:
var initialCount = 2; var counter = initialCount; function count() { return counter++; } export var isCounting = true; export { initialCount as startValue }; export default count;
Import declarations
Importing works in a similar fashion. import
must be followed by one of:
- A name for the default export of the imported module, ie:
import foo from 'my-module'
. - A list of named imports wrapped in curly brackets. Each import may be
bound with a new name using
as
. For example:import { foo as bar, baz } from 'my-module'
.
Both types of import declaration can be combined to import the default export of a module alongside other named exports by separating them with a comma:
import count from 'counter'; import { startValue as initValue, isCounting } from 'counter'; export function countPixels() { if (!isCounting) { throw new Error('Counter is not working'); } return count() + 'px'; };
Pros and cons of using ES6 modules
Authoring code using the ES6 module syntax brings several new advantages and disadvantages:
- It requires a build step for your project. If you are already using tools to build your project's files, then using ES6 syntax should easily tie into the process you already have to get your application running.
- It allows you to write your code in one format and transpile it to different module formats including CommonJS, AMD and YUI modules.
- Sourcemaps allow you to debug using the new syntax, so the difference between all the different underlying module systems is hidden by the developer tools.
- ES6 modules use special syntax for exporting members of the module and other modules have mirror syntax for importing those exports. The collection of exports is then not a mutable object. This allows tools to more easily analyze which exports of a module are actually being used in order to do analytics on the code or to remove unused parts of the application.
Using transpiled modules in a YUI application
Since YUI 3.15.0 supports loading ES6 modules transpiled to YUI modules that
look slightly different from traditional YUI modules. Instead of adding
properties to the Y
object, the return value of the module factory
function is stored as the module exports.
Here is the result of transpiling one of the previous examples:
YUI.add("pixel-counter", function(Y, NAME, __imports__, __exports__) { "use strict"; /*jslint esnext: true*/ var count = __imports__["counter"]["default"]; var initValue = __imports__["counter"].startValue; var isCounting = __imports__["counter"].isCounting; function countPixels() { if (!isCounting) { throw new Error('Counter is not working'); } return count() + 'px'; }; __exports__.countPixels = countPixels; return __exports__; }, "@VERSION@", {"es":true,"requires":["counter"]});
Imports are received inside an object as a parameter of the factory function. As a convenience, an object for storing the exports is also created, but the actual exports of the module are the ones in the value returned by the factory function.
Using the ES6 module transpiler
The es6-module-transpiler
is
a Node
application that parses modules written using the ES6 module syntax and
compiles them to other JavaScript source files using Node's module system, AMD
modules or YUI modules.
You can install it with npm globally and use it as a command line tool called
compile-modules
$ npm install -g es6-module-transpiler $ compile-modules ./src-dir --to ./build-dir --type=yui
Since the ES6 syntax does not have a way to specify the name of the module, the transpiler must either receive the name beforehand or infer it from the file name. Both options are available from the command line:
$ compile-modules ./es6-mod.js --to ./build-dir --type=yui --module-name=foo $ compile-modules ./src-dir --to ./build-dir --type=yui --infer-name
Starting up your application with Y.require()
Since these transpiled modules are not traditional YUI modules,
YUI().use()
would not work for loading them into a page. Instead,
use YUI().require()
which has a similar signature but also passes a
second argument to the callback that contains all the ES6 required modules.
YUI().require('pixel-counter', function (Y, __imports__) { var countPixels = __imports__['pixel-counter'].countPixels; // Use countPixels... });