add support for an optional runtime - closes #129

This commit is contained in:
Sebastian McKenzie 2014-11-09 12:02:06 +11:00
parent 8ef5148870
commit ab9cd4e630
8 changed files with 175 additions and 25 deletions

View File

@ -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

View File

@ -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
<script src="node_modules/6to5/browser.js"></script>
<script type="text/6to5">
class Test {
test() {
return "test";
}
}
var test = new Test;
test.test();
</script>
```
#### 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

4
bin/6to5-runtime Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env node
var runtime = require("../lib/6to5/runtime");
console.log(runtime(process.argv[2]));

View File

@ -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
};

View File

@ -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;

View File

@ -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);

44
lib/6to5/runtime.js Normal file
View File

@ -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;
};

View File

@ -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",