diff --git a/.npmignore b/.npmignore index 2f58445743..7031ae4f97 100644 --- a/.npmignore +++ b/.npmignore @@ -3,5 +3,6 @@ node_modules *.cache lib/6to5/templates test +benchmark Makefile .* diff --git a/FEATURES.md b/FEATURES.md index f00b09e2de..3a72a4f7d1 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -99,18 +99,16 @@ for (var i of [1, 2, 3]) { ```javascript var obj = { - bar: "foobar", - foo() { return "foobar"; }, get bar() { - + return this._bar; }, - set bar() { - + set bar(val) { + this._bar = val; } }; ``` @@ -131,7 +129,7 @@ function printList(name, ...items) { items.forEach(function (item) { console.log(item); }); -}; +} ``` ## Spread diff --git a/Makefile b/Makefile index 3e6fad7629..636a84fca2 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ MOCHA_CMD = node_modules/mocha/bin/_mocha export NODE_ENV = test -.PHONY: clean test test-cov test-travis publish +.PHONY: clean test test-cov test-travis publish bench clean: rm -rf coverage templates.json @@ -11,6 +11,9 @@ clean: test: $(MOCHA_CMD) +bench: + node node_modules/matcha/bin/_matcha + test-cov: make clean node $(ISTANBUL_CMD) $(MOCHA_CMD) -- diff --git a/README.md b/README.md index d8d932ef17..7a45304f78 100644 --- a/README.md +++ b/README.md @@ -189,25 +189,36 @@ limitations in ES5 implementations. | | 6to5 | Traceur | esnext | es6now | es6-transpiler | | -------------------------- | ---- | ------- | ------ | ------ | -------------- | -| No runtime required | ✓ | | | | ✓ | -| -------------------------- | ---- | ------- | ------ | ------ | -------------- | -| Array comprehension | ✓ | | ✓ | | ✓ | -| Arrow functions | ✓ | | ✓ | ✓ | ✓ | -| Block binding | ✓ | | | | ✓ | -| Classes | ✓ | | ✓ | ✓ | ✓ | -| Computed property names | ✓ | | ✓ | ✓ | ✓ | -| Constants | ✓ | | | | ✓ | -| Default parameters | ✓ | | ✓ | ✓ | ✓ | -| Destructuring | ✓ | | ✓ | ✓ | ✓ | -| For-of | ✓ | | ✓ | ✓ | ✓ | -| Generator comprehension | | | ✓ | | ✓ | -| Generators | | | ✓ | | | -| Modules | ✓ | | | ✓ | | -| Property method assignment | ✓ | | ✓ | ✓ | ✓ | -| Property name shorthand | ✓ | | ✓ | ✓ | ✓ | -| Rest parameters | ✓ | | ✓ | ✓ | ✓ | -| Spread | ✓ | | ✓ | ✓ | ✓ | -| Template literals | ✓ | | ✓ | ✓ | ✓ | +| No runtime | ✓ | | | | ✓ | +| Source maps | ✓ | ✓ | ✓ | | ✓ | +| **Compiler usage:** | | | | | | +| No global pollution | ✓ | | ✓ | | ✓ | +| **Syntax features:** | | | | | | +| Array comprehension | ✓ | ✓ | ✓ | | ✓ | +| Arrow functions | ✓ | ✓ | ✓ | ✓ | ✓ | +| Block binding | ✓ | ✓ | | | ✓ | +| Classes | ✓ | ✓ | ✓ | ✓ | ✓ | +| Computed property names | ✓ | ✓ | ✓ | ✓ | ✓ | +| Constants | ✓ | ✓ | | | ✓ | +| Default parameters | ✓ | ✓ | ✓ | ✓ | ✓ | +| Destructuring | ✓ | ✓ | ✓ | ✓ | ✓ | +| For-of | ✓ | ✓ | ✓ | ✓ | ✓ | +| Generator comprehension | | ✓ | ✓ | | ✓ | +| Generators | | ✓ | ✓ | | | +| Modules | ✓ | ✓ | | ✓ | | +| Property method assignment | ✓ | ✓ | ✓ | ✓ | ✓ | +| Property name shorthand | ✓ | ✓ | ✓ | ✓ | ✓ | +| Rest parameters | ✓ | ✓ | ✓ | ✓ | ✓ | +| Spread | ✓ | ✓ | ✓ | ✓ | ✓ | +| Template literals | ✓ | ✓ | ✓ | ✓ | ✓ | + +#### Performance + + $ make bench + +![Output size (including runtime) (lower is better)](http://i.imgur.com/hAybrA2.png) + +![Compile speed (higher is better)](http://i.imgur.com/yMwMvhg.png) ### [Traceur](https://github.com/google/traceur-compiler) @@ -215,10 +226,6 @@ Traceur requires quite a bulky runtime (~75KB) and produces quite verbose code. While this can be trimmed down by selectively building the runtime, it's an unneccesary step when a runtime can be eliminated entirely. -Instead of mapping to a runtime, 6to5 maps directly to the equivalent ES5. This -means that your transpiled code will be as simple as possible and is -**exactly** the equivalent ES5. - ### [esnext](https://github.com/esnext/esnext) esnext is **slow**, painfully so. Runtime required. @@ -229,13 +236,9 @@ Doesn't output sourcemaps. This is cited as a positive as line-to-line mapping is the goal. This however obviously doesn't retain column mapping resulting in the output code not being very pleasant. -Runtime required. - ### [es6-transpiler](https://github.com/termi/es6-transpiler) -Requires shims to compile and pollutes the global scope resulting in possible -collisions. - -## Performance - - $ make bench +es6-transpiler requires shims to compile and pollutes the global scope resulting +in possible collisions. es6-transpiler maps line-by-line, just like es6now, this +results in the same issues such as lack of column information and unpleasant +code output. diff --git a/benchmark/fixtures/all.js b/benchmark/fixtures/all.js new file mode 100644 index 0000000000..2082915c93 --- /dev/null +++ b/benchmark/fixtures/all.js @@ -0,0 +1,99 @@ +var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; +var obj = {}; +var foo = "foo"; +var bar = "bar"; + +// constants +const MULTIPLIER = 5; + +// classes +class Foo { + constructor() { + this.foo = "bar"; + } +} + +class Bar extends Foo { + constructor() { + super(); + } + + // default parameters + go(foo = "bar", bar = "foo") { + + } + + get foo() { + return this._foo; + } + + set foo(val) { + this._foo = val + " foo!"; + } +} + +// arrow functions +arr.map(x => x * x); + +// block binding +for (let key in arr) { + let val = arr[key]; + console.log(key, val); +} + +// computed property names +obj = { + ["foo" + bar]: "foobar" +}; + +// destructuring +var [a, [b], c, d] = ["hello", [", ", "junk"], ["world"]]; +console.log(a + b + c); + +// array comprehension +// [for (i of [1, 2, 3]) i * i]; // not supported by es6now + +// for-of +for (var i of [1, 2, 3]) { + console.log(i * i); +} + +// property method assignment +obj = { + foo() { + return "foobar"; + }, + + get bar() { + return this._bar; + }, + + set bar(val) { + this._bar = val; + } +}; + +// property name shorthand +function f(x, y) { + return { x, y }; +} + +// rest parameters +function printList(name, ...items) { + console.log("list %s has the following items", name); + items.forEach(function (item) { + console.log(item); + }); +} + +// spread +function add(x, y) { + return x + y; +} +var numbers = [5, 10]; +add(...numbers); + +// template literals +var x = 5; +var y = 10; +console.log(`${x} + ${y} = ${x + y}`); diff --git a/benchmark/index.js b/benchmark/index.js new file mode 100644 index 0000000000..52298ea8a7 --- /dev/null +++ b/benchmark/index.js @@ -0,0 +1,88 @@ +Error.stackTraceLimit = Infinity; + +var traceur = require("traceur"); +var es6tr = require("es6-transpiler"); +var es6now = require("es6now"); +var esnext = require("esnext"); +var to5 = require("../lib/6to5/node"); + +var matcha = require("matcha"); +var stream = require("stream"); +var path = require("path"); +var fs = require("fs"); +var vm = require("vm"); +var _ = require("lodash"); + +var readResolve = function (filename) { + return fs.readFileSync(require.resolve(filename), "utf8"); +}; + +var compilers = { + "6to5": { + compile: function (code, filename) { + return to5.transform(code, { filename: filename }); + } + }, + + traceur: { + runtime: readResolve("traceur/bin/traceur-runtime.js"), + compile: function (code, filename) { + return traceur.compile(code, { + modules: "commonjs", + experimental: true + }); + } + }, + + esnext: { + runtime: readResolve("esnext/node_modules/regenerator/runtime.js"), + compile: function (code, filename) { + return esnext.compile(code).code; + } + }, + + es6now: { + runtime: readResolve("es6now/runtime/ES6.js"), + compile: function (code, filename) { + return es6now.translate(code); + } + }, + + "es6-transpiler": { + compile: function (code, filename) { + var result = es6tr.run({ src: code }); + if (result.errors.length) throw new Error(result.join("; ")); + return result.src; + } + } +}; + +_.each(fs.readdirSync(__dirname + "/fixtures"), function (name) { + var alias = path.basename(name, path.extname(name)); + + suite(alias, function () { + set("delay", 0); + + var loc = __dirname + "/fixtures/" + name; + var code = fs.readFileSync(loc, "utf8"); + + before(function () { + _.each(compilers, function (compiler, name) { + var output = compiler.compile(code, loc); + if (compiler.runtime) output = compiler.runtime + "\n" + output; + + var kilo = (output.length / 1024).toFixed(2); + console.log( + matcha.utils.color(matcha.utils.padBefore(kilo + "KB", 22), "cyan"), + matcha.utils.color("» " + name, "gray") + ); + }); + }); + + _.each(compilers, function (compiler, name) { + bench(name, function () { + compiler.compile(code, loc); + }); + }); + }); +}); diff --git a/package.json b/package.json index 80ab538481..db93c803b6 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,24 @@ "6to5": "./bin/6to5", "6to5-node": "./bin/6to5-node" }, + "keywords": [ + "es6-transpiler", + "scope", + "harmony", + "blockscope", + "block-scope", + "let", + "const", + "var", + "es6", + "transpile", + "transpiler", + "traceur", + "6to5" + ], "scripts": { - "test": "mocha" + "bench": "make bench", + "test": "make test" }, "dependencies": { "ast-types": "0.5.0", @@ -32,7 +48,12 @@ "es6-shim": "^0.18.0" }, "devDependencies": { + "es6-transpiler": "0.7.17", + "istanbul": "0.3.2", + "matcha": "0.5.0", "mocha": "1.21.4", - "istanbul": "0.3.2" + "traceur": "0.0.66", + "esnext": "0.11.1", + "es6now": "0.8.11" } }