Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ES6 import syntax #1186

Open
romeovs opened this issue Apr 1, 2015 · 52 comments

Comments

@romeovs
Copy link

commented Apr 1, 2015

This might be a long shot but I'd like to see this in browserify.

The ES6 module syntax has a few nice features compared to commonJS require method,
namely bindings and cyclic dependencies.

Since these things are in the ES6 standard it seems reasonable to work them into browserify too!

Note that just using a ES6 to ES5 transpiler wouldn't work in this case because these are cross module concerns.
For instance, babelify is only able to transpile import foo from 'foo' to var foo = require('foo') at file-level, but this does not allow cyclic dependencies.

The Esperanto project has a nice way of handling things but lacks too many features to be a valid replacement for browserify.

Is there any possibility to see support for ES6 import syntax come to browserify?

@substack

This comment has been minimized.

Copy link
Collaborator

commented Apr 1, 2015

I've been waiting for this feature to land in node first so browserify can match the semantics properly. I'm also concerned that if browserify implements a default es6 import mechanism while node doesn't have one, it will needlessly fragment browser and server ecosystems.

@romeovs

This comment has been minimized.

Copy link
Author

commented Apr 1, 2015

Yes, my approach to writing modules is currently to write them in ES6 but only expose ES5-compliant
code (transpiling everything on npm publish for example).

I get your concerns, and they are indeed important ones.

How feasible would you say it is to expose this as a plugin for browserify (I'm currently looking into
writing that).

@romeovs

This comment has been minimized.

Copy link
Author

commented Apr 1, 2015

I've created a small gist with a proof of concept for a plugin. I'll start working on it!

@nmn

This comment has been minimized.

Copy link

commented May 20, 2015

@romeovs
You can already use a transform like babelify to get ES6 imports. With both Node and Browserify. You can turn off the other features if you don't want them.

@romeovs

This comment has been minimized.

Copy link
Author

commented May 20, 2015

@nmn but do these imports with babelify have the complete ES6 semantics?
As far as I can see they just transform the import statements into require statements, but require and import have different semantics with respect to bindings and cyclic dependencies.

The problem is really the way browserify concatenates the imported files. esperanto does this correctly, but lacks other features that make browserify a much better choice.

@romeovs

This comment has been minimized.

Copy link
Author

commented May 20, 2015

@nmn after some testing I can see that it does!

@fregante

This comment has been minimized.

Copy link

commented Aug 17, 2015

I think @substack is right in waiting for proper node support. browserify brings node to the browser; if node doesn't support import, browserify shouldn't either.

If babelify doesn't follow the right semantics, raise the issue with them or ask for an esperantify plugin.

@flyingrobots

This comment has been minimized.

Copy link

commented Dec 15, 2015

How about now?

@yoshuawuyts

This comment has been minimized.

Copy link
Contributor

commented Jan 25, 2016

It appears a good deal of fragmentation will start occurring because of d3@4.0.0 relying on es6 imports. It's not seen an official release yet, but given the buzz around its components I think it's already becoming somewhat of an issue.

I know that Node doesn't support ES6 imports quite yet, but arguably browserify is in a somewhat different spot since it doesn't support dynamic imports (or at least I don't think it does out of the box).

The reason why I think we should consider options is because if other loaders become popular because of only a single feature, it might signal there's a need for it.

I'm not quite sure what the correct resolution is; for the package I'm writing that consumes d3 I might include a compiled build (breaking npm reliance) or include babelify (making the package very heavy) - though neither is ideal. Perhaps an importify transform needs to be written, or perhaps this should be resolved at the browserify level - I'm not sure.

For now I'm posting this here to signal that changes are happening, and we'll probably need to think of a solution for this 😕

edit July 2016: nope nope, we shouldn't move ahead on import unless Node does so (which it frankly might not, so hey)

@terinjokes

This comment has been minimized.

Copy link
Contributor

commented Jan 25, 2016

@yoshuawuyts Implying that d3@4.0.0 only works with loaders that support ES6 modules is a bit disingenuous. The main field in the root's package.json and the individual modules all point at Node.js compatible files (and I'm successfully using several d3 modules with Browserify just fine)

@dantman

This comment has been minimized.

Copy link

commented Jan 25, 2016

Browserify's greatest feature is the transform pipeline (heck the parts that actually break require into a dependency tree and combine that tree into a bundle aren't even in this repo, they're the module-deps and browser-pack packages) and the collection of transforms we have that make . IMHO rollup's greatest feature is not ES6 imports, but the static analysis and tree shaking it does. So even if browserify rushes to hastily implement non-babel ES6 import support before any JS engine natively supports it, I doubt that'll stop may people from using rollup.

