Coder Social home page Coder Social logo

es6-module-transpiler's Introduction

ES6 Module Transpiler Build Status

NOTE: This project been deprecated in favor of Babel & Rollup.

This project is part of esnext, which has merged with Babel. All the features of esnext are supported by Babel, and more. All the tests from esnext have been ported over to Babel to ensure that switchers will have minimal code changes to make. The maintainers of esnext will continue working on Babel to bring better spec compliance, ES6 feature support, and performance. If you want a fast tool with bundling support as found in this project, you should check out Rollup.


ES6 Module Transpiler is an experimental compiler that allows you to write your JavaScript using a subset of the ES6 module syntax, and compile it into AMD or CommonJS modules.

This compiler provides a way to experiment with ES6 syntax in real world scenarios to see how the syntax holds up. It also provides a nicer, more declarative way to write AMD (or CommonJS) modules.

See the CHANGELOG for the latest updates.

Usage

Build tools

The easiest way to use the transpiler is from an existing build tool. There several plugins developed for different build tools:

Executable

The transpiler can be used directly from the command line:

$ npm install -g es6-module-transpiler
$ compile-modules convert foo.js

Here is the basic usage:

compile-modules convert -I lib -o out FILE [FILE…]

Library

You can also use the transpiler as a library:

var transpiler = require('es6-module-transpiler');
var Container = transpiler.Container;
var FileResolver = transpiler.FileResolver;
var BundleFormatter = transpiler.formatters.bundle;

var container = new Container({
  resolvers: [new FileResolver(['lib/'])],
  formatter: new BundleFormatter()
});

container.getModule('index');
container.write('out/mylib.js');

Supported ES6 Module Syntax

Named Exports

There are two types of exports. Named exports like the following:

// foobar.js
var foo = 'foo', bar = 'bar';

export { foo, bar };

This module has two named exports, foo and bar.

You can also write this form as:

// foobar.js
export var foo = 'foo';
export var bar = 'bar';

Either way, another module can then import your exports like so:

import { foo, bar } from 'foobar';

console.log(foo);  // 'foo'

Default Exports

You can also export a default export. For example, an ES6ified jQuery might look like this:

// jquery.js
var jQuery = function() {};

jQuery.prototype = {
  // ...
};

export default jQuery;

Then, an app that uses jQuery could import it with:

import $ from 'jquery';

The default export of the "jquery" module is now aliased to $.

A default export makes the most sense as a module's "main" export, like the jQuery object in jQuery. You can use default and named exports in parallel.

Other Syntax

import "foo";

A "bare import" that doesn't import any identifiers is useful for executing side effects in a module. For example:

// alerter.js
alert("alert! alert!");

// alertee.js
import "alerter";  // will pop up alert box

Compiled Output

Default Exports

This is super important:

Default exports bind to an identifier on the module called default!

Internally, the transpiler will use this default identifer when importing, but any outside consumer needs to be aware that it should use the default key and not the module itself. For example, a CommonJS consumer should look like this:

var $ = require('jquery')['default'];

Installation

Add this project to your application's package.json by running this:

$ npm install --save es6-module-transpiler

Or install it globally:

$ npm install -g es6-module-transpiler

Acknowledgements

Thanks to Yehuda Katz for js_module_transpiler, the library on which this one is based. Thanks to Dave Herman for his work on ES6 modules. Thanks to Erik Bryn for providing the initial push to write this library. Thanks to Domenic Denicola, Jo Liss, & Thomas Boyt for their efforts to make this project even better. And finally thanks to the JavaScript community at Square for helping to write and release this library.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

Any contributors to the master es6-module-transpiler repository must sign the Individual Contributor License Agreement (CLA). It's a short form that covers our bases and makes sure you're eligible to contribute.

When you have a change you'd like to see in the master repository, send a pull request. Before we merge your request, we'll make sure you're in the list of people who have signed a CLA.

Thanks, and enjoy living in the ES6 future!

es6-module-transpiler's People

Contributors

