From ab9cd4e630971fb9cad89943e45c4182480b8902 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Sun, 9 Nov 2014 12:02:06 +1100 Subject: [PATCH] add support for an optional runtime - closes #129 --- Makefile | 4 +- README.md | 90 +++++++++++++++++++++++++++++++++++++++++++-- bin/6to5-runtime | 4 ++ bin/6to5/index.js | 2 + lib/6to5/file.js | 51 +++++++++++++++---------- lib/6to5/index.js | 2 + lib/6to5/runtime.js | 44 ++++++++++++++++++++++ package.json | 3 +- 8 files changed, 175 insertions(+), 25 deletions(-) create mode 100755 bin/6to5-runtime create mode 100644 lib/6to5/runtime.js diff --git a/Makefile b/Makefile index 2274e81ee4..96de83b3d0 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,8 @@ publish: make build cp dist/6to5.js browser.js + node bin/6to5-runtime >runtime.js + node bin/cache-templates test -f templates.json @@ -64,4 +66,4 @@ publish: git push --follow-tags - rm -rf templates.json browser.js + rm -rf templates.json browser.js runtime.js diff --git a/README.md b/README.md index f58af6a14b..d01ec44642 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ It's as easy as: - [Browser](#browser) - [Modules](#modules) - [Caveats](#caveats) +- [Runtime](#runtime) - [Differences](#differences) ## [Features](FEATURES.md) @@ -177,7 +178,12 @@ to5.transformFile("filename.js", options, function (err, result) { // Set `sources[0]` on returned source map. // Default: `filename` option. - sourceFileName: "filename" + sourceFileName: "filename", + + // Optionally replace all 6to5 helper declarations with a referenece to this + // variable. If set to `true` then the default namespace is used "to5Runtime". + // Default: false + runtime: true } ``` @@ -226,6 +232,33 @@ require("6to5/register")({ ### Browser +A browser version of 6to5 is available from `browser.js` inside the 6to5 +directory in an npm release. + +#### Scripts + +While it's not recommended for serious use, when the browser version is included +all scripts with the type `text/ecmascript-6` and `text/6to5` are automatically +compiled and ran. + +For example: + +```html + + +``` + +#### Build + You can build a browser version of the compiler by running the following in the 6to5 directory: @@ -233,8 +266,7 @@ You can build a browser version of the compiler by running the following in the This will output the files `dist/6to5.js` and `dist/6to5.min.js`. -Just include one of those in the browser and access the transform method via the -global `to5`. +#### API ```javascript to5.transform("class Test {}").code; @@ -320,6 +352,58 @@ class Bar extends Foo { The [regenerator runtime](https://github.com/facebook/regenerator/blob/master/runtime.js) and an [ES6 polyfill](#polyfill) are required in order for generators to work. +## Runtime + +6to5 has a few helper functions that'll be placed at the top of the generated +code so it's not inlined multiple times throughout that file. This may become an +issue if you have multiple files, especially when you're sending them to the +browser. gzip alleviates most of this concern but it's still not ideal. + +You can tell 6to5 to not place any declarations at the top of your files and +instead just point them to a reference contained within the runtime. + +Simply use the following option if you're using the [Node API](#node-1): + +```javascript +{ + runtime: true +} +``` + +or the following flag if you're using the [CLI](#cli): + + $ 6to5 --runtime + +Then just include the runtime before your generated code. + +### Getting the runtime + +You can get the runtime via either: + + $ 6to5-runtime + +or + +```javascript +require("6to5").runtime(); +``` + +or from an npm release in `runtime.js` from the 6to5 directory. + +### Customising namespace + +You can also customise the runtime namespace by passing an optional namespace +argument: + +```javascript +require("6to5").runtime("myCustomNamespace"); +``` + + $ 6to5-runtime myCustomNamespace + +See [Options - runtime](#options) for documentation on changing the reference in +generated code. + ## Differences ### Philosophy diff --git a/bin/6to5-runtime b/bin/6to5-runtime new file mode 100755 index 0000000000..a19e68f826 --- /dev/null +++ b/bin/6to5-runtime @@ -0,0 +1,4 @@ +#!/usr/bin/env node + +var runtime = require("../lib/6to5/runtime"); +console.log(runtime(process.argv[2])); diff --git a/bin/6to5/index.js b/bin/6to5/index.js index a3991603f4..b492dbb1b7 100755 --- a/bin/6to5/index.js +++ b/bin/6to5/index.js @@ -10,6 +10,7 @@ commander.option("-t, --source-maps-inline", "Append sourceMappingURL comment to commander.option("-s, --source-maps", "Save source map alongside the compiled code"); commander.option("-f, --filename [filename]", "Filename to use when reading from stdin - this will be used in source-maps, errors etc [stdin]", "stdin"); commander.option("-w, --watch", "Recompile files on changes"); +commander.option("-r, --runtime", "Replace 6to5 declarations with references to a runtime"); commander.option("-m, --modules [modules]", "Module formatter type to use [common]", "common"); commander.option("-w, --whitelist [whitelist]", "Whitelist of transformers to ONLY use", util.list); @@ -87,6 +88,7 @@ exports.opts = { blacklist: commander.blacklist, whitelist: commander.whitelist, sourceMap: commander.sourceMaps || commander.sourceMapsInline, + runtime: commander.runtime, modules: commander.modules }; diff --git a/lib/6to5/file.js b/lib/6to5/file.js index 9bbf157cf8..9e8d6a674b 100644 --- a/lib/6to5/file.js +++ b/lib/6to5/file.js @@ -5,7 +5,6 @@ var SHEBANG_REGEX = /^\#\!.*/; var transform = require("./transformation/transform"); var generate = require("./generation/generator"); var Scope = require("./traverse/scope"); -var acorn = require("acorn-6to5"); var util = require("./util"); var t = require("./types"); var _ = require("lodash"); @@ -19,6 +18,8 @@ function File(opts) { this.ast = {}; } +File.declarations = ["extends", "class-props", "slice"]; + File.normaliseOptions = function (opts) { opts = opts || {}; @@ -28,7 +29,8 @@ File.normaliseOptions = function (opts) { whitelist: [], sourceMap: false, filename: "unknown", - modules: "common" + modules: "common", + runtime: false }); _.defaults(opts, { @@ -36,6 +38,10 @@ File.normaliseOptions = function (opts) { sourceMapName: opts.filename }); + if (opts.runtime === true) { + opts.runtime = "to5Runtime"; + } + transform._ensureTransformerNames("blacklist", opts.blacklist); transform._ensureTransformerNames("whitelist", opts.whitelist); @@ -43,18 +49,18 @@ File.normaliseOptions = function (opts) { }; File.prototype.getModuleFormatter = function (type) { - var ModuleLoader = transform.moduleFormatters[type]; + var ModuleFormatter = transform.moduleFormatters[type]; - if (!ModuleLoader) { + if (!ModuleFormatter) { var loc = util.resolve(type); - if (loc) ModuleLoader = require(loc); + if (loc) ModuleFormatter = require(loc); } - if (!ModuleLoader) { + if (!ModuleFormatter) { throw new ReferenceError("unknown module formatter type " + type); } - return new ModuleLoader(this); + return new ModuleFormatter(this); }; File.prototype.parseShebang = function (code) { @@ -70,13 +76,26 @@ File.prototype.parseShebang = function (code) { }; File.prototype.addDeclaration = function (name) { + if (!_.contains(File.declarations, name)) { + throw new ReferenceError("unknown declaration " + name); + } + var declar = this.declarations[name]; if (declar) return declar.uid; + var ref; + var runtimeNamespace = this.opts.runtime; + if (runtimeNamespace) { + name = t.identifier(t.toIdentifier(name)); + return t.memberExpression(t.identifier(runtimeNamespace), name); + } else { + ref = util.template(name); + } + var uid = t.identifier(this.generateUid(name)); this.declarations[name] = { uid: uid, - node: util.template(name) + node: ref }; return uid; }; @@ -118,7 +137,7 @@ File.prototype.generate = function () { var opts = this.opts; var ast = this.ast; - var result = generate(this.code, ast, opts); + var result = generate(ast, opts, this.code); if (this.shebang) { // add back shebang @@ -133,7 +152,10 @@ File.prototype.generate = function () { }; File.prototype.generateUid = function (name, scope) { + name = t.toIdentifier(name); + scope = scope || this.scope; + var uid; do { uid = this._generateUid(name); @@ -142,17 +164,6 @@ File.prototype.generateUid = function (name, scope) { }; File.prototype._generateUid = function (name) { - // replace all non-valid identifiers with dashes - name = name.replace(/[^a-zA-Z0-9]/g, "-"); - - // remove all dashes and numbers from start of name - name = name.replace(/^[-0-9]+/, ""); - - // camel case - name = name.replace(/[-_\s]+(.)?/g, function (match, c) { - return c ? c.toUpperCase() : ""; - }); - var uids = this.uids; var i = uids[name] || 1; diff --git a/lib/6to5/index.js b/lib/6to5/index.js index c1b0a2db3a..29e73fc64c 100644 --- a/lib/6to5/index.js +++ b/lib/6to5/index.js @@ -2,6 +2,8 @@ var transform = require("./transformation/transform"); var fs = require("fs"); var _ = require("lodash"); +exports.runtime = require("./runtime"); + exports.register = function (opts) { var register = require("./register"); if (opts != null) register(opts); diff --git a/lib/6to5/runtime.js b/lib/6to5/runtime.js new file mode 100644 index 0000000000..ee77d65c60 --- /dev/null +++ b/lib/6to5/runtime.js @@ -0,0 +1,44 @@ +var generator = require("./generation/generator"); +var util = require("./util"); +var File = require("./file"); +var t = require("./types"); +var _ = require("lodash"); + +module.exports = function (namespace) { + var body = []; + var container = t.functionExpression(null, [], t.blockStatement(body)); + + var tree = { + type: "Program", + body: [t.expressionStatement(t.callExpression(container, []))] + }; + + body.push(t.variableDeclaration("var", [ + t.variableDeclarator(t.identifier("self"), t.conditionalExpression( + t.binaryExpression("===", + t.unaryExpression("typeof", t.identifier("global"), true), + t.literal("undefined") + ), + t.identifier("window"), + t.identifier("global")) + ) + ])); + + var namespace = t.identifier(namespace || "to5Runtime"); + + body.push(t.variableDeclaration("var", [ + t.variableDeclarator( + namespace, + t.assignmentExpression("=", t.memberExpression(t.identifier("self"), namespace), t.objectExpression([])) + ) + ])); + + _.each(File.declarations, function (name) { + var key = t.identifier(t.toIdentifier(name)); + body.push(t.expressionStatement( + t.assignmentExpression("=", t.memberExpression(namespace, key), util.template(name)) + )); + }); + + return generator(tree).code; +}; diff --git a/package.json b/package.json index cf7bac9c35..53a7c7220b 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "main": "lib/6to5/index.js", "bin": { "6to5": "./bin/6to5/index.js", - "6to5-node": "./bin/6to5-node" + "6to5-node": "./bin/6to5-node", + "6to5-runtime": "./bin/6to5-runtime" }, "keywords": [ "harmony",