There are already a pile of other packages using ES6 import; but they all do it alongside the use of other ES2015 features. So I expect packages like d3 that only use ES6 import is going to be a rarity. And the moment you use any other feature, you need Babel, whether you're using rollup or browserify. So I doubt "rollup lets me use packages that only use ES6 import without needing Babel" will be the reason people use rollup.

I think the problem browserify is going to have is rollup's plugins. That functionality is what turns rollup from just a tool to pack up ES6 exports/imports into something that can pass as a standalone loader.

Rather than trying to hack ES6 import in with require schematics, just as a way to bypass babel in a few cases (because if you use Babel this is already entirely possible). I think it would be better to accept the area that rollup is better at (tree shaking ES6 imports) and find a way to break up rollup and create a rollupify plugin that will integrate rollup's tree-shaking and also act as an optional ES6 import handler for those that don't want to use babelify.


It's a different topic. But I think browserify's other undoing may be how easy it I've seen it is to make a simple transform but hard it is to make one that correctly preserves source maps. I don't see any easy tools for source-map aware string manipulation. And while I'd love to transform using an AST, that's not viable when each transform has to source -> parse to AST -> transform -> AST to source -> source instead of sharing an AST. At this point, in my own code, I can't tell if my source maps work or not anymore and I have no clue which piece might be at fault for messing with them.

@jokeyrhyme

This comment has been minimized.

Copy link

commented Mar 7, 2016

FYI: there's an enhancement proposal for Node.js being discussed here regarding ES2015 modules:

@gregtatum

This comment has been minimized.

Copy link

commented Jul 27, 2016

Coming in to say I'm actively getting issues because d3's latest version is only using ES6 syntax. I can't use my browserify tooling now. The time seems ripe for this change as the ecosystem has already begun the move, otherwise I think browserify will have lost its relevance in this increasingly competitive bundling space.

@jmm

This comment has been minimized.

Copy link
Collaborator

commented Jul 27, 2016

Hello @TatumCreative. D3's README says their releases support CommonJS. Is that not the case? Even so, there are multiple tools for compiling ES6 module syntax to CJS -- can you not use one of those?

@gregtatum

This comment has been minimized.

Copy link

commented Jul 28, 2016

Hmm... Yeah my bad. It looks like user error on my part. Sorry about that. My opinion still stands though. Three.js just landed a big patch to go the ES6 route as well. Personally I'm in a weird position as I tend to primarily target one browser and I want what Browserify does with bundling without the side-effect of mangling my ES6 code and turning it into ES5 code.

I can probably come up with a solution if I do more research, but regardless I still feel it is important to support ES6 imports sooner rather than later, as the community is already adopting it in projects. I feel like fragmentation is happening as people have moved on to other bundling solutions, which I would really not have to do, as I really love the browserify tooling ecosystem. All that said, I probably don't have the time to contribute to this project to make it happen, and I appreciate the work everyone does here!

@terinjokes

This comment has been minimized.

Copy link
Contributor

commented Jul 28, 2016

@TatumCreative I'm glad that you were able to correct this issue. The contributors to Browserify, including myself, understand your frustration.

Browserify has always been a way to use Node.js-compatible modules in the browser. As a result, Browserify has always looked to Node.js for how to implement the module resolution and loader. Right now Node.js doesn't support ES6 imports; there are blockers in other parts of the stack. We don't yet know the final algorithms or behaviors.

While slower than we would all like, these efforts are moving ahead. I'm excited for the day! Once Node.js has implemented ES6 imports and exports, we can add support to Browserify.

You may wish to opt-in to a possible future, and Browserify's plugin system allows you to do so. But it's not the place for us to make that decision for everyone.


As an aside, there's probably still a few improvements to Browserify to make using standardized ES6 a little more comfortable, even without imports and exports. I'm happy to take a look at those issues. 💖

@jmm

This comment has been minimized.

Copy link
Collaborator

commented Jul 28, 2016

@TatumCreative Ok, no problem, thanks for the feedback.

Personally I'm in a weird position as I tend to primarily target one browser and I want what Browserify does with bundling without the side-effect of mangling my ES6 code and turning it into ES5 code.

I understand. That's not that weird of a position, as people increasingly want to selectively transpile parts of ES6. For example, only transpile the parts not natively supported by recent versions of Node. ES6 has no native module bundling story anyway, so even if a browser supported ES6 100% you might still want to bundle them via transpiling just module syntax to ES5.