airportyh avatar benjamn avatar brzpegasus avatar caridy avatar danbell avatar eoinkelly avatar ericf avatar eventualbuddha avatar guybedford avatar jamesmgreene avatar joefiorini avatar kpdecker avatar laurelnaiad avatar matthewrobb avatar meesayen avatar ragiragi avatar rich-harris avatar rkusa avatar ryanflorence avatar ryanseddon avatar tbranyen avatar termi avatar thomasboyt avatar tonybaroneee avatar trek avatar unscriptable avatar wycats avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

es6-module-transpiler's Issues

Published CLI is out of date

EDIT: Installation works for me now, mysteriously, but compile-modules is still out of date.

I can't install version 0.3.2:

$ npm i es6-module-transpiler
npm ERR! Error: ENOENT, chmod '/Users/xtian/Projects/es6-transpile/node_modules/es6-module-transpiler/bin/compile-modules'
npm ERR! If you need help, you may report this log at:
npm ERR!     <http://github.com/isaacs/npm/issues>
npm ERR! or email it to:
npm ERR!     <[email protected]>

npm ERR! System Darwin 12.5.0
npm ERR! command "/usr/local/Cellar/node/0.10.21/bin/node" "/usr/local/bin/npm" "i" "es6-module-transpiler"
npm ERR! cwd /Users/xtian/Projects/es6-transpile
npm ERR! node -v v0.10.21
npm ERR! npm -v 1.3.11
npm ERR! path /Users/xtian/Projects/es6-transpile/node_modules/es6-module-transpiler/bin/compile-modules
npm ERR! code ENOENT
npm ERR! errno 34
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR!     /Users/xtian/Projects/es6-transpile/npm-debug.log
npm ERR! not ok code 0

I'm not sure what the issue is, but here are the full logs for a successful 0.3.1 install and an unsuccessful 0.3.2 install: https://gist.github.com/xtian/7088576

Ignore import statements within a block comment

So, the following block comment:

/* import { foo } from "foo";
import { bar } from "bar";
import { baz } from "baz";
import { buzz } from "buzz";*/

Will result in this output:

define("firebase_adapter",
  ["bar","baz"],
  function(__dependency1__, __dependency2__) {
    "use strict";
    var bar = __dependency1__.bar;
    var baz = __dependency2__.baz;
    /* import { foo } from "foo";
    import { buzz } from "buzz";*/
  });

Where the statements that do not start with a /* or end with a */ are kept.

I don't know if how import statements in block comments are handled in ES6 has been specified yet, but my assumption is that they should be ignored just like anything else in a block comment.

Support `ExportSpecifierSet` being `"*"`.

export * from "crypto";

should transpile to something like

var __dependency1__ = require("crypto");
Object.getOwnPropertyNames(__dependency1__).forEach(function (x) {
    exports[x] = __dependency1__[x];
});

Correctly export bindings, not snapshots

See e.g. this es-discuss thread.

The way to correct this would require whole-program analysis, like so. These:

// foo.js
export var x = 5;
export function modifyX() {
  x = 10;
};
import { x, modifyX } from "foo";
console.log(x);
setTimeout(function () {
  console.log(x);
}, 100);

should transpile to these:

// foo.js
exports.x = 5;
export.modifyX = function () {
  exports.x = 10;
};
var __dependency1__ = require("foo");

console.log(__dependency1__.x);
setTimeout(function () {
  console.log(__dependency1__.x);
}, 100);

This is painful and counterintuitive, but it is how the spec works and TC39 is very dedicated to this feature (which I like to explain as "namespaces, not modules"). Failing to include this semantic in the transpilation seems likely to cause unexpected pain and bugs when people move to real ES6 modules.

Support `ExportSpecifier` being `Identifier "as" IdentifierName`

export { foo as qux, bar, baz as quux };

should transpile to

exports.qux = foo;
exports.bar = bar;
exports.quux = baz;

and

export { foo as qux, bar, baz as quux } from "crypto";

should transpile to

var __reexport1__ = require("crypto");

