Add support for ES6 module syntax
simonexmachina opened this issue · 168 comments
Maybe I'm missing something, but I can't see how to use ES6 modules from CoffeeScript. We should have this.
It looks like there isn't yet a single JS runtime that supports ES6 modules yet: http://kangax.github.io/es5-compat-table/es6/
We should not have this until it's ready.
Its preventing me from using an es6 module transpiler. Is there any way I can
prevent this from being a syntax error?
Is there any way I can prevent this from being a syntax error?
Could you include the code as JavaScript between backticks?
`import { Point, pow, sqrt } from 'math'`
# actual CoffeeScript code...
`export Segment`Yes, but it's pretty ugly! Thanks for the tip though, that works.
👍
+1
`export` Controller.extend # not working
content: ...
vs.
# in 'controllers/configuration/items'
ConfigurationItemsController = Controller.extend
content: ...
`export ConfigurationItemsController`
+1. Great
Is this something we should reconsider? With things like Ember App Kit and similar projects evolving, I think there's at least grounds to brainstorm a potential solution.
Is the solution I posted (inline javascript) too invasive to be implemented?
It's absolutely more of a nuisance than an actual issue.
Things like this: (export default)
export default Ember.TextField.extend({
didInsertElement: function() {
this.$().focus();
this.$().addClass('focus'); // headless testing is brittle
}
});I would like to be able to write
export default Ember.TextField.extend
didInsertElement: ->
@$()
.focus()
.addClass 'focus'@kimroen see @jashkenas's answer above
I obviously read through the issue before commenting :)
No worries, I just thought it was worth reconsidering. Do with as you please.
👍
👍
👍 I would really like this feature. I'd wager that we are going to start seeing more projects that use ES6 modules.
Even if the word "export" and "import" could be shortened to "exp" and "imp" respectively to get around keyword conflicts, that would be pretty great. I suppose an alias to those methods in the Square's ES6 module transpiler could be created. That may relieve coffeescript developers for a little time, but knowing that export and import are reserved words in ES6 makes me doubt that making those aliases outside of coffeescript would be well received.
I've gotta say that, as much as I love CoffeeScript, I've moved away from
it in my latest project because it doesn't support import, export and
generator functions. It's a sad day, but all things must pass :)
aexmachina, I'll much rather struggle to find a way to make CoffeeScript work with export and import than to stop using CoffeeScript. I keep hearing people say "JavaScript is fun." If JavaScript is so fun to write, why are there 100+ JS compilers?
I just posted an issue on the CoffeeScriptRedux project: michaelficarra/CoffeeScriptRedux#281
Alternatively, I suppose there is nothing that would stop anyone from forking CoffeeScript and changing the reserved words. Doing so would likely break backwards compatibility.
There are 100+ compilers because 1) it's the only language that runs client-side (expected chromium-dart and such) 2) it's an easy compilation target
I meant excepted*. I can't type on phones ;)
Creating a version of CoffeeScript that targets ES6/traceur might become important in near future. We don't want lose @aexmachina! I wouldn't worry about the things that don't add to CS (like destructuring), but this seems to make sense (as do generators).
Most importantly, this doesn't break IE6 - adding this to CS doesn't force you to use it.
@xixixao: Before we do that, we need to syntactically and semantically align existing overlapping features. Ellipses for spread/rest need to be prefix to match ES6. super semantics need to be changed to match ES6. But we need to wait until it's finalised before making any of those changes. I know I've gone into some detail on this in an issue before, but good luck finding it...
@michaelficarra I do not agree with that at all. But I guess that my position breaks the good old just JavaScript motto. On the other hand, == is an overlapping feature and has different semantics, so maybe that motto is not meant to be interpreted in this way.
As I read an article, linking some words here.
http://shift.mirego.com/post/76526223016/javascript-next
I don’t think the team was enthusiastic about the idea of losing the classes, destructuring, rest arguments, defaut parameters and other cool features of CoffeeScript. I don’t blame them. I like these features too. But being future-friendly was more important to me. I wanted to use that ES6 syntax as soon as possible. With the new generation of auto-updating browsers, the time when we can all use ES6 is not so far away and being ahead of the curve could serve us well.
Backticks don't work with Ember App Kit Rails, at least.
Why not ?
Unrelated, you're just using a global variable in the second example. Continue that discussion there though ;-).
Worth noting that AngularJS 2.0 will be utilizing this feature. Might be time to revisit this soon.
While not meaning to beat this particular horse, I would love to see ES6 module syntax supported without backticks. Many popular frameworks are already embracing modules (ember, angular, etc...) today via transpilers.
import, export, and default are all reserved words in JS (as of es5), of which only default is used as a keyword in CS (and semantically distinguishably, at that). Since using these keywords essentially opts you in to the new es6 features, I don't fully understand compatibility argument. In so far as I understand, any language compatibility is pushed out to the JS interpreter, which only reinforces the axiom that CoffeeScript "is just JavaScript".
I can definitely see how other es6 features would break existing CS syntax, but is there a particular reason we need to all-or-nothing them?
I dunno, maybe it's time to re-examine this particular feature? It's definitely becoming more of a pita for me every day.
+1
+1, es6-module-transpiler dropped CoffeeScript support
+1
The less reason people have to disparage the use of CoffeeScript, the better.
Have the major browsers all made a statement/put a point on their roadmaps for generator support? I think it's reasonable to expect a timeframe or roadmap from the CS devs but only if they have an idea of when browsers will be doing the same.
Would love if support for this was reconsidered so that things like the es6-module-transpiler and ember-cli can work well with CoffeeScript.
+1 we love coffeescript here and used it for lot of client projects in last 2 years, however we're starting to play with angular 2 and es6 transpilers and would really appreciate coffeescript support for es6 constructs
+1
If anyone interested has the time, I am sure that a PR would have a good chance of getting in (along with yield support).
"import" and "yield" should be two separate PRs, I suspect.
Just to be clear: when you use backticks for the import/export module syntax, do you then include the traceur runtime? I'm fairly sure the System object import/export is not yet available, right?
Answered my own question. Our es6 work now includes concatenating the runtime to our js/es6 framework. This means we get both import/export but also all the polyfills.
ES6 is increasingly important, and I think it may be too big a deal to do piecemeal by PR's.
Personally, I'd love to see something from @jashkenas / @xixixao on the intended direction for this. How will CS's class work with ES6's? Modules? etc. I imagine there may need to be some non-backwards-compatible changes made, in which case this would be a major release. While sooner rather than later is nice, I'm personally more interested in hearing about a strong, reliable plan for the future of CoffeeScript than a few patches thrown on tomorrow.
TL;DR: Modules are not es6, they are separate. CS can easily use import/export or System.js polyfills. This has nothing to do with current browsers. Define your goals and you can achieve a reasonable result.
Long Form:
I am currently integrating a modestly large CS project with a team who has adamantly rejected CS, God knows why .. we all have run across this and it seems to be that its just one more thing to learn. Shit! But...
We have come to peace over all this by agreeing that modules really are not es6, they are separate. Even traceur uses a separate module for import/export. The "right" solution is to use the System object, and following/messaging with Guy Bedford, the daddy of current es6/system.js, has helped a lot. The CS/JS war is somewhat ameliorated by meeting at module. So the JS/CS folks are converging via modules. This is a Good Thing .. more small modules seem more used. DRY.
We traced two reasonable solutions: a System.js polyfill, and es6 import/export. After a couple of weeks of exploring these, we agreed on import/export and using the traceur runtime if needed. There are several workflows to achieve this.
One huge advantage is that it appears that we may no longer have to state a specific CS concatenation of our CS modules into dependency order. (Only tried on a small sample) Traceur appears to do that for us.
We also can use only the parts of the framework we want by exposing our use of import/export. The resulting concatenation will include only the transitive closure .. not the entire framework.
All this is to urge you to separate es6 features from modules. We've been cursed by differing module systems for far too long and System.js & import/export promise to unite them.
Jeremy is right to say we shouldn't include es6 features until universal. But it is wrong for CS to avoid the module problem. Really.
Yes, people are rejecting CS often for irrational reasons. JS is evolving rapidly however and if CS doesn't keep up there will be more reasons to abandon it. I vote for incremental improvements over delayed major releases.
Is it correct to say that the only real "issue" here is that CoffeeScript's compiler throws an error whenever import or export is encountered? Is it adding much value for CoffeeScript to do this versus falling back on interpreters to raise alarm? To me, the only benefit to these errors is slightly-faster-feedback that I've just run afoul of a runtime constraint, but that's a marginal benefit compared to the inconvenience people are describing in this thread. Seems like a lot of pain would be avoided by simply removing the compilation errors at little cost to everyone else.
In cases like these, where post-CoffeeScript-compilation transpilers are being used by many projects (I stumbled upon this trying to start a new project in ember-cli, for example), whether or not the ultimate runtime interpreter supports a given ES6 feature is not the most pressing question to answer when asked whether CoffeeScript should throw an error. Instead, what's the most valuable behavior to achieve developer happiness most of the time while still being "just JavaScript"? In this case, removing the error thrown when these reserved words are used seems to be the smart call. 🤷
It is trivial to backtick import/export and it works fine. It requires a
runtime .. I think only the System polyfill. And it has all the advantages
import/export provides .. leaving out modules that are no longer needed.
This is a huge advance to the usual Coffee stunt of concatenating your
whole system and then compiling. I've tried it on a small demo and all
seems well. Gets the dependencies in the correct order and handles
transitive closure over modules.
This has completely changed my CS usage. I'm way more modular, and my
team can accept my modules as if they were es6.
-- Owen
On Mon, Nov 3, 2014 at 8:37 PM, Justin Searls notifications@github.com
wrote:
Is it correct to say that the only real "issue" here is that
CoffeeScript's compiler throws an error whenever import or export is
encountered? Is it adding much value for CoffeeScript to do this versus
falling back on interpreters to raise alarm? Seems like a lot of pain would
be avoided by simply removing the compilation errors at little cost to
everyone else.In cases like these, where post-CoffeeScript-compilation transpilers are
being used by many projects (I stumbled upon this trying to start a new
project in ember-cli, for example), whether or not the ultimate runtime
interpreter supports a given ES6 feature is not the most pressing question
to answer when asked whether CoffeeScript should throw an error. Instead,
what's the most valuable behavior to achieve developer happiness while
still being "just JavaScript"? In this case, removing the error thrown when
these reserved words are used seems to be the smart call. 🤷—
Reply to this email directly or view it on GitHub
#3162 (comment)
.
+1
+1
As CoffeeScript is locked at ES5 by its maintainer, i've started a discussion of a potential ES6-friendly CoffeeScript replacement here: coffeescript-cookbook/coffeescript-cookbook.github.io#128
Please, participate and spread the word throughout the CoffeeScript community.
You know what? I need to say this, to get it off my chest.
You don't need ES6. At all.
There, I said it. What am I talking about, exactly? Let's face it, most of the proposed features are either completely unnecessary (e.g. let/const, Map/Set, Symbol), done better by CoffeeScript (arrow functions, class-extends, spread/rest, for-of, destructuring, template strings, comprehensions...), or done better by libraries (Promises, modules).
The most important feature of ES6 is still not implemented anywhere, and is likely to arrive last because it doesn't change/affect syntax and is apparently harder to do than I think: Tail call optimization. The most divergent (and, widely in use already) feature in ES6 is generators, and the next release of CS will have full support for them.
ES6 modules are kind of terrible, and no one can figure out why the TC didn't just use CommonJS, which everyone loves. Browserify handles modules and modularity better than the ES6 "modules" feature for the client side, and any use cases that fall outside of what Browserify does are probably handled well by Webpack.
So much of ES6 is straight up hype. "Solutions" that we've already solved ourselves by building libraries, or which only solve problems that come out of a textbook on computing theory.
With all that said, a small subset of ES6 things should probably be allowed to "pass through" to JS without the use of backticks, because some people will be happier that way, and everyone else can just ignore it. Especially if it's easy to implement, with no special syntax. But, even if it isn't, CS still does what it does very well, and you can build anything that you need using it.
ES6 will be obsolete before CoffeeScript is.
ES6 modules are kind of terrible
I'd like to hear more on why you feel this way. I personally love the ES6 modules. Remember, their main benefit over CommonJS is that they may be statically determined, so tools like Browserify and my own CommonJS Everywhere can actually do what they claim to be able to do. And unlike other terrible module systems from other languages, they don't magically bring any names into scope. I think their design is quite elegant and obviously very carefully thought out.
By the way, I totally agree that generators and TCO are by far the most important features coming out of ES6.
@bjmiller
Those are interesting thoughts. I agree that you certainly shouldn't have
to use ES6 to use coffeescript.
However, incorporating the changes for ES6 would probably be significant
enough to warrant a major version bump - CS2.x.x - so you would be able to
continue to use es5-only coffeescript if you preferred.
As for whether coffeescript should support ES6 at all, I honestly think the
question of es6's design quality is irrelevant. It's the future of
JavaScript by fiat. Just like JavaScript is the language of the web by
fiat, regardless of its strength as a language.
If ES6 has warts, let's do for them what @jashkenas did for ES3.
The most important feature of ES6 is still not implemented anywhere, and is likely to arrive last because it doesn't change/affect syntax and is apparently harder to do than I think: Tail call optimization.
You don't know how much i agree with this. The lack of TCO makes me unhappy in a much profound sense than the stupidity == coercions rules.
When TCO lands (or starts landing) on browsers, i think we should discuss the support for it in CoffeeSciprt. E.g., do all Coffee's constructs that have simple JS equivalents align with what ES6 consider tail call sites?
At least the tail calls feature does not introduce new syntax.
@michaelficarra:
I took a little time to look more closely at ES6 (Or, is it ES2015?) modules.
I find that it's harder to reason about, and that maybe it's trying to solve too many problems at once?
This helped me a little: https://github.com/addyosmani/es6-equivalents-in-es5#modules, but I'm even more confused now about what "default" is supposed to do.
This also gave me some concerns: http://www.geedew.com/2014/12/26/es6-module-gotchas/
Also of note: No one is anywhere near a "real" implementation yet. It seems like the "6to5" project has the best support so far.
Lastly, I actually like the fact that you can require things dynamically. I get a lot of use out of that. But, I can see how that can be frustrating for implementors.
Friends, I don't think that our personal feelings on ES6 module are relevant to this discussion. What I would like to walk away with is concrete understand where CoffeeScript stands in relation to ES6.
As a long-time CS user I had to migrate to LiveScript more than a year ago because Generators became important for my team and we needed something that wasn't stuck in ES3 land. I'm overjoyed to hear that CS will have support for generators in its next version, when is this planned for release?
Yesterday ;-) http://coffeescript.org/#changelog
On Fri Jan 30 2015 at 6:37:16 PM Sleepyfox notifications@github.com wrote:
As a long-time CS user I had to migrate to LiveScript more than a year ago
because Generators became important for my team and we needed something
that wasn't stuck in ES3 land. I'm overjoyed to hear that CS will have
support for generators in its next version, when is this planned for
release?—
Reply to this email directly or view it on GitHub
#3162 (comment)
.
I agree that CS still does more than a few things better than even ES6 JS and I don't really have any plans to stop using in in favour of ES6 JS. However a couple of features stand out to me as things I'd like to have in CS. Namely destructuring and getters and setters.
destructuring
CoffeeScript has got that.
Getters and setters, however, have be turned down already.
I strongly suggest you look at Crockford's 'module pattern' as a better solution than exposing an object's attributes externally.
I'm working on a 9.5MB CoffeeScript source project at my day job and am struggling to convince the team to stay on CoffeeScript... Don't throw around silly suggestions about Crockford's patterns, that's very narrow minded.
We are fully committed to CS, but looking even couple of years down the road it seems be mostly obsoleted by ES6 and not to say completely stalled. I can't make a valid argument against rewriting the app in ES6 no matter how I try... Which is very upsetting to me personally since I have almost 4 years of full time dev experience in it and still love it.
While I personally like CommonJS require + Browserify a lot better, it's becoming obvious that the ability to use the import, default, and export keywords is something that people really want.
Can they be removed from the CS "reserved word" list? I think that (plus an additional transpiler layer of the user's choice) is enough to solve the problem for people.
@alexgorbatchev: You should make the case to your team that nearly every ES6 feature that they want is already done better by CoffeeScript today.
Can we avoid calling each other silly and childish?
I don't think anyone struggling to convince their team about CS over ES6
has forgotten to mention that it has virtually all the same features, only
better. That clearly isn't enough.
We don't decide the EcmaScript standard that coffeescript targets. Ecma
International does. They have (all but) decided on the future of
JavaScript. Why wouldn't we target that?
On Wed, Feb 4, 2015, 7:09 AM Brian Miller notifications@github.com wrote:
While I personally like CommonJS require + Browserify a lot better, it's
becoming obvious that the ability to use the import, default, and export
keywords is something that people really want.Can they be removed from the CS "reserved word" list? I think that (plus
an additional transpiler layer of the user's choice) is enough to solve the
problem for people.@alexgorbatchev https://github.com/alexgorbatchev: You should make the
case to your team that nearly every ES6 feature that they want is already
done better by CoffeeScript today.—
Reply to this email directly or view it on GitHub
#3162 (comment)
.
My team had a simple answer: one more thing to learn! They were already
learning about GIS, Agent Based Modeling and more technologies and learning
CS was overwhelming.
Not that I agree, but just an insight into the team difficulties mentioned
by others.
On Tue, Feb 3, 2015 at 8:50 PM, Alex Rattray notifications@github.com
wrote:
Can we avoid calling each other silly and childish?
I don't think anyone struggling to convince their team about CS over ES6
has forgotten to mention that it has virtually all the same features, only
better. That clearly isn't enough.We don't decide the EcmaScript standard that coffeescript targets. Ecma
International does. They have (all but) decided on the future of
JavaScript. Why wouldn't we target that?On Wed, Feb 4, 2015, 7:09 AM Brian Miller notifications@github.com
wrote:While I personally like CommonJS require + Browserify a lot better, it's
becoming obvious that the ability to use the import, default, and export
keywords is something that people really want.Can they be removed from the CS "reserved word" list? I think that (plus
an additional transpiler layer of the user's choice) is enough to solve
the
problem for people.@alexgorbatchev https://github.com/alexgorbatchev: You should make the
case to your team that nearly every ES6 feature that they want is already
done better by CoffeeScript today.—
Reply to this email directly or view it on GitHub
<
#3162 (comment).
—
Reply to this email directly or view it on GitHub
#3162 (comment)
.
If someone wants to cook up a solid, thought-through proposal that adds module-related keywords to CoffeeScript (e.g. export), and allows the resulting output to compile down to either ES2015 modules, CommonJS modules, or AMD modules — as specified by the user, I think that would be a proposal worth taking a look at.
I think module system transpilation (es6 -> commonjs / amd) is outside the scope of coffeescript, whose sole purpose is to produce javascript.
That said, no reason not to allow users to use the import / export keywords if they're targeting es6.
I'm happy that @jashkenas finally expressed interest in implementing modules.
But u agree with @kieran: CS modules should taerget modern ES standard. It's up to user whether not to use them, use them literally, or use with a transpiler.
Recommendation: Ask Guy Bedford about how to do this, he has the most
experience, I believe, in modules and optimal use of them for both node and
the browser.
On Wed, Feb 4, 2015 at 9:36 AM, Andrey Mikhaylov (lolmaus) <
notifications@github.com> wrote:
I'm happy that @jashkenas https://github.com/jashkenas finally
expressed interest in implementing modules.But u agree with @kieran https://github.com/kieran: CS modules should
taerget modern ES standard. It's up to user whether not to use them, use
them literally, or use with a transpiler.—
Reply to this email directly or view it on GitHub
#3162 (comment)
.
I don't want to go that far. I believe that "supporting" ES6 modules should require nothing more than moving import, export, and default from the "forbidden" list to the "strict proscribed" list. This should allow anyone to use those keywords, and have them show up in the compiled code the way they're written in CS.
After that, another preprocessor can take it from there. Eventually, there might be browser support, too. But, we don't need to get involved in that. And, we shouldn't.
On the other hand, if anyone wants to write and maintain an independent translator between module formats, I imagine that would go over really well with the community.
I agree with @bjmiller. I would not expect that CoffeeScript would implement those keywords. Making those words no longer keywords would be a good start.
After looking at the proposed syntax, there's a slight additional tweak necessary to my suggestion. If you write import { a, b } from 'foo';, the bracketed expression would expand into an object. So, you'd have to either be aware to not do that, or have an alternate syntax that ends up correct in the end.
Any suggestions on a proper CoffeeScript-y way to handle that?
Maybe the same rules that cover backticks could be applied to the pairs import ... \n and export ... \n ?
No, we just need a different kind of "objects" that won't expand {a} to {a: a} (or maybe we can do away with it entirely and just have an import node)
And we obviously need the lexer to be taught not to treat imports as implicit calls.
Well... it looks like this will take more work than just permitting previously forbidden keywords. 😩
Well... it looks like this will take more work than just permitting previously forbidden keywords.
Yes, that would be a lazy and half-assed way to go about it ;)
CoffeeScript needs to be a coherent language — we should be putting in keywords that we "ignore" and hope that some other transpiler in the pipeline will be able to take care of.
If we're going to support export, then we should support it. Given that ES6 (ES2015) modules still don't exist at all (http://kangax.github.io/compat-table/es6/) ... that would mean compiling down to the different popular module formats that do.
I think that such a pull request has a moderately slim chance of being accepted — it's probably still better to wait until real JS modules are finished and fully described. But it's worth a shot.
It might be time to revisit this, a proper module system is one of the strongest reasons people are adopting Babel / abandoning coffeescript.
Rather than leaving export/import statements in the compiled source and leaving the job to another project like Webpack isn't it possible to wrap any files with an import statement and delaying them until the dependencies are met to make them load order independent?
Here's a naive version of what I'm describing:
lib.coffee
export square(x)-> x * xscript.coffee
import { square } from 'lib'
alert square(2)lib.js
// head
var _modules, _scripts;
_modules = {};
_scripts = [];
(function() {
_modules['lib'] = {}
_modules['lib'].square = function(x) {
return x * x;
}
})();script.js
_scripts.push(function() {
var square;
square = _modules['lib'].square;
alert(square(2));
})
// tail
var i, len;
for (var i = 0, len = _scripts.length; i < len; i++) {
_scripts[i]();
}This may be naive but it doesn't seem like an impossible task to get the expected behavior of modules inside of coffeescript.
Your suggestion requires the compiler to know in advance what the other modules are, or whether they even exist, and then resolving the dependencies.
This would require at least as much code as already comprises CS, and is clearly the job for another project.
The only thing that CS should do here is enable the user to specify the syntax for modules that they want. This already works for commonjs and AMD. The only thing CS can't do is emit the unpleasant ES6 module format without using backticks. There should be a way to do simply that - but no more.
But this would require runtime support.
Yeah, I was proposing an alternative that could compile to javascript without modules or need for a runtime. What are the important features of modules that you'd lose if you stripped them out?
I know the original question is about being able to consume es6 modules within coffeescript, my solution doesn't help with that at all, it would only allow us to use export / import in coffeescript. If you're planning on mixing es6 and coffeescript then you'd definitely need a module loader and runtime.
Your suggestion requires the compiler to know in advance what the other modules are, or whether they even exist, and then resolving the dependencies.
Would it? Why is the current filepath not enough? You'd need to include a head / tail script at some point.
It will throw an error if you try to import something that doesn't exist but that's exactly what I'd expect.
I've been using poor mans modules/namespaces and it's been working well except for the problem of order dependency.
# pseudo export
App.Components.Tab = {}
# pseudo import
{ Tab } = App.ComponentsNow that es6 has widespread adoption I'd prefer to be able to use export / import being aware of the filepath as the module-name and have the issue of source order independence sorted. My silly example delays any scripts using an import til the end and runs through them in order.
The idea of modules is being able to share and consume code in standard ways, so limiting coffeescript modules to use within coffeescript is probably a terrible idea. Move along.
BTW: I did a successful experiment using backticks with module
import/export within coffeescript "modules", first compiling w/
coffeescript, then running the resulting JS through traceur with only
modules enabled. Then using a module loader to manage the difficulties of
actually gluing the results together. It worked fine, although adds an
extra workflow step.
On Tue, Oct 6, 2015 at 7:00 PM, Mark notifications@github.com wrote:
But this would require runtime support.
Yeah, I was proposing an alternative that could compile to javascript
without modules or need for a runtime. What are the important features of
modules that you'd lose if you stripped them out?Your suggestion requires the compiler to know in advance what the other
modules are, or whether they even exist, and then resolving the
dependencies.
Would it? Why is the current filepath not enough? You'd need to include a
head / tail script at some point.
It will throw an error if you try to import something that doesn't exist
but that's exactly what I'd expect.I've been using poor mans modules/namespaces and it's been working well
except for the problem of order dependency.pseudo exportApp.Components.Tab = {}
pseudo import{ Tab } = App.Components
Now that es6 has widespread adoption I'd prefer to be able to use export /
import being aware of the filepath as the module-name and have the order of
source order independence sorted. My silly example delays any scripts using
an import til the end and runs through them in order.—
Reply to this email directly or view it on GitHub
#3162 (comment)
.
I'm about to abandon CoffeeScript because non-compatibility with ES6 style modules. The lack of import/export for more than two years seems like a sort of language suicide. A shame because I really loved CoffeeScript and will hate to walk away from it.
I'm in the same boat, I think a lot of others are as well. It's hard to keep up with new libraries and techniques when they require huge workarounds to function with CoffeeScript.
For modules, I recommend JSPM .. its more standards based.
I'm using it because for development, it has no workflow .. just code and
load in a browser.
I've also used the JSPM bundler and it does just what it should, and
produces very fast code. It is built on top of es6-module-loader (github)
if you'd prefer more control over module loading. Both are lead by Guy
Bedford.
I recommend Babel over Traceur due to readability and wider scope such as
JSX etc, and es7 support too.
The main problem for modules is workflow for module loading (not part of
es6 spec), which is what JSPM is, although it will transpile while
traversing the dependencies too.
But there are way to many, legacy approaches like bower, browserify,
webpack and so on. Yes they work but I dislike the multiple formats being
produced so I'm sticking with the standards approach JSPM
and es6-module-loader via System.js.
-- Owen
On Sun, Oct 25, 2015 at 1:18 PM, Sean Roberts notifications@github.com
wrote:
I'm in the same boat, I think a lot of others are as well. It's hard to
keep up with new libraries and techniques when they require huge
workarounds to function with CoffeeScript.—
Reply to this email directly or view it on GitHub
#3162 (comment)
.
Why can't import/export be passed through like require is? CoffeeScript doesn't resolve require statements, it lets Node or Browserify handle it. Why can't import and export be the same way?
require is just a regular function. Nothing special is done about it. import and export are language constructs.
Yes - it is because they are so different from legal ES5 constructs that there's no way to express them using CS.
I'll reiterate that I personally think that the syntax should change slightly to allow valid ES6 module statements to pass through untouched without the use of backticks, but that nothing more should be done with them. This would make everyone happy, while being fully backwards-compatible - since export, import, and default are all presently on the reserved words list.
I think the solution is now clear, along the lines of what Jeremy originally suggested and what @bjmiller is saying, all it needs is someone to bang out the implementation, make a fork, test it, and it'll come around to the compiler. It's not gonna be simple, because it requires treating syntax after import and export differently, but it's doable.
Some notes (following the description here, if it's incorrect correct me):
- export will have to be tracked and pushed to the var declaration, which complicates var compilation (it's not a simple list anymore, but two lists, one for exported and one for unexported vars)
- syntax needs to be finalized, starting with the simple case,
export { each as foreach }should (imo) beexport {foreach: each} import { square, diag } from 'lib'could be used verbatim, although it is a rather strange new piece of syntax to add to CoffeeScript (esthetically, passing a string tofromfeels really weird), I think Node makes so much more sense here, but surely the committee had their reasons..., I can only think ofimport 'lib' as {square, diag},{square, diag} = import 'lib'is probably undoable and has too much of a surprising compilation output- alternatively (there is an issue with default vs object import, see below):
import _, { each } from 'underscore'(verbatim)import 'underscore' as _, { each }(reversed)_ = {each} = import 'underscore'(tough to parse)
- same applies for pure default import (
import myFunc from 'myFunc') (although see below)
- alternatively (there is an issue with default vs object import, see below):
- using
{a: b}instead of{b as a}inimport - good old multiply, generator and now an import wildcard
import * as mylib from 'src/mylib', which is the object import, different from the default import (for some reason there are both), again, we can implement it verbatim or, for example:- only support default import via
defaultkey,import 'myFunc' as {default: myFunc}, leavingimport 'src/mylib' as mylibormylib = import 'src/mylib'as the object import above
- only support default import via
Folks here will surely have a better sense of what to do syntactically. The output is a valid ES6 code, intended to be further compiled using Babel or whatever you prefer.
I don't think we even have to do that much. Just make the syntax for import and export legal (as it is in ES6), and have it place the exact statements as written to the compiled result.
I don't believe that there is anything that CS can do to make the syntax any more palatable. I've tried thinking about how one could make the syntax of it less ugly, and nothing that comes to mind improves it any. ¯_(ツ)_/¯
But, ultimately, the use of that syntax is what people are asking for. No one wants an alternate version of module salad. They just want to pass the output to another tool in the chain. I see this as being somewhat like generators, in that it's a "buyer beware" feature. You use it if you know you can get it to work downstream, otherwise you avoid it.
What I definitely don't want to see is an attempt at also doing what Babel does, changing ES6 module syntax to CommonJS require statements.
With the upcoming release of Meteor 1.3, we will have two major JavaScript frameworks (along with Ember) that require import/export statements. I think it’s time to prioritize allowing a way, other than backticks, to pass through import and export for an ES2015 parser to evaluate.
ember-cli-coffees6 works around this problem by doing some string substitutions to replace import/export statements written in Coffee style before the real CoffeeScript compiler parses the code. This strikes me as a hack for something that should be part of CoffeeScript core, but I thought I’d draw your attention to one possible solution.
One other thought: should we not add something like target: 'es2015' to the build params? That way ES2015 import/export statements are allowed only when CoffeeScript is configured to output ES2015, rather than ES5; and when the target is ES5 either keep the current lack of support for import/export or implement one of the other proposals mentioned above. (This also opens the door for other variations in generated output for target: 'es2015' mode, such as compiling => into =>, for example.)
@GeoffreyBooth Agree with the proposal for the build targets and the reason.
I also believe that this is a major feature hole in CoffeeScript and to keep it relevant in relation to the current alternatives (es6, TypeScript, etc...) the ability to have imports/exports needs to be present. I've been having to hack in solutions for large projects in the meantime. This is an area that is pushing developers into other solutions. That's unfortunate because CoffeeScript has a lot to offer, but is becoming irrelevant by not keeping up with some of these important features.
Agreeing with @GeoffreyBooth again, this standard should be compile differently depending on it's intended target (es2015/es6). I also think the feature should look more like python imports/exports. Treat anything in the global scope of a CoffeeScript file as an export. So as a proposed example of how this could implemented:
# common.coffee
global_var = 'SOMETHING'
class SomeService
constructor: ->
doSomething: ->
helper = -># main.coffee
import common
service = new common.SomeService()
common.helper()
console.log common.global_var
# or
from common import SomeService, helper
service = new SomeService()
helper()
# common.helper and common.global_var are availableAlso provide the ability to alias import with as like import common as shared or from common import SomeService as SomeSharedObject, helper as someHelper. Reason for this is that I believe it follows better the flow of CoffeeScript, and allows for it be more Pythonesque with syntactic sugar and easy readability. Which are the some of the advantages of using CoffeeScript.
@jashkenas Please reopen.
@jashkenas why is this still closed? I think the original reason for closing it is demonstrably not the case anymore.
Everything functionally works 100% fine right now AFAICT, it's just really annoying to have to add backticks to every expression that begins with import or export (which is becoming a major PITA)
What I'd love to see is this:
`import { member as alias } from "module-name"`
obj =
method: alias.bob
`export { obj as default }`becoming this (no backticks, that is all):
import { member as alias } from "module-name"
obj =
method: alias.bob
export { obj as default }FYI: the first example currently compiles (correctly) to:
import { member as alias } from "module-name";
var obj;
obj = {
method: alias.bob
};
export { obj as default };CoffeeScript needs no knowledge of the effects of this code IMO, and targeting other module systems should be left to a transpiler after the CS compilation step.
CS is protected from compatibility concerns since import and export are already reserved words. Is there no way to simply pass through any expression that begins with them un-molested?
I believe the reason it is closed is that it is not a language issue, but a browser, WHATWG standards body, problem. Although @jashkenas could solve the strictly syntax/semantics of import/export, he could not solve the module loader problem.
From the discussion thus far, I would say many of us are not familiar just how gawd awful this is!
Please see this for a discussion on the simplest solution yet:
https://groups.google.com/d/msg/systemjs/a7vB2YmdXp8/HCh1Rx0XEAAJ
I will warn you that the babel folks as well as the module loader folks will lead you down horrible workflows with npm/browserify/babelfy, webpack, and the less awful jspm. The whatwg lack of standard is creating module wars, not pleasant. Do recall that systemjs is the only standards based solution at this point in time.
I believe the issue should remain closed until we do serious research on the module loader nightmare. Then pick a strategy. And remember, your choice of loader will affect the compiled code depending on your chose of CommonJS, AMD, SystemJS.
I'll whisper on other solution: bundling. I do NOT recommend it (it is deprecated due to slowing down HTTP/2 parallel/async download speeds) but it may provide a solution to the complexity. As an example, JSPM provides a bundling method with no additional required <script>'s. Likely the others do to. But do you really want more workflow and required bundling?
Keep it closed 'til you can answer all the above questions. Seriously.
@backspaces I think you and @kieran (and I) are talking about two different things. What I was proposing with target: 'es2015' and/or simply removing import and export from the reserved words list, is let CoffeeScript compile import and export statements the same way it compiles require statements—that is, just convert the CS syntax to the JS syntax and leave it at that. Like @kieran’s second example. It sounds to me like what you’re talking about is asking CoffeeScript to do what Babel does, which is to actually do the module importing and exporting etc. But if our target is ES2015, and import/export are part of ES2015, then there’s no further processing/module loading necessary.
Since the backticks solution already works, would simply removing import and export from the reserved words list be sufficient? With the caveat to the user that they need to make sure something else in their pipeline, or their JavaScript runtime itself, needs to know what to do about those statements. Then import/export would behave just like require does now, and generally anyone who writes such statements knows that they need something else to process them. Do we even need target: 'es2015' or allowImportExport: true or the like in the params, if this is all we’re doing?
Hi!
On Thu, Dec 17, 2015 at 2:31 PM, Geoffrey Booth notifications@github.com
wrote:
@backspaces https://github.com/backspaces I think you and @kieran
https://github.com/kieran (and I) are talking about two different
things. What I was proposing with target: 'es2015' and/or simply removing
import and export from the reserved words list, is let CoffeeScript
compile import and export statements the same way it compiles require
statements—that is, just convert the CS syntax to the JS syntax and leave
it at that.Ah! So a require('foo') works correctly in CS? And you can just include a
library implementing the require() correctly?
exports.__esModule = true;
exports.square = square;
I didn't realize that. (I think the first line is for signaling
import/export syntax but not sure). The example is from the babel REPL
using the commonjs default module loader for the 2015 preset.
The "import" used by babel's commonjs is simply:
var _libSquare = require("lib/square");
.. not sure why the _ but...
Can all this simply use RequireJS in a <script> tag? I believe they prefer
a different use, but if its easy enough to use, then that's fine.
That handles the import. Do you do the require "export" by just directly
manipulating the exports object?
I see nothing wrong with import/export being removed from the reserved
words list.
Like @kieran https://github.com/kieran’s second example. It sounds to
me like what you’re talking about is asking CoffeeScript to do what Babel
does, which is to actually do the module importing and exporting etc. But
if our target is ES2015, and import/export are part of ES2015, then
there’s no further processing/module loading necessary.I'm not sure I understand. You're proposing a target es2015
would simply leave import/export alone, i.e. not reserved words, right?
But there's all the syntax that goes with import/export. Coffee would have
to grok that, unless you require a terminator like a semicolon or EOL.
Since the backticks solution already works, would simply removing import
and export from the reserved words list be sufficient? With the caveat to
the user that they need to make sure something else in their pipeline, or
their JavaScript runtime itself, needs to know what to do about those
statements. Then import/export would behave just like require does now,
and generally anyone who writes such statements knows that they need
something else to process them. Do we even need target: 'es2015' or allowImportExport:
true or the like in the params, if this is all we’re doing?Removing import/export from reserved words, and somehow agreeing to skip
the ... ;/eol would at least get you ready for running the results thru
babel (to convert to one of commonjs, amd, system) .. i.e. be entirely
equivalent to backticking.
But it would leave a lot to be done by workflow.
Wouldn't you prefer a more CS standard module semantics of some sort? And
I'd prefer use of SystemJS because it would eventually be replaced in the
browser. I'd also prefer to avoid bundling, which I think most other
techniques prefer because it can avoid module loading all together.
But simply removing import/export from the reserved word list seems OK.
Full Disclosure: I've converted all new code to es6 and so am not as
current to this discussion as I should be!
Hope it all gets solved.
Folks, spend the couple of minutes and read through the previous discussion. Removing export and import from reserved keywords is not gonna work because there is more syntax to the statements in ES6, and CS has no way to parse them atm. No one wants to implement module system in CS at this point. Jeremy has always been against flags, although there is a possibility of CS2.0 if someone rewrote the compiler to target as much ES6/7/2016 as possible. See my comment and bjmiller's answers.
There's no need for any logic in CS around the importing or exporting of modules. This is taken care of at JavaScript's VM layer, and "CoffeeScript is just JavaScript" (or so I've heard)
es6 module syntax is opaque as far as the lexer is concerned, since it has no effect on the rest of the AST. We can just bulk-pass it like we do with literal JS strings.
Anyone wishing to use an alternative to es6 modules can (and should) continue to use traspilers. This should not affect your existing build pipelines at all.
As for targeting es6/7/2016 - using a language feature is implicit targeting IMO. No feature flags are (or should be) required.
Anyway: PR open, comments welcome!