I think there's probably a solution for you. If I'm not mistaken some people run Rollup to convert module syntax before carrying on with bundling with Browserify, or you could run Babel (Babelify) with just the module transform enabled. With Rollup you could get the benefit of tree shaking as well.

but regardless I still feel it is important to support ES6 imports sooner rather than later, as the community is already adopting it in projects.

Like other people have mentioned, the community is adopting the syntax and speculating about what behavior will be standardized. So it's not necessarily all smooth sailing to implement it now. For example, from version 5 to 6 the core Babel CommonJS module transform made a big change in its output. If you look at the issue linked in the comment before yours up above you'll see that the discussion about how to implement ES modules in Node is epic and very complex.

I feel like fragmentation is happening as people have moved on to other bundling solutions

I think that has more to do with other factors than this.

I appreciate the work everyone does here!

Thanks!

@gregtatum

This comment has been minimized.

Copy link

commented Jul 28, 2016

Thanks @jmm and @terinjokes! I think that is very well reasoned, and I agree with where you all are coming from. I'll probably end up adding another tool to help me deal with this until all of this gets sorted out on the node end. I can deal with a little bit more tooling complexity on my end :) I'm almost afraid to read that node module discussion, lol.

Keep on rocking it! 😀

@gregtatum

This comment has been minimized.

Copy link

commented Aug 15, 2016

For anyone coming into this thread, the browserify transform rollupify will take all of your ES6 import statements and hoist them all into a single module scope.

@gkatsanos

This comment has been minimized.

Copy link

commented Jan 4, 2017

I am assuming I can't use ES6 style imports with browserify and babelify still?

@yoshuawuyts

This comment has been minimized.

Copy link
Contributor

commented Jan 4, 2017

@gkatsanos

This comment has been minimized.

Copy link

commented Jan 4, 2017

I use browserify in Gulp.. does this change things?:)

@yoshuawuyts

This comment has been minimized.

Copy link
Contributor

commented Jan 4, 2017

@gkatsanos

This comment has been minimized.

Copy link

commented Jan 4, 2017

What does "not recommended" mean? The end result seems to work?
Should I just drop gulp/browserify and use webpack instead?

@yoshuawuyts

This comment has been minimized.

Copy link
Contributor

commented Jan 4, 2017

@gkatsanos

This comment has been minimized.

Copy link

commented Jan 4, 2017

Alright. From reading around it seems to me that's the basic syntax is pretty finalized and is the future but I could be wrong of course.

@terinjokes

This comment has been minimized.

Copy link
Contributor

commented Jan 4, 2017

@gkatsanos the syntax is stable, but the mechanics of how to do imports (and specifically, how Node.js will do imports) are still being figured out.

Browserify is a set of tools that together bring Node.js's module resolution and loading to the browser. Since Node.js doesn't support importing ES6 modules, we have nothing to implement.

@gkatsanos

This comment has been minimized.

Copy link

commented Jan 4, 2017

@terinjokes alright, it's clear. How does browserify compare to webpack in that respect?

@terinjokes

This comment has been minimized.

Copy link
Contributor

commented Jan 5, 2017

@gkatsanos Being module bundlers, Webpack and Browserify are similar. They take input, resolve a tree of dependencies, and generate a bundle (or bundles) as output.

As described above, Browserify supports only require at the moment. Webpack supports the illusion of other module types, including AMD and ES6, but the resolution algorithm is the same. If you used AMD modules expecting dependencies resolution according to AMD's rules, you'd be surprised to learn that it instead uses the Node.js require rules!

Neither project knows how Node.js will handle ES6 resolution and loading. There have been discussions of using separate file extensions or looking up a key in the module's package.json. We'll have to wait and see gets implemented.

Webpack's plugin system would likely allow them to pivot and allow developers to configure which behavior they want. Browserify prefers waiting for Node.js to decide and not have the need for configuration or the fears of breaking user applications.

@gkatsanos

This comment has been minimized.

Copy link

commented Jan 5, 2017

@terinjokes (referring to Bootstrap v4) :
https://github.com/twbs/bootstrap/blob/v4-dev/js/src/carousel.js
...
import Util from './util'
export default Carousel

@terinjokes

This comment has been minimized.

Copy link
Contributor

commented Jan 5, 2017

@gkatsanos If you installed bootstrap@4.0.0-alpha.5 as noted in their Quick Start you'll see that they distribute ES5 code (by default) for this reason.

@gkatsanos

This comment has been minimized.