exports.qux = __reexport1__.foo;
exports.bar = __reexport1__.bar;
exports.quux = __reexport1__.baz;

lib directory not in .gitignore?

Hi, I have a few patches for running this in Windows (backslashes in paths are tripping up cli, amd_compiler, and test specs). I was getting ready to commit them to a fork when I noticed that the lib directory is in git.

If the content of the lib directory is generated during the build process, should it be there? I guess it's there so that lib doesn't need to be generated when npm install is run?

Should I commit changes to files in the lib directory that are being changed due to running the build? I assume that because they're in git and not .gitignored, the answer is yes... but just want to double-check.

Correctly distinguish between default export and module instance object

The module instance object, retrieved by module foo from "foo", is very different from the default export, retrieved by import foo from "foo". The current transpilation conflates these.

It would be best to transpile as follows:

module foo from "foo";
import bar from "bar";

export default baz;
export { qux };

should become

var foo = require("foo");
var bar = require("bar").__default__;

exports.__default__ = baz;
exports.qux = qux;

This is especially important on the import side, as people using the wrong syntax there (i.e. using import ... from when they should be using module ... from, because es6-module-transpiler only allows the former) will cause forward-compatibility problems as they try to upgrade to real ES6 modules.

bin should not be gitignored

I can't install from my fork because bin is ignored. So when the original author publishes to npm everything is fine, but anybody else will publish something w/o bin.

Shouldn't CommonJS exports be relative to file?

ES6 module declarations are relative to the current file, i.e., import "baz" as myModule in foo/bar.js will import foo/baz.js. However, the current CommonJS output will convert that require declaration to require("baz"), which, in NodeJS terms, will attempt to import foo/node_modules/baz/main.js. Presumedly, it should be turning that declaration into require("./baz"), which will work as expected, right?

(it's also possible that I'm missing something at 1:30 am, but I think this is just a pretty large oversight)

Of course, this does mean that there would be no syntax for doing actual node_module-based imports. It just seems that without it, you'll have super-inconsistent behavior between the AMD and CommonJS transpiled output.

Support `export function default()`

currently outputs

define(["exports"],
  function(__exports__) {
    "use strict";
    function default() {
      return "foo";
    }

    __exports__.default = default;
  });

which fails because default is reserved. easy solution is just to have a special case that converts export function default() -> exports['default'] = function()

Error when compiling globals without imports

Are imports required for using globals? I'm not sure I entirely understand the use case, because I'm getting an error compiling globals without imports. It looks like it's due to a line in globals_compiler.js that runs:

  globalImport = _this.options.imports[name];

Is this intentional or a bug?

Consider using Esprima for parsing

esprima is a general-purpose JS parser, written in JS. It has a separate harmony branch that already includes the previous module syntax. There's an open issue for the new syntax here.

Esprima would make it possible to support block (multiline) exports, as well as making it easier to maintain the transpiler by not having to write so many regular expressions :)

The best route for this would be to look at Esprima and make sure it's easy to use how we want it (probably by examining how the current module support works), and if so, helping to improve the syntax.

Will (hopefully) fix #27, #28, #31, #32, and #33.

Publish new version

Any chance of a quick 0.1.3 version bump & publish? I'm working on a blog post for using the transpiler with Grunt that relies on 21d4efb, which hasn't been in a published version yet. Normally I'd just point people at the git master, but since it's being used through grunt-es6-module-transpiler, there's no easy way to change the dependency without using a fork of that plugin.

--anonymous option is non-functional

It appears that the --anonymous option is never used in the code. We'd love to use this transpiler, but anonymous modules are absolutely essential for AMD development.

Consider making anonymous modules the default

Currently, the --anonymous flag defaults to no. I suggest you default it to yes. Here's why:

  1. the "recommended" format for AMD modules is anonymous. http://www.requirejs.org/docs/api.html#modulename and https://github.com/know-cujojs/know/blob/master/modules/001-authoring-amd-modules.md
  2. the single use case for not creating anonymous modules is to accommodate non-AMD-aware concatenation tools.

