Sie sind auf Seite 1von 74
ars20%6 Read Seting up ES6 |Leanpu BF Signin _ signup Setting up ES6 & Axel Rauschmayer Setting up ES6 Dr. Axel Rauschmayer Eemanauten $5.00 $8.00 Add Ebook to Cart Setting up ES6 Table of Contents ip:eareub comiseting pesbiread wa 462016 Read Setting up ESS | Leanpub * 1. About this book * 2. Deploying ECMAScript 6 + 2.1 Using ECMAScript 6 today + 2.2 ES6REPLs + 2.3. Transpilation tools + 24 Other useful ES6 tools and libraries * 2.5 The future: native ESé * 2.6 Are there ES6 features that can’t be transpiled to ES5? 3. Babel setups for browsers and Node.js * 3.1 npmand local installs * 3.2 Source maps * 3.3 Browser setup: ES6 via webpack and Babel * 3.4 Nodejs setup: Dynamically transpiled ES6 via Babel + 35. Node,js setup: Statically transpiled ES6 via Babel « 4. Configuring Babel 6 * 41 Installing Babel 6 Setting up ES6 e 5. Babel: configuring standard library and helpers $5.00+ 5.1 $6¥eMIew — Acid Ebook to Cart MINIMUM | SUGGESTED ——_ * 5.2. External dependencies of transpiled code * 5.3. External dependencies via global variables * 54 External dependencies via module imports * 5.5 What should I use when? ip:eareub comiseting pesbiread 2m ars20%6 Read Seting up ES6 |Leanpu * 6. Babel’s loose mode * 61 Twomodes + 6,2. Example: the output of normal mode and loose mode * 7. Babel and CommonJS modules * 71 ES6 modules vs. CommonJS modules * 7.2 How Babel compiles ES6 modules to CommonJS * 7.3 How Babel imports CommonJS modules * 7.4 Recommendations 8. The future of bundling JavaScript modules * 81 Why we bundle modules * 82 JavaScript modules * 83 Future developments and bundling + 8.4 Further reading 1. About this book ES6 (whose official name is ECMAScript 2015) is the latest version of JavaScript. Topics covered in this book: * Configuring Babel. * Setting up ES6 projects that are compiled to ESS via Babel: * Deploying ES6 in browsers via Babel and webpack. * Deploying ES6 in Node.js, by statically or dynamically compiling it via Babel. Versions used in this book: ip:eareub comiseting pesbiread ama ars20%6 Read Seting up ES6 |Leanpu * Babelé + webpack 1.x + Node,js 5 More information on this book: Required knowledge: You should already know ES6, If you don't, consult my book "Exploring E56" which you can read online for free Feedback, submitting errata: consult the home page of this book More information on Babel: * Babel has an official forum + The new Babel handbook has two parts: + User Handbook: how to set up/configure Babel and more. * Plugin Handbook: how to create plugins for Babel. Acknowledgements. Many thanks go to the Babel team (especially Logan Smyth, James Kyle and Sebastian McKenzie) for answering questions | had while writing this book. Deploying ECMAScript 6 This chapter describes the options you have for deploying ECMAScript 6 in current JavaScript environments. It is selective w.r.t. the amount of tools it covers. If you want a comprehensive list of tools, | suggest you look at Addy Osmani's “ECMAScript 6 Tools". 2.1 Using ECMAScript 6 today What options do you have for using ECMAScript 6 today? * Current JavaScript engines (browsers, Nodes, ...) already ip:eareub comiseting pesbiread a8 anncore Read Sting up E55 Lord support much of ES6. You can look up which features are supported where: * In Kangax’ “ECMAScript 6 compatibility table”. * William Kapke's "Node, js £2015 Support" lists only the Node-related entries in Kangax' table. ES6 REPLs (interactive command lines) let you try out smaller pieces of code. A section in this chapter lists available options. Compiling from ES6 to ESS: Especially if you take support for legacy engines into consideration, compiling ES6 to ESS will be the only viable option for using ES6 for quite a while. Compiling from source code to source code is also called transpiling. You can transpile ES6 either before deployment (statically) or at runtime (dynamically). This chapter explains how that works and what other ES6 tools and libraries there are. The nice thing about ES6 is that it is a superset of ES5, which means that all of your ESS code bases are already valid ES6. This helps with adopting ES6-specific features, because you can do so incrementally. 2.2 ES6 REPLs There are many REPLs (command lines) out there for interactively playing with ES6. The obvious choices are the interactive online playgrounds of the following projects: * TypeScript Playground © Babel REPL * Traceur Transcoding Demo * Closure Compiler Service Additionally, Babel brings ES6 support to the Node,js REPL via its babel-node tool. 2.3. Transpilation tools ip:eareub comiseting pesbiread 574 ars20%6 Read Seting up ES6 Leong There are three essential choices that you have to make for transpilation: * A transpiler (for your code) * Apackage manager (to install existing libraries) + Amodule system (for the complete app) Note that the choices are not completely independent; not every module system works with every package manager etc. The next sections explain each of these choices in more detail. 2.3.1 Choosing a transpiler A transpiler compiles your ES6 code to ES5. Popular choices are: + Microsoft TypeScript: Is basically ECMAScript 6 plus optional type annotations. Google Traceurt is the first popular ES6 transpiler. Pronounced French, /twa.scex/; an English approximation is “truh-SIR” (source, listen to native French speakers pronounce this word) Babel: is a newer ES6 transpiler that has become the de-facto standard. Babel supports Reacts JSX syntax in addition to ES6. Pronounced “babble” (think Australian accent - Babel's creator, Sebastian McKenzie is Australian) Closure Compiler: can be used as a static transpiler from, e.g., ECMAScript 6 to ECMAScript 5, if you use the following two command line options: * Specify the input language: --language ECMASCRIPT6_STRICT. * Specify the output language: --language_out ECMASCRIPTS: In principle, transpilation can be done either: * statically (before deployment) or + dynamically (at runtime) ip:eareub comiseting pesbiread ams ars20%6 Read Seting up ES6 Leong 2.3.1.1 Static transpilation As a build step, TypeScript, Traceur, Babel and Closure Compiler let you produce ESS code in the following module formats. You can either invoke them directly or use a build tool (grunt, gulp, broccoli, etc). * AMD * CommonJS * ES6 module loader AP!: The ES6 code is transpiled to ES5 code that uses this API via a poly/ll In browsers, such ES5 modules are loaded via one of the module systems described later. On Nodejs, you can use the built-in module system (other options exist, e.g. webpack and the ES6 Module Loader Polyfill) 2.3.1.2. Dynamic transpilation In browsers, you transpile dynamically via a library plus a custom 3.3.7 File webpackcontig;s This is an excerpt of the configuration file for webpack (I've omitted the imports and a few other details): var dir_js = path.resolve(_dirname, 'js'); var dir_html = path. resolve(_dirname, "html'); var dir_build = path.resolve(_dirname, ‘build’ module.exports = { : path.resolve(dir_js, 'main.js"), output: { path: dir_build, filename: 'bundle.js' 3, module: { loaders: [ { Joader: 'babel-loader', test: dirs, + ip:eareub comiseting pesbiread ama ars20%6 Rea Sting up ESS | Lean 1 } plugins: [ // Simply copies the files over new CopywebpackPlugin(( { from: dir_html } // to: output.path Dd, 1 // Create Sourcemaps for the bundle devtool: 'source-map' devserver: { contentsase: dir_build, 3, ai The file is a native Node.js module that exports an object with the configuration data. It uses the special Node,js variable _ dirname that contains the path of the parent directory of the currently executed module. The configuration data has the following properties: * entry: This is where the execution of JavaScript code starts. webpack starts compiling here and continues by compiling its dependencies (imported modules), then the dependencies of the dependencies, etc. * output: webpack bundles the entry file and everything it depends on into the output file bundles. + module.loaders: are preprocessors for imported files. Support for ES6 is enabled via a the module loader babel-loader, * Property test specifies what files the loader should transpile You can specify a single test or multiple tests * Single test: match an absolute path via a regular expression or a string * Multiple tests: array of single tests (logical and”) * plugins extend webpack in various ways. | use CopyWebpackPlugin to copy everything in html/ over to build/. That means that webpack performs a task here that is traditionally handled by a build tool such as grunt or gulp. ip:eareub comiseting pesbiread zara ars20%6 Read Seting up ES6 Leong * The option devtool switches on and configures source maps. * devServer tells the webpack development server what files to serve. 3.3.8 Installing client-side libraries via npm You can install packages via npm and use them from your client- side E56 code, seamlessly. For example: First install lociash and save that dependency as a runtime dependency via ~-save: npm install --save lodash Then use it anywhere in your ES6 code: import { zip } from ‘lodash'; console.log(zip(L'l', '2'], ['a', "b']))5 3.4. Node.js setup: Dynamically transpiled ES6 via Babel In this section, we run ES6 on Node.js. We transpile ES6 code dynamically (at runtime), via Babel (version 6). We run unit tests via mocha, which we configure so that it transpiles the tests dynamically, again via Babel. ip:eareub comiseting pesbiread 274 ars20%6 Read Seting up ES6 |Leanpu 6 Alternative: static transpilation The approach explained in this section is convenient for experiments and development. But it uses on-the-fly transpilation, which means that startup is slower and that Babel needs to be installed on the production system. If you want to avoid those disadvantages, you can transpile statically, as described in the next section. For libraries, you normally don't have a choice and have to statically transpile them to ES5, because you should not force your users to transpile dynamically. 3.4.1 Installing the demo project This section describes a demo project, which you can install like this: Download or clone the GitHub repository node-babel-dynamic- demo. cd node-babel-dynamic-demo/ rpm install Everything is installed only locally. 3.4.2 The structure of the demo project The project has the following structure: node_modules/ package. json sre/ point. js require-hook. js ip:eareub comiseting pesbiread 274 ars20%6 Read Seting up ES6 |Leanpu test/ point_test. js Explanations: * node_modules/ contains the packages installed via npm. * package json configures npm. 3.4.3 babel-node is an executable for running code via Babel that otherwise works like the node executable. It is installed via the npm package babel-cli, The important parts for setting up babel-node in package.json are: src/ contains ES6 source code. test/ contains tests for the ES6 source code. Running ES6 code via batel-noae "dependencies": { “babel-cli": "A6.2.4", “babel-preset-es2015-nodeS": "A1.1.0" 3 "bin": { “point": "./src/point.js" 3, "scripts": { point": "babel-node ./src/point.js", babel -node" babel": { "presets": [ “es2015-nodes" ] 3 t Explanations: * dependencies: We need the npm package babel-cli for the babel-node epe:eareub comiseting pestiread 2074 ane20%6 Read Seting up ES6 Leong executable and the babel-preset-es2015-node5 so that Babel can transpile ES6. The preset configures Babel so that only ES6 constructs are transpiled that are missing from Nodejs 5 (which supports quite a bit of ES6; e.g,, classes and generators). * bin: If you install the demo project globally then you'll get the shell command point * scripts: enables us to run src/point.js via npm run point. Even though we have installed babel-node only locally, we can use it here, because npm adds all executables in the dependencies to the shell path. The script b is explained later. * babel: tells Babel to use the aforementioned preset for transpilation. The file points looks as follows: #!/usr/bin/env babel-node export class Point { constructor(x, y) { this.x this.y 3 tostring® { return “new Point(S{this.x}, S{this.y})°; 3 t if (require.main === module) { let pt = new Point(7,4); console. log( My point: S{pt}"); Explanations: * The first line lets us run this file as an executable on Unix (it's not needed if you use npm run to execute it). It starts with a so- called hashbang (+!) + Next, class Point is declared and exported. + At the end, we check whether pointjs is run as a script (and not ips:itearpubcomiseting-upestiread aims anncore Read Sting up E55 Lord just imported as a module). Ifit is, we create an instance of Point and log it to the console. There are several ways of running points: * On Unix, you can run the file as follows (if it is executable and has the first line shown in the previous code): -/src/point. js * You can execute point.js via npm run (as configured in scripts): apm run point * If you install babel-node globally (via npm install -g babel-cli) then you can execute points like this: babel-node src/point. js * The helper script b lets us run babel-node locally. The local version of the previous invocation is: npm run b src/point.js * If you install the demo project globally, you get a shell command point (as specified via bin) If you install the demo project as a dependency of another package, you can execute point via the scripts of that package, as if it were a globally installed command. This is what the output of point(s looks like if you execute it via npm run point: > @ point node-babel-dynamic-demo > ./sre/point. js ip:eareub comiseting pesbiread 274 ars20%6 Read Seting up ES6 |Leanpu My point: new Point(7, 4) 3.4.4 Running ES6 scripts via a require hook The idea of a require hook is as follows: * The first script of an app is a native (untranspiled) module, that you can start via the normal node binary, * That script hooks Babel into Nodes require * All modules the script requires are than transpiled from ES6 to ESS. The inital script looks like this: #!/usr/bin/env node // The advantage of a require hook is that // you can start via normal Node. js require("babel-register") ({ presets: [ “es2015-nodes" 1 vi var point = require('./point'); console. log('Case in point: ' + new point.Point(8, 2)); ‘ > Again, the first line (starting with #) lets us run this file as a script on Unix (but it must be executable). If you use babel-register then that package becomes a runtime dependency! 3.4.5 Standard library and source maps ip:eareub comiseting pesbiread 274 ane20%6 Read Seting up ES6 Leong Whenever you transpile code dynamically on Node,js, Babel automatically includes babel-polyfill (which polyfills what's missing from the ES6 standard library) and switches on support for source maps 3.4.6 Getting an ES6 REPL Via bavei-noae babel-node also gives you a REPL, via the following shell command: babel-node In the REPL, you can use ES6: a, > 3] map(x => x * x) ca, 2,3] 4,9] 3.4.7 Running mocha unit tests via Babel You can run your unit tests in ES6 via mocha. The relevant bits of package,son are: { "devbependencies": { "mocha": "A2Z.2.5 “babel-register": 3, "scripts": { jocha --ui qunit --compilers js:babel-core “presets”: [ “es2015-nodeS” ] } } Explanations: ip:eareub comiseting pesbiread sua anncore Read Sting up E55 Lord + devDependencies: mocha is needed for running unit tests, babel- register is how we enable mocha to use Babel * scripts: defines a shortcut for invoking mocha * You can use that shortcut via npm run test or via npm test or via npmt + | prefer a QUnit-style “frame” around the assertions (the mocha docs call this kind of frame an “interface”). This is switched on via --ui qunit. * babel: sets up Babel so that it transpiles ES6. The unit test itself in test/point tests looks as follows. /* global suite */ /* global test */ ‘import assert from ‘assert’; ‘import { Point } from '../src/point'; suite('Point'); test('Instance properties’, Q => { // (A) Jet p = new Point(1, 5); assert. strictequal(p.x, 1); assert.strictequal(p-y, 5); Di * As previously mentioned, the mocha “UI" is QUnit (suite() and test(), flat at the top level). * The assertions API is the built-in Node.js module assert. * The unit tests profit from ES6's arrow functions (line A). 3.5 Node.js setup: Statically transpiled ES6 via Babel This section explains how to use ES6 on Nodejjs by statically transpiling it to ES5 via Babel (version 6). ip:eareub comiseting pesbiread aus ane20%6 Read Seting up ES6 Leong The previous section showed how to dynamically transpile ES6 at runtime (also via Babel). That is more convenient and should work for many projects, but occasionally you may want a simpler and faster setup for your runtime environment. 3.5.1 Installing the demo project You don't need to do so in order to follow this section, but here is how to install the demo project that we are examining in this section: * Download or clone the GitHub repository node-babel-static-demo. * cdnode-babel-static-demo/ * npm install Everything is installed locally. 3.5.2 Structure of the demo project The repo has the following structure: es5/ myapp.3s myapp.js.map es6/ myapp. js node_modules/ package. json Explanations: es6/: contains the source code of the Node,js app, written in ES6. es5/: contains the ES5 that the ES6 code is transpiled to. And a source map so that the ES5 code can be debugged via the ES6 code. The files in this directory don’t exist, initially. They are created by a build step. node_modules/: contains the packages installed via npm ip:eareub comiseting pesbiread sama anncore Read Sting up E55 Lord * package.json: contains the configuration data for npm 3.5.3 File packagejson t devDependencies": { “babel-cli": "A6.2.0", "babel -preset-es2015-nodeS": "A1.1.1" 3, dependencies": { "babel-polyfil1": "A6.2.0 "source-map-support”: "A0.4.0" 3, "scripts": { "babel es6 --out-dir es5 --source-maps” : "babel es6 --out-dir es5 --source-maps "start": "node esS/myapp.js” 3, "babel": { "presets": [ “es2015-nodes" J 3 3 Explanations: * devDependencies: We need babel-cli to get the executable babel for transpiling on the command line. And we need the preset babel- preset-es2015-nodes so that Babel can transpile full ES6 to the partial ES6 supported by Node,js version 5. * dependencies: If you import babel-polyfill, it adds whatever is missing from the ES6 standard library, globally. Package source- map-support provides support for source maps on Nodejs. * scripts: lets us use npm to build and run the Nodejs app * Build once: npm run build * Watch files, build whenever there are changes: npm run watch * Run the app (as ESS code, via the normal Node,js binary) npm start (or npm run start) ip:eareub comiseting pesbiread sama anncore Read Sting up E55 Lord * babel: is for configuring Babel. 3.5.4. Transpilation The file esé/myappjs contains the ES6 code of the Node,js application: ‘import { install } from 'source-map-support'; installO; ‘import 'babel-polyfill'; console. 1og([1,2,3].map(x => x * x); throw new Error('Test!'); // line 8 Alas, Node,js does not come with built-in support for source maps. But it can be enabled via a library, e.g. the npm package source-map- support. That library needs to be called at least once in an app. The first two lines in the previous code take care of that. They also demonstrate that you can use any npm-installed package via ES6 syntax. Afterwards, importing babel-polyfill ensures that all of the ES6 standard library is present globally. The following npm invocation transpiles myapp.js. npm run build Alternatively, you can use npm run watch to continuously watch the ES6 files and transpile them whenever they change. The results of the transpilation are in the directory es5/: es5/ myapp.js myapp.js.map ip:eareub comiseting pesbiread Ta ars20%6 Read Seting up ES6 |Leanpu You can see the ESS version of ess/myappjs and the source map file myapp.js.nap. The contents of the former file are: ‘use strict’; var _sourceMapSupport = require(' source-map-support') ; require('babel-polyfil1'); (0, _sourceMapsupport.instal1) Q; console.log([1, 2, 3].map(x => x * x)); throw new Error('Test!"); // line 8 //# sourceMappingURL=myapp . js map 3.5.5 Running the transpiled code The transpiled code is a normal ESS Node,js app. You can run it as usual: node es5/myapp. js Or via npm: npm start The latter invocation produces the following output. Note that, thanks to the source map, the stack trace reports that the exception is thrown where it is in the ES6 file (not where it is thrown in the ESS file). The source code that is quoted is from the ES6 file, too. > @ start /tmp/node-babel-static-demo > node es5/myapp. js (1,4,9] ip:eareub comiseting pesbiread aera ars20%6 Read Seting up ES6 Leong /tmp/node-babel-static-demo/es6/myapp.js:8 throw new Error('test!"); // line 8 A Error: Test! at object. (/tmp/node-babel-static-demo/ 4. Configuring Babel 6 Babel 6 is much more configurable than Babel 5, but also more difficult to configure. This chapter gives tips. 4.1 Installing Babel 6 The following are a few important npm packages. All Babel packages reside in a single repository on GitHub. Browsing their source code and their package,json files is instructive. * babel-core: the core compilation machinery and plugin infrastructure for Babel. You will rarely need to install this package, because other packages such as babel-cli have it as a dependency, meaning that it will be automatically installed when they are installed. babel-cli: a command line interface to Babel. It includes the following commands: * babel-doctor detects common problems with your Babel installation. babel transpiles files or stdin via Babel babel-node a version of the Node.js executable node that transpiles everything via Babel babel-external-helpers prints all of Babel’s helper functions (such as inherits for subclassing) to the console. babel-register: lets you switch on Babel transpilation from within Node.js. After you do, all modules you require (minus code you want to ignore, e.g, packages installed via npm) are automatically transpiled ip:eareub comiseting pesbiread oor sanerzot6 Rees Seng up ES8 | Leap 4.2 Configuration data Babel is often about compiling an input file, e.g. in the following two scenarios: * Compiling a file via the command line tool babel babel input-es6.js --out-file output-es5.js + Running a Node,js script written in ES6 babel-node input-es6.js The configuration data is an object of JSON data that is assembled from various sources (which are described later). Two configuration options have much influence on how the output is produced: plugins and presets. These are explained next. The remaining configuration options are explained in the Babel documentation. 4.2.1 Plugins Roughly, plugins are functions that are applied to the input during compilation. Two important categories of plugins are: * Syntax plugins enable Babel to parse syntactic entities beyond the built-in base syntax. They help with constructing an abstract syntax tree. Examples are: * syntax-async-functions © syntax-jsx * Transform plugins modify the abstract syntax tree, Examples are: * transform-async-to-generator * transform-react-jsx * transform-es2015-arrow-functions ip:eareub comiseting pesbiread amma ars20%6 Read Seting up ES6 |Leanpu * transform-es2015-classes If you want to compile something that isn't part of the base syntax, you need both a syntax plugin and a corresponding transform plugin. However, each transform plugin that depends on a syntax plugin automatically activates that plugin. Plugins are installed via npm. Their package names are their names plus the prefix babel-plugin-: * Plugin syntax-jsx: npm install babel-plugin-syntax-jsx * Plugin transform-react-isx: npm install babel-plugin-transform-react-isx 4.2.2 Presets In order to configure Babel's output to your liking, you need to specify what plugins it should use. You can specify: * Individual plugins + Presets, sets of plugins that support various compilation scenarios. The following are useful presets: * 52015: compiles ES6 (as described by the ECMAScript spec) to ESS stage-3: compiles stage 3 ECMAScript proposals to ESS react: compiles JSX to JavaScript and removes Flow type annotations e52015-nodeS: Contains just those plugins that are needed to upgrade Node js 5 to full ES6. Therefore, a lot less is transpiled than with the es2015 preset. Especially generators not being transpiled helps with debugging. Presets are installed via npm. Their package names are their names plus the prefix babel-preset-. For example, this is how to install the ip:eareub comiseting pesbiread ours ars20%6 Read Seting up ES6 |Leanpu preset es2015: hpm install babel-preset-es2015 4.3 Sources of configuration data This section explains where configuration data can come from. 4.3.1 Primary source of configuration data: babeire The main source of configuration data is a file .babelrc that should be located close to the input file that you want to compile. Babel first looks for .babelrc in the same directory as the input file, then in that directory's parent directory, etc. The contents of .babeire are interpreted as JSON and used as Babel options. For example: t “presets” "es2015" ] 3 C The file .babelignore complements .babelrc: * Itis searched for independently of .babelrc, but in the same manner (by going through the ancestor directories of the input file), + It does not replace .babelrc; the two sets of data are merged, babelignore only specifies the option ignore: its lines are turned into an Array and interpreted as that option. 4.3.2 Alternative to babetre? packagejson Each npm package has a file packagejson. Babel allows you to use ip:eareub comiseting pesbiread saa ars20%6 Read Seting up ES6 Leong that file for configuration, as an alternative to .babelrc. Then it must have a property babel (otherwise Babel ignores package,json files). The value of that property is an object with configuration data. For example: "dependencies": { } "babel": { "presets": [ “es2015" ] } + Babel searches for packagejson in the same way that it searches for babelre, by going through the ancestor directories of the input file. If there is both a .babelrc and a package.json in the same directory then the former file wins. 4.3.3. Mixing in additional configuration data Two properties in configuration data specify additional configuration data: * Property env of maps the names of environments (development, ‘production’, etc.) to objects with more configuration data. If env exists, the object corresponding to the current environment is merged with the configuration data that has already been assembled, Consult the Babel documentation for more information on environments Property extends contains a path pointing to a file with more configuration data. 4.3.4 Secondary sources of configuration ip:eareub comiseting pesbiread 4074 ars20%6 Read Seting up ES6 |Leanpu data Be careful with secondary configuration data It is important to note that a secondary source of configuration data adds to .babelrc (or package.json), it doesn't replace it. That means that if you distribute a directory with your project, you should always include a .babelrc. Then Babel doesn't find and use one in an ancestor directory. Such a file could, for example, specify its own presets, which could interfere with your build process or even crash it (if one of the presets doesn't exist). 4.3.4.1. babel-node If you are using babel-node, you can specify the following options (and a few others) via the command line: + —presets + ~plugins + ~ignore: by default, any file that has the segment ‘node_modules' in its path is not transpiled The following command runs my-scriptjs via babel-node, with the presets es2015-nodeS and react, and the plugin transform-async-to-generator enabled. babel-node \ --presets es2015-nodeS, react \ --plugins transform-async-to-generator \ my-script.js ip:eareub comiseting pesbiread airs 462016 Read Setting up ESS | Leanpub 4.3.4.2 webpack The following is an excerpt of a webpack configuration file webpack.configs: var path = require('path'); module.exports = { module: { Joaders: [ { Joader: 'babel-loader’ test: path.resolve(_dirname, 'js'), query: { presets: ['es2015'], 3, + ] 3, As you can see, babel-loader supports the property query for specifying Babel options. 4.4. More information + The Babel docs are excellent. For example, this page explains the Babel options. The bar at the top gets you to other pages. + Additionally, the following files in Babel's source code are helpful for figuring out how it handles options * option- managers contains the algorithm for finding and merging Babel options * _babel-node,js contains the parameter handling code for babel-node * babel-register for Node,js is hosted here. 5. Babel: configuring standard library and ip:eareub comiseting pesbiread aaa ars20%6 Read Seting up ES6 |Leanpu helpers This chapter explains how to configure how Babel 6 accesses its own helper functions and the ES6 standard library. The following GitHub repo lets you play with what's explained here: babel-config-demo 5.1 Overview The code produced by Babel usually has two kinds of external dependencies: * Helper functions (e.g. for subclassing) * Standard library functionality (e.g. Map or ES6 string methods) There are two ways of fulfilling these dependencies: by installing functionality globally or via modules. In both cases the functionality is delivered as npm packages. 5.1.1 External dependencies via global variables The following npm packages install their functionality globally and let you access it via global variables: + (P) babel-plugin-external-helpers and (I) generated file: global helpers * (1) babel-polyfill: global standard library + ES5, ES6+, Regenerator runtime + (1) core-js: global standard library * core-js/shim: ES5, ES6+ * core-js/es6: ES6 Installation: ip:eareub comiseting apestiread ara 462016 Read Setting up ESS | Leanpub * (P) Plugin: install the npm package as a dev dependency and switch on the plugin in the Babel configuration data (see Chap. “Configuring Babel 6"). * (J) Import: install the npm package as a runtime dependency and import it when the program starts. 5.1.2 External dependencies via module imports The following npm packages enable dependencies via modules: * (P) babel-plugin-transform-runtime, (M) babel-runtime: helpers and standard library via imports (plugin generates imports). * Babel helpers (mandatory) * Standard library (can be switched off) + Regenerator API (can be switched off) * (M) core-js: standard library via modules. * Single entities: ‘import repeat from 'core-js/library/fn/strin 4 > + Namespace object (ESS, ES6+) import * as core from 'core-js/library'; const mystr = core.String.repeat('*", 10); + Namespace object (ES6): ‘import * as core from 'core-js/library/es6 const myStr = core.string.repeat('*', 10); Installation: ip:eareub comiseting pesbiread aa74 ars20%6 Read Setting up ESS | Leanpub + (P) Plugin: install the npm package as a dev dependency and switch on the plugin in the Babel configuration data (see Chap. “Configuring Babel 6"). + (IM) Module: install the npm package as a runtime dependency and import entities at runtime (as needed) 5.2 External dependencies of transpiled code The code generated by Babel usually has two kinds of external dependencies that need to be fulfilled. First, most code invokes functionality of the ES6 standard library. By default, you access this functionality via global variables: ‘let m = new MapQ; if (str. startswith('/')) Second, Babel has helper functions (e.g. for subclassing) that are called from the transpiled code. By default, the code of helper functions is inlined, inserted into each file. For example (_classCallCheck is a helper): M--~ -- Input: ES6 code class Person {} Mn -- Output: ESS code that uses helpers “use strict"; function _classcallcheckCinstance, Constructor) { if (!Ginstance instanceof Constructor)) { throw new TypeError("cannot call a class as a f i i var Person = function Person() { —classcallcheck (this, Person); ip:eareub comiseting pesbiread 474 anncore Read Sting up E55 Lord Inlined helpers lead to code duplication whenever the same helper is used in several files. There are two ways in which you can get the standard library and non-inlined helpers: via global variables and via module imports. How is explained in the next sections. 5.3 External dependencies via global variables 5.3.1 Helpers via a global variable: babe plugin-external-helpers There are two things you need to install: * Plugin babel-plugin-external-helpers’ * Install as development dependency: npm install --save-dev babel-plugin-external- 4 > * Switch on in Babel configuration data "plugins": ["external-helpers"] * File that sets up global variable babelHelpers: + Must be loaded or imported at runtime, as early as possible. Eg: ‘import 'babelHelpers'; + Generated via command line tool babel-externakhelpers (how is explained in the next section). * Install babel-external-helpers as a development dependency: npm install --save-dev babel-cli ip:eareub comiseting pesbiread 4074 ane20%6 Read Seting up ES6 | Leanpib The plugin ensures that all helpers are invoked via methods of the global object babelHelpers. In this section, I'll explain how that works. In the next section, I'll explain how to set up babelHelpers. As an example, consider the following ES6 code, before transpilation: class Point { constructor(x, y) { this.x = x; this.y = y; 3 tostring®) { return “(S{this.x}, S{this.y})"; 3 If you transpile it with the es2015 preset and without external-helpers, you get: “use strict"; var -createClass = (function © { HO : . function _classcallcheck(instance, Constructor) { t var Point = (function © { function Point(x, y) { —classcallcheck(this, Point); this.x = x5 this.y = ys 3 —createclass (Point, [{ key: "tostring”, value: function tostring() { return "(" 4+ this.x +", "+ this.y + ")"G ip:eareub comiseting pesbiread arms ars20%6 Read Seting up ES6 |Leanpu + Ws return Point; HOF Note the two helper functions _createClass and _classCallCheck. If you switch on the plugin external-helpers, you get this output: “use strict"; var Point = (function © { function Point(x, y) { babelHelpers .classcalIcheck(this, Point); this.x this.y = y; 3 babelHelpers.createclass(Point, [{ key: “tostring” value: function tostring®) { return "(" + this.x +", "+ this.y + ")"; + WD; return Point; HO: 5.3.1.1 Installing the global Babel helpers How do you install the object with the helpers into the global variable babelHelpers? Via a file generated by the command line tool babel-externathelpers. The tool is part of the npm package babel-cli. The file is available in three formats: * babel-external-helpers -t global prints a Node,js module that puts the helpers into global.babelHelpers. * babel-external-helpers -t var ip:eareub comiseting pesbiread 4074 ars20%6 Read Seting up ES6 Leong prints a script file (browser code) that var-declares babelHelpers in global scope and assigns it an object with the helpers. babel-external-helpers -t umd prints a Universal Module Definition (UMD) that works as CommonJS module, AMD module and as a script (via a global variable) This invocation prints usage information: babel-external-helpers --help 5.3.2 Standard library and more via global variables: babet-polysin The package babel-polyfill contains a module that installs several things into global variables: ESS polyfills (whatever is missing from the ESS standard library): Object.create(), Array.prototype-forEach(), etc. ES6 polyfills: Map, String.prototype.repeat(), etc. A few polyfills of ECMAScript feature proposals: Objectentries(), Array.prototype.includes(), etc. The runtime for Regenerator (which is used by Babel to transpile ES6 generators to ESS). The polyfills are provided by core-js, which you can see if you look at the two import statements making up this module: ‘import “core-js/shim"; ‘import “babel-regenerator-runtime"; 5.3.2.1 Installation Install babel-polyfill via npm as a runtime dependengy if you find that any of the aforementioned functionality is missing in your transpiled code. In current Node,js versions, you may be able to get ip:eareub comiseting pesbiread 4974 ars20%6 Read Seting up ES6 |Leanpu by without using it, because those versions come with much of the ES6 standard library and native generators. The module is installed via: npm install --save babel-polyfi11 You must import it before you use the standard library: import "babel-polyfil1"; The module will check global variables and only install missing functionality. The downside of the polyfill is that you always deliver and load all of the functionality, independently of how much you use. 5.3.3. Just the standard library via global variables: core-js If you don't need the Regenerator runtime, you can use the core-js polyfill directly. You install it like this: hpm install --save There are several ways in which you can install the polyfill functionality. Two common ones are: * import ‘core-js/shim'; Polyfills ESS, ES6 and some post-ES6 functionality. * import ‘core-js/es6'; Polyfills just ES6 functionality. ip:eareub comiseting pesbiread sara anncore Read Sting up E55 Lord The import statement needs to happen before you access the runtime library. It installs the polyfills globally. 5.4. External dependencies via module imports 5.4.1 Helpers and standard library via iMPOTts: babel-plugin-transform-runtime Two pieces are needed for this approach: * Amodule that contains helpers and standard library. Install as a runtime dependency: npm install --save babel-runtime + Aplugin that changes Babel output so that helpers and standard library are imported from babel-runtime. * Install as a development dependency pm instal] --save-dev babel-plugin-transform 4 > * Switch on in Babel configuration data: "plugins": ["transform-runtime"] The plugin redirects three kinds of operations to imports from babel- runtime: 1, Babel helpers (mandatory) 2, Standard library (can be switched off) 3. Regenerator API (can be switched off): used by babel-plugin-transform- regenerator to transpile ES6 generators to ESS code babel-runtime becomes a runtime dependency, but the import statements are created by the plugin - you do not need to import tipeearpucometing-eetead sw ane20%6 Read Seting up ES6 Leong anything. The plugin lets you switch off #2 and #3 as follows: “plugins' C ("transform-runtime", { "polyfill": false, “regenerator”: false }1, The next two sections explore how «ransform-runtime works for helpers and for the standard library. 5.4.2 transform-runtime and Babel helpers transforrn-runtime works well for the helpers. Consider the following ES6 code: class Point { constructor(x, y) { this.x = x; this.y = y; 3 tostring) { return “(S{this.x}, S{this.y})"; 3 With the plugin, this is transpiled to: “use strict"; var _classcallcheck2 = require("babel-runtime/helpers/c var _classcallcheck3 = _interopRequirebefault(_classcal var _createClass2 require("babel-runtime/helpers/crea var —createClass3 = _interopRequireefault (createclass ip:eareub comiseting pesbiread sama anerote Read Seting up ES6 Leong function _interoprequiredefault (obj) { return obj && obj._esmodule ? obj : { default: obj 3 var Point = (function © { function point(x, y) { (0, _classcal1check3.default) (this, Point); this.x = x; this.y = yi t (0, —createclass3.default) (Point, [{ key: “tostring™ value: function tostring®) { return "(" + this.x +", "+ this.y + "D"; + Ds return Point; HOF The helpers classCallCheck (line A) and createClass (line B) are now imported from babel-runtime. Note that each function sits in its own module, which ensures that only functions you actually use end up in bundled code. The helper function _interopRequireDefault ensures that either plain Commonjs modules or transpiled ES6 modules can be used. The details of how Babel compiles ES6 modules to Commons modules are described in Chap. “Babel and Commonjs modules”. 5.4.3 transform-runtime and the standard library The plugin transform-runtime handles helpers automatically, but for much of the standard library, extra work is required. Let’s examine ip:eareub comiseting pesbiread saa ars20%6 Read Seting up ES6 |Leanpu the support for the following ways of accessing the standard library: + Accessing functions (supported) * Accessing methods normally (not supported) * Accessing methods via custom utility functions (supported) 5.4.3.1 Accessing functions (supported) transform-runtime does properly detect function invocations: namespaced functions (such as Object.assign and Math.sign) and constructors (such as Map and Promise). Take, for example, the following ES6 code: Jet m= new mapO; Math. sign(-1); This code is transpiled to: "use strict"; var sign = require("babel-runtime/core-js/math/sign") ; var _sign2 = _interopRequirebefault(_sign); var _map = require("babel-runtime/core-js/map"); // (8) var _map2 = _interopRequirepefault map) ; function _interopRequirebefault(obj) { return obj && obj._esModule ? obj : { default: obj + var m = new _map2.defaultQ; (0, -sign2.default)(-1); Note the imports in line A and line B. 5.4.3.2 Accessing methods normally (not ip:eareub comiseting pesbiread Sura ars20%6 Read Seting up ES6 |Leanpu supported) However, transform-runtime does not detect method calls like those in the following ES6 code: console. log('a'. repeat (3)); console. log(String.prototype.repeat.call("b’, 3)); This is transpiled to: "use strict’; console. 1og('a' repeat (3); console. log(string.prototype.repeat.call("b", 3)); There are no imports - the input code in basically untouched. The first method calll is dynamically dispatched, so it’s not surprising that transform-runtime doesn't catch it. However, the second method call is direct and ignored, too. 5.4.3.3 Accessing methods via custom utility functions (supported) transform-runtime provides a work-around for method calls - utility functions attached to constructors. You can use them to replace method calls such as this one: "ct repeat (3); With an invocation of a utility function: string.repeat('c', 3); Transpiled, the code looks like this (note the import in line A): ‘use strict; ip:eareub comiseting pesbiread sora ane20%6 Read Seting up ES6 Leong var _repeat = require('babel-runtime/core-js/string/rep var _repeat2 = _interoprequireDefault(_repeat); function —interoprequiredefault (obj) { return obj & obj._esModule ? obj : { default: obj 3 (0, -repeat2.default)('c', 3); 5.4.3.4 Babel’s polyfilling is based on core-js If you look back, all imports generated by transform-runtime use module IDs that start with babel-runtime/core-js. That's because Babel's polyfilling is based on the library core-js. You can look up how transform-runtime maps identifiers and chained property accesses to core-js modules in the repository file definitions.s, This is an excerpt: module.exports = { builtins: { set: "set", 3 methods: { Array: { from: “array/from", 3 string: { repeat: "string/repeat", That means that transform-runtime provides Set, Array.from), String.repeat() tips earpucomsting--eetiead ars20%6 Read Seting up ES6 |Leanpu and more. 5.4.4 core-js: Standard library via modules Given that transform-runtime requires you to access properties of built- in constructors if you want to make a method call, using core-js directly is a useful alternative to that plugin. Install it as a runtime dependency: npm install --save core-js One way of accessing standard library functionality non-globally is via a single library object: ‘import * as core from 'core-js/library'; const mySet = new core.Set([1, 2, 3, 2, 1]); const myArr = core.Array.from(myset) const myStr = core.String.repeat('*" 10); As for the content of the library object, you have a choice between: * core-js/library: polyfills ES5, ES6 and a few proposed features. * core-js/library/es6: polyfills just ES6. Another way of accessing standard library functionality non-globally is to import entities individually: ‘import _set from 'core-js/library/fn/set'; ‘import _from from ‘core-js/library/fn/array/from’ ; ‘import _repeat from 'core-js/library/fn/string/repeat' ; const mySet = new _set([1, 2, 3, 2, 1]); const myArr = _from(mySet) ; const myStr = _repeat('*', 10); ip:eareub comiseting pesbiread srs ars20%6 Read Seting up ES6 |Leanpu 5-5 What should I use when? For libraries, you must not touch global variables, which is why everything must come from imports: Babel helpers: babel-plugin-transform-runtime and babel-runtime work well. Regenerator runtime: The previous combo also provides the regenerator runtime via imports. If you don't use or transpile generators then you can switch off this part of babel-plugin- transform-runtime, Standard library: | don't like that babel-plugin-transform-runtime enables ES6 methods (e.g. Array.prototype.repeat()) via non- standard global methods (e.g. Array.repeat()). It'd switch this part of the plugin off and use core-js directly. For apps, you can use a mixed approach: Use Babel helpers and - if necessary - the Regenerator runtime via module imports, as explained for libraries Install the ES6 standard library globally. Modules have the advantage that a bundler will only deploy the functionality that is actually used by the app. But a global polyfill lets you write code that will eventually run natively without any changes. | find that more important. Given that Regenerator is already taken care of, you don’t need babel-polyfill; core-js is enough. Non-redundant Babel helpers are always just an optimization, but especially for large code bases, it is worth it because of space savings. Acknowledgements. Thanks to Denis Pushkarev (@zloirock) and Paul Klimashkin for their feedback on this content. 6. Babel’s loose mode ip:eareub comiseting pesbiread sara ars20%6 Read Seng wp ES5 | Leapid Babel's loose mode transpiles ES6 code to ES5 code that is less faithful to ES6 semantics. This chapter explains how that works and what the pros and cons are (spoiler: normally not recommended). 6.1 Two modes Many plugins in Babel have two modes: * Anormal mode follows the semantics of ECMAScript 6 as closely as possible. * A loose mode produces simpler ES5 code Normally, it is recommended to not use loose mode. The pros and cons are: * Pros: The generated code is potentially faster and more compatible with older engines. It also tends to be cleaner, more “ESS-style” + Con: You risk getting problems later on, when you switch from transpiled ES6 to native ES6, That is rarely a risk worth taking. 6.1.1 Switching on loose mode The preset es2015-loose is the loose version of the standard ES6 preset, es2015. The preset’s code provides a good overview of what plugins have a loose mode and how to switch it on. This is an excerpt: module.exports = { plugins: [ [require("babel-plugin-transform-es2015-classes"), require("babel-plugin-transform-es2015-object-super ip:eareub comiseting pesbiread sara ars20%6 Read Seting up ES6 |Leanpu This is a CommonjS module where you can use all of ECMAScript 5. If you configure Babel via .babelrc or package.json (etails), you need to use JSON. You can either include the whole preset: “presets”: [ "es2015-loose", Or you can include plugins individually: "plugins": [ ["transform-es2015-classes", {loose: true}], “transform-es2015-object-super", i, 6.2 Example: the output of normal mode and loose mode Let's see how the modes affect the transpilation of the following code. class Point { constructor(x, y) { this.x = x; this.y 3 tostringO { return “(S{this.x}, S{this.y})"; 3 ip:eareub comiseting pesbiread 74 462016 Read Setting up ESS | Leanpub 6.2.1 Normal mode In normal mode, the prototype methods of the class are added via Object.defineProperty (line A), to ensure that they are non-enumerable, as required by the ES6 spec. “use strict"; var _createclass = (function © { function defineProperties (target, props) { for (var i = 0; i < props.length; i=+) { var descriptor = props[il; descriptor.enumerable = descriptor.enumerab descriptor.configurable = true; if C"value" in descriptor) descriptor.writa object .defineProperty(target, descriptor. ke 3 return function (Constructor, protoProps, staticPro if (protoprops) defineProperties (constructor. pr if (staticprops) defineproperties (constructor return Constructor; Ho; function _classcallcheck(instance, Constructor) { if (\Cinstance instanceof Constructor)) { throw new TypeError("cannot call a class as a f var Point = (function © { function Point(x, y) { _classCallcheck(this, Point); this.x = x; this.y = y; —createclass(Point, [{ key: "tostring”, value: function tostring® { return "(" + this.x +", "+ this.y + ")" + Ws ip:eareub comiseting pesbiread ours ars20%6 Read Seting up ES6 |Leanpu return Point; YO: 6.2.2 Loose mode In loose mode, normal assignment is used to add methods (line A). This style is more like you'd hand-write code in ESS. “use strict"; function _classcallcheck(instance, Constructor) { +++ } var Point = (function © { function Point(x, y) { -classcallcheck(this, Point); this.x this.y = y; + Point.prototype.tostring = function tostringO { // return "(" + this.x +", "+ this.y + ")"5 oH return Point; HO: 7. Babel and CommonJS modules This chapter examines how Babel ensures that code it transpiles interoperates properly with normal Common|s modules. Consult chapter “Modules” in “Exploring ES6” for more information on ES6 modules. 7.1 ES6 modules vs. CommonJS modules 7.11 ECMAScript 6 modules Default export (single export): ip:eareub comiseting pesbiread outa ars20%6 Read Seting up ES6 |Leanpu // Vib.is export default function () {} // wain.js ‘import lib from './lib Named exports (multiple exports): // Vib.is export function fooO (} export function barO {} // mainl.js ‘import * as lib from './1ib'; Vib. foo; Tib.barQ; // main2.js ‘import {foo, bar} from './1ib'; Foo); barQ; It is possible to combine both styles of exports, they don’t conflict with each other. 7.1.2 CommonJS modules Single export: // Vib.is module.exports = function () {}; // main.js var lib = require('./lib'); Multiple exports: // Vib.js exports. foo = function © {}; exports.bar = function O 0: ip:eareub comiseting pesbiread oars ars20%6 Read Seting up ES6 Leong // mainl.js var lib = requireC’./1ib"); Vib. foo; Vib.barO; // main2.js var foo = require('./lib').fo0; var bar = require('./lib') bar; foo); barQ; Single exports and multiple exports are mutually exclusive. You have to use either one the two styles, Some modules combine both styles as follows: function defaultexport() {} defaultexport.foo = function © { defaultexport.bar = function ©) (3; module.exports = defaultexport; 7.1.3 Comparing the two modules formats ES6 modules have two advantages over Commonjs modules. First, their rigid structure makes them statically analyzable. That enables, e.g,, tree shaking (dead code elimination) which can significantly reduce the size of bundled modules. Second, imports are never accessed directly, which means that cyclic dependencies are always supported. In Commons, you must code like this, so that the exported entity foo can be filled in later: var lib = require('./1ib'); Tib. foo); In contrast, this style of importing does not work (neither do single exports via module.exports): ip:eareub comiseting pesbiread oars ars20%6 Read Seting up ES6 |Leanpu var foo foo); require('./1ib').foo; More information on cyclic dependencies: Section "Support for cyclic dependencies” in “Exploring ES6”. 7.2 How Babel compiles ES6 modules to CommonJS As an example, consider the following ES6 module. export function fooO (}; export default 123; Babel transpiles this to the following Common]s code: “use strict"; object.defineproperty (exports, "__esModule” value: true Di exports. foo = foo; function foo) {}; exports.default = 123; The following subsections answer questions you may have about this code: * Why isn't the default export done like a Commonls single export? * Why mark transpiled £56 modules with the flag _esModule? 7.2.1 Why isn’t the default export done like a CommonJS single export? Answer: There are three reasons for doing so. First, it is closer to ES6 semantics. ip:eareub comiseting pesbiread ora ars20%6 Read Seting up ES6 |Leanpu Second, you prevent scenarios like the following. // Vib.js export default { foo: © => {}, bar: O => {, 3 // main.js ‘import {foo,bar} from './lib'; This is illegal in native ES6 and Babel shouldn't let you do that. Third, you want to support doing a default export and named exports at the same time. You could treat a module with just a default export like a single-export Common|S module: // Vib_es6. js export default ‘abc'; // wain_cjs.js var lib = require('./lib_es6"); // "abc" However, then the exports would change completely if you add a named export: // Vib_es6. is export default 'abc'; export var foo = 123; // wain_cjs.js var lib = require('./lib_es6"); // { foo: 123, default: ‘abc’ } 7.2.2. Why mark transpiled ES6 modules with the flag _ esnodute? The flag enables Babel to treat non-ES6 Commons modules that have single exports as if they were ES6 modules with default exports. How that is done is examined in the next section. ip:eareub comiseting pesbiread ou74 ars20%6 Read Seting up ES6 |Leanpu 7.3. How Babel imports CommonjJS modules 7.3.1 Default imports This ES6 code: import assert from ‘assert’; assert(true); is compiled to this ESS code: ‘use strict’; function _interopRequiredefaultCobj) { return obj & obj._esModule ? obj : { ‘default’: obj }; } var _assert = require('assert'); var _assert2 = _interopRequirebefault(_assert); (0, _assert2['default']) (true); // (A) Explanations: * _interopRequireDefault(): An ES6 CommonJS module is used as is (if it has a default export then it has a property named default). A normal CommonJS module becomes the value of the property default. In other words, in the later case, the module’s exports become the default export. Note that the default export is always accessed via the exports object _assert2 (line A), never directly, like this: var assert = _assert2.default; The reason for that is support for cyclic dependencies. * (0, _assert2[‘default’]) is done so that the invocation in line Ais a pe:eareub comiseting pesbiread ons ars20%6 Read Seting up ES6 |Leanpu function call, not a method call (with this =: 7.3.2 Namespace imports This ES6 code: import * as assert from 'assert'; assert.ok(true) ; is compiled to this ESS code: ‘use strict’; function _interoprequirewildcard(obj) { if (obj && obj._esmodule) { return obj; 3 else { var newobj = {}; // (A) if (obj != null) £ for (var key in obj) { ‘if (object.prototype.hasownProperty.cal newobj key] = obj [key]; + + newobj.default = obj; return newobj; + var _assert = require('assert'); var assert = _interopRequirewildcard(_assert); assert.ok(true) ; Explanations: * _interopRequireWildcard(): CommonJS exports are translated to an object where the named exports are the properties of the exports objects and the default exports is (yet again) the exports object, The module assert is an example of where a epe:eareub comiseting pestiread ura ars20%6 Read Setting up ESS | Leanpub normal CommonJS module mixes a single export with multiple exports and the Babel work-around translates such a module to the world of ES6 import assert, {ok} from ‘assert’; assert accesses a default export, (ok) accesses a named export. * Babel creates a new object (line A), because it must not modify the original exports object 7.3.3. Named imports This ES6 code: import {ok} from ‘assert’; okQ; is compiled to this ESS code: ‘use strict’; var _assert = require('assert'); (0, _assert.ok)Q; Again, you can see that ok) is never accessed directly, always via _assert, which ensures that cyclic dependencies work. 7.4. Recommendations You need to look very closely at what a module exports and then choose the appropriate way of importing. For example, conceptually, the Node.js module fs is clearly a collection of named exports, not a single export (an object). Therefore, while both of the following two ways of importing this module work, the second one ip:eareub comiseting pesbiread 974 ars20%6 Noo w Read Seting up ES6 |Leanpu is the better choice. ‘import fs from 'fs'; // no ‘import * as fs from 'fs'; // recommended If you want to future-proof your normal CommonjS module, you should opt for either a single export or multiple named exports, but not for mixing styles (attaching named exports as properties of a single export). 8. The future of bundling JavaScript modules This chapter examines how the bundling of modules is affected by two future developments: HTTP/2 and native modules. 8.1 Why we bundle modules Bundling modules means combining several files with modules into asingle file. That is done for three reasons: Fewer files need to be retrieved in order to load all modules. Compressing the bundled file is slightly more efficient than compressing separate files During bundling, unused exports can be removed, potentially resulting in significant space savings. 8.2 JavaScript modules With ECMAScript 6, JavaScript finally got built-in modules (I'm calling them JavaScript modules for the remainder of this chapter). However, that feature is currently in a strange position: On one hand, ES6 fully standardized their syntax and much of their semantics. They have become a popular format for writing modules and their static structure enables the automatic omission of unused ip:eareub comiseting pesbiread a4 ars20%6 Read Seting up ES6 |Leanpu exports (also known as “tree-shaking" in the JavaScript world). On the other hand, standardizing how to load JavaScript modules is ongoing and no JavaScript engine supports them natively, yet. That means that, at the moment, the only way of using JavaScript modules is by compiling them to a non-native format. Popular solutions are: browserify, webpack, jspm and Rollup. 8.3. Future developments and bundling Let’s look at two future developments and how they affect the bundling of JavaScript modules. 8.3.1 Future development: HTTP/2 HTTP/2 is slowly being rolled out. It mainly affects reason #1 for bundling: With HTTP/2, the cost per request has decreased considerably compared to HTTP/1, which means that there are practically no performance gains if you download a single file instead of multiple ones. That enables smaller, more incremental updates: With bundling, you always need to download the complete bundle. Without bundling, you only need to download the parts that have changed (while the other parts are often still in the browser cache). However, reasons #2 and #3 for bundling are not negated by HTTP/2. Therefore, mixed approaches may be adopted in the future, to optimize for both incremental updates and minimal total download size. 8.3.2 Future development: native JavaScript modules Once engines support native JavaScript modules, will that affect bundling? Even AMD modules - which run natively in browsers - have a custom bundle format (along with a minimal loader). Will native JS modules be different? It looks like they will. Rollup lets you ip:eareub comiseting pesbiread rma ars20%6 Read Seting up ES6 |Leanpu bundle multiple JS modules into a single JS module. Take, for example, these two JS modules: // Vib.is export function fooQ) {} export function barQ {} // wain.js ‘import {foo} from './Tib.js'; console. 1og(foo()); Rollup can bundle these two JS modules into the following single JS module (note the eliminated unused export bar): function foo {} console. log(foo()); Initially, it wasn’t a given that JavaScript modules would work as a bundle format - quoting Rollup’s creator Rich Harris: When | started writing Rollup, it was an experiment that | wasn't certain would succeed. The way imports are handled by JS modules helps with bundling: they are not copies of exports, they are read-only views on them. Rollup’s site has a nice interactive playground where you can try it out. 8.4 Further reading * “Building for HTTP/2" by Rebecca Murphey (explains how best practices change - often radically - with this new version of HTTP) * Chap. “Modules” in “Exploring ES6" (explains how ES6 modules ip:eareub comiseting pesbiread rama ars20%6 Read Seting up ES6 |Leanpu work) + Chap. “Babel and CommonJs modules” in this book (explains how Babel ensures that transpiled ES6 modules interoperate properly with CommonJS modules) About Leanpub What is Leanpub? Blog Buzz Testimonials, Podcast Press Contact Us Readers In-Progress & Serial Publishing Ebook Formats With No DRM Variable Pricing 100% Happiness Guarantee Interacting With Authors The Leanpub App Kindle Support Reader FAQ Reader Help Authors Leanpub For Authors How To’ Introduction Writing With Leanpub Writing In Word Publishing With Leanpub Royalties and Payments Leanpub Book Pricing ip:eareub comiseting pesbiread rama ane20%6 Rees Seg ip ES6 Leap Uploading A Book Packaging Books With Videos The Lean Publishing Manifesto ‘Author Manual ‘Author FAQ ‘Author Help Books Asile Data Science Computer Programming Fiction Non-Fiction More.. More Leanpub for Causes Publishers Friends of Leanpub Terms of Service Copyright Take Down Policy Privacy Policy Leanpub is copyright © 010-2016 Ruboss ip:eareub comiseting pesbiread ata

Das könnte Ihnen auch gefallen