Copy link

commented Jan 5, 2017

@terinjokes This is the code from alpha.5 :
https://github.com/twbs/bootstrap/blob/v4.0.0-alpha.5/js/src/carousel.js
and I believe this is ES6 modules?

@terinjokes

This comment has been minimized.

Copy link
Contributor

commented Jan 5, 2017

@gkatsanos In the npm releases they distribute ES5 code. That is, they compile the ES6 to ES5 before publishing the package.

@terinjokes terinjokes closed this Jan 5, 2017

@terinjokes terinjokes reopened this Jan 5, 2017

@gkatsanos

This comment has been minimized.

Copy link

commented Jan 5, 2017

@terinjokes sorry, not following. The compiled version isn't related to what we're trying to do here which is use only 1 out of the 10 Bootstrap plugins :) (a bit like how we can import lodash.debounce without loading the entire lodash library.)
twbs/bootstrap@ce2e944

@terinjokes

This comment has been minimized.

Copy link
Contributor

commented Jan 5, 2017

var Carousel = require('bootstrap/js/dist/carousel');

@gkatsanos

This comment has been minimized.

Copy link

commented Jan 6, 2017

Nah, doesn't work because the Carousel module is requiring another library (with ES6 imports) - I read on it and it seems Bootstrap v4 hasn't yet made it possible for people to use plugins independently.

@AurelioDeRosa

This comment has been minimized.

Copy link

commented Jan 19, 2018

@gkatsanos it's now possible to import plugins individually but I'm not clear how to do that with browserify (the doc only mention a Webpack solution).

@mattdesl

This comment has been minimized.

Copy link
Contributor

commented Jul 9, 2018

I'm curious what the current feel is on this, now that ES6 modules are in browsers (at least in some form). I've also noticed more modules on npm being published with code that works fine in Webpack/Rollup/Parcel (and other ES6-able bundlers) but does not work in Browserify.

I personally don't like import/export but if the rest of the community is using it, and browsers are adopting it, I feel Browserify should definitely follow suit, even if Node.js hasn't fully adopted it yet.

@ljharb

This comment has been minimized.

Copy link
Member

commented Jul 9, 2018

I don't agree; until node supports it unflagged, browserify shouldn't support it.

Browsers only currently support URLs with import, and node doesn't support URLs with import.

@gkatsanos

This comment was marked as disruptive content.

Copy link

commented Jul 9, 2018

It doesn't really matter. No-one is using browserify any more. It's hanging out with its old buddies Grunt and Gulp somewhere.

@mattdesl

This comment has been minimized.

Copy link
Contributor

commented Jul 9, 2018

@ljharb Makes sense.

Another option: what about allowing import syntax and just ignoring it? Or perhaps providing a warning that it was skipped? I'm enjoying the new dynamic import() support in browsers (which isn't possible to fully re-create with a bundler), but I can't use that syntax currently in browserify.

In the mean time I am considering writing a small transform to handle this transparently so users don't need to deal with babel/config/etc.

EDIT: I just realized browserify actually supports dynamic import() already, it only fails on static import/export. So maybe no need to change browserify yet.

@ljharb

This comment has been minimized.

Copy link
Member

commented Jul 9, 2018

(dynamic import() is also available in Scripts, import is only available in Modules)

@ljharb

This comment has been minimized.

Copy link
Member

commented Jul 9, 2018

It wouldn't be safe to treat a Module as if it was a Script - modules are in auto-strict mode, for examples, and there's a number of things that could behave differently.

@mattdesl

This comment has been minimized.

Copy link
Contributor

commented Jul 10, 2018

For the mean time, I've created a browserify plugin that:

  • Adds .mjs extension to browserify so that it takes precedence over .js
  • Use "module" field in package.json (when "browser" is not specified)
  • Transform ES Module import/export syntax into CommonJS so that it can be consumed & used by browserify

See here:
https://github.com/mattdesl/esmify

@mukururo

This comment was marked as off-topic.

Copy link

commented Sep 16, 2018

I am happy and excited with the upgrade

@mukururo

This comment was marked as off-topic.

Copy link

commented Sep 16, 2018

Let's work together to meet my obligations to work

@Swoorup

This comment has been minimized.

Copy link

commented Nov 14, 2018

Since now its in experimental state in node? What is the state of this?

@ljharb

This comment has been minimized.

Copy link
Member

commented Nov 14, 2018

Experimental means it’s too soon for it to be used. Browserify should not support ESM until it’s supported unflagged in node; and once it is, imo browserify must support it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.