Imho, 99%+ of the users of this lib will either be using anonymous modules or will know if/when they want them.

Fwiw, guys, I am really, really liking what I see here! This project is awesome! Well, except for the coffeescript part, but I'm hoping my eyes can adjust. :) :)

-- John

Support default import/exporting

Recent changes to the ES6 module syntax have added importing and exporting default variables, as seen in the BNF here. Here's the relevant changes:

ExportDeclaration  ::=  ...
                    |   "export" "default" AssignmentExpression ";"               // default export

ImportDeclaration ::= "import" ImportSpecifierSet "from" ModuleSpecifier ";"      // explicit import declaration (fetch and execute dependency)

ImportSpecifierSet ::=   Identifier                                               // default import
                    |    "{" (ImportSpecifier ("," ImportSpecifier)* ","?)? "}"   // named imports

Example usage:

// import the default export of a module as the name "$"
import $ from "jquery";
// export a default function
export default function () { ... }

This one is kind of up in the air, but sounds likely:

// import the default export of a module as "$" and a named export called "ajax"
import {default as $, ajax};

Source map support.

Just wondering if you are working on source map support?

If not would you accept a PR to add source map support using the Mozilla source_map module?

Also, I have noticed you are maintaining a move-to-js branch. Should new PR's be using master or the move-to-js branch as a starting point?

Support the "as" keyword

This transpiler is currently useless for importing node modules, but if support for the "as" syntax was added, it could easily be used as such:

import 'express' as express

Transpiles to...

var express = require('express')

Am I wrong? Is there any other way to accomplish this with how the transpiler works now?

Is node require support gone for good?

I noticed the recent rewrite removed the require_support file. Part of my es6mt grunt task allows running tasks that need to use import or export. Should I plan on removing that task or is this coming back eventually?

Thanks!

ES6 Define Output Format

There is an output format for a module that would work ideally with the ES6 Module Loader Polyfill.

Basically a module looking like:

my/module.js

  import dep from 'someDep';
  export var p = 'export';

Can be output as the following:

System.set('my/module', (function(dep) {
  var p = 'export';
  return new Module({
    p: p
  });
}).call(System.global, System.get('someDep')));

This is effectively the named define analogy for the browser module loader.

Do you think there is a chance of this format being included if I provide a pull request?

Ensure `module ... from ...` gives an object.

This is a forward-compatibility concern.

Today, code like

module $ from "jquery";

will transpile to

var $ = require("jquery");

and then you can use $ as a function. This is bad, as if jQuery were to switch to ES6 modules, all code of this sort would break. (If jQuery were to switch to ES6 modules, the $ variable above would probably have properties like ajax, fx, parseJSON, etc., but would not be a function.)

I would suggest transpiling to

var $ = (function () {
  var moduleInstanceObject = Object.create ? Object.create(null) : {};
  var imported = require("jquery");
  for (var key in imported) {
    if (Object.prototype.hasOwnProperty.call(imported, key)) {
      moduleInstanceObject[key] = imported[key];
    }
  }
  if (Object.freeze) {
    Object.freeze(moduleInstanceObject);
  }
  return moduleInstanceObject;
}());

or perhaps in an ES5-only mode,

var $ = (function () {
  var moduleInstanceObject = Object.create(null);
  var imported = require("jquery");
  Object.keys(imported).forEach(function (key) {
    moduleInstanceObject[key] = imported[key];
  });
  return Object.freeze(moduleInstanceObject);
}());

How do I combine multiple modules?

I have a folder containing a few different ES6 modules:

lib/
  index.js -- import "a"
  a.js -- import "b"
  b.js

I had assumed that running

compile-modules lib/index --to web/ --type=globals --global=Foo

would have pulled in a.js and, recursively, b. That doesn't seem to be the case. Is the recommended solution to instead create a parallel directory of CommonJS versions with

compile-modules lib/ --to cjs/ --type=cjs

and then run something like browserify or gluejs to convert those into a web-friendly file?

Support `export foo =`

This is an esprima issue.

Implementation should be

