ternjs / tern_for_sublime

Sublime Text package adding Tern support
MIT License
803 stars 54 forks source link

Does this work with ES6/2015 imports? #90

Closed dan-gamble closed 8 years ago

dan-gamble commented 8 years ago

An example i was trying was React.

When i do var React = require('react'); i get autocomplete React.cr suggests createClass When i do import React from 'react'; i don't get any autocomplete at all.

Is there a setting to change or does it just not support it out of the box? :)

cr0n0s commented 8 years ago

Try using

import * as React from 'react';

I have not tried React but the autocompletions do not work if you do:

pastedgraphic-5

But it works if i do the following

pastedgraphic-6 pastedgraphic-7
dan-gamble commented 8 years ago

Hmm i tried that myself even with child_process and neither seemed to work for me. Do you have anything special in your .tern-project?

marijnh commented 8 years ago

Have you enabled the es_modules plugin?

dan-gamble commented 8 years ago

In my .tern-project i have:

{
    "plugins": {
        "node": {},
        "modules": {},
        "es_modules": {}
    }
}

Is this the correct syntax?

dan-gamble commented 8 years ago

Saying that i just tried @cr0n0s import * as React from 'react'; and that does seem to offer auto complete that will do unless it is possible to do it with the standard import way :)

marijnh commented 8 years ago

It seems Babel has some magic to automagically allow non-ES6 modules to be imported in this way, though the standard doesn't require it (it just says that you get the export named default when you import like this). Tern isn't currently aware of this fallback feature. Can anyone point me to a description of discussion that explains how it really works?

(cc @sebmck: Maybe you can shed some light on this?)

sebmck commented 8 years ago

@marijnh There was a really good gist by @jeffmo that explains how the interop works. (The interop is the same in Flow) but I can't manage to find it. @jeffmo, have a link handy?

Basically all compiled ES6 modules have an __esModule property set to tell us that it's been a compiled ES6 module. This is important since as you've ascertained, there's some magic going on behind the scenes. Here's some desugaring (taken some liberty with the equivalent CommonJS, the generated code isn't nearly as pretty) for the following constructs:

import "foo";

require("foo");
import foo from "bar";

var _foo = require("bar");
var foo = foo.__esModule ? _foo.default : _foo;
import { foo } from "bar";

var foo = require("bar").foo;
import * as foo from "bar";

var _bar = require("bar");
var bar = {};
if (bar.__esModule) {
  bar = _bar;
} else {
  for (var key in _bar) bar[key] = _bar[key];
  bar.default = _bar;
}

If you're curious here are some of the issues that lead to this behaviour: babel/babel#95, babel/babel#845, babel/babel#673, babel/babel#587, babel/babel#493, babel/babel#406.

jeffmo commented 8 years ago

I don't recall (and can't find) a gist, but I did make a lot of Flow tests and a weird table diagram for it. The diagram isn't very precise though and might be kind of confusing if you're not me, so I'll refrain from posting it I guess

marijnh commented 8 years ago

Attached Tern patch should work. It doesn't entirely follow the behavior of Babel, but should do the right thing in almost all situations -- it'll propagate the module's default property into the imported binding, and propagate the whole module into it as well with a lower weight. That way, if there's a default property, you get that, and if not, you get the module.

marijnh commented 8 years ago

That's tern patch https://github.com/marijnh/tern/commit/7b22a74a707e04ed5b542b57e1be0955a3a80ef7