export foo = 5;

becomes

var foo = 5;
exports['foo'] = foo;

__dep__['default'] is incompatible with existing AMD/CJS scripts

README.md says:

The reason for all of this extra boilerplate is that ES6 modules support a module having both default and named exports, whereas AMD and CJS do not.

Yes they do:

// AMD
define(function() {
  var DefaultExport = function(){};
  DefaultExport.NamedExport = function(){};
  return DefaultExport;
});

// node
var DefaultExport = function(){};
DefaultExport.NamedExport = function(){};
module.exports = DefaultExport;

I don't get this. It makes working with existing libraries that support one module format or the other unnecessarily complex.

Just take whatever the default export is, and then add the named exports onto it as properties.

Remove `export =` and `import ... as`

As of the January 31 TC39 meeting, export = (and its counterpart, import ... as) are dropped.

It would be best to remove them, both to stay up to date with the spec and improve the likelihood of code you write being future-compatible, and also to avoid giving consumers or perusers of this library the wrong impression about ES6.

Also, the current implementation is buggy with respect to the old spec. In particular, it's impossible by the spec to use import { ... } from "foo" if "foo" did export =; similarly it's impossible to use import "foo" as foo if "foo" did not do export =. The current implementation does not enforce that and thus has similar future-compatibility problems.

Support for code without semicolons

JavaScript semicolons are optional.

The following code transpiles incorrectly:

import 'fortune'
var hbs = require('hbs')

Transpiles to...

"use strict";
require("fortune");ar hbs = require('hbs')

However, it does transpile correctly is a semicolon is used after the line, import 'fortune'.

Release a beta release

This has changed significantly since the 0.2.0 release, can you release a prerelease tag to npm so that we don't have to install from the repo which can be unstable.

Also I am completely unable to execute (from the readme) npm install -g https://git.squareup.com/javascript/es6-module-transpiler

Is that a publicly accessible repo?

TypeError: Cannot read property 'ember' of undefined

I'm running the following command

cat lib/i18n.js | compile-modules\
  --stdio\
  --type globals\
  --global "Ember.I18n"\
  --imports "ember:Ember,handlebars:Handlebars,jquery:jQuery"\
  > dist/ember-i18n.js

and it throws

/Users/jamesarosen/Projects/ember/i18n/node_modules/es6-module-transpiler/lib/globals_compiler.js:35
          globalImport = _this.options.imports[name];
                                              ^
TypeError: Cannot read property 'ember' of undefined
    at GlobalsCompiler.stringify (/Users/jamesarosen/Projects/ember/i18n/node_modules/es6-module-transpiler/lib/globals_compiler.js:35:47)
    at GlobalsCompiler.AbstractCompiler.build (/Users/jamesarosen/Projects/ember/i18n/node_modules/es6-module-transpiler/lib/abstract_compiler.js:83:7)
    at GlobalsCompiler.stringify (/Users/jamesarosen/Projects/ember/i18n/node_modules/es6-module-transpiler/lib/globals_compiler.js:22:19)
    at Compiler.toGlobals (/Users/jamesarosen/Projects/ember/i18n/node_modules/es6-module-transpiler/lib/compiler.js:227:54)
    at CLI._compile (/Users/jamesarosen/Projects/ember/i18n/node_modules/es6-module-transpiler/lib/cli.js:215:30)
    at Socket.CLI.processStdio (/Users/jamesarosen/Projects/ember/i18n/node_modules/es6-module-transpiler/lib/cli.js:149:24)
    at Socket.EventEmitter.emit (events.js:85:17)
    at Pipe.onread (net.js:416:51)

Do I have the syntax wrong?

Import map

It would be quite nice if the import option could be used to also provide a custom normalization map for AMD and CJS compilation modes.

This would allow a tracer such as https://github.com/guybedford/es6-tracer to input the normalization map solving the relative path and normalization problem.

I'm currently working along these lines on @thomasboyt's esprima rewrite branch. Would appreciate advice re pull requests as I can currently only create them for the forked repo.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.