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

6.0 #2168

Closed
sebmck opened this issue Aug 5, 2015 · 90 comments
Closed

6.0 #2168

sebmck opened this issue Aug 5, 2015 · 90 comments
Milestone

Comments

@sebmck
Copy link
Contributor

sebmck commented Aug 5, 2015

Foreword: None of this is really set in stone. Feel free to argue and discuss. This is kinda a long issue so I added some gifs, I hear developers love that kind of stuff. This post is also a bit rough, figured it's better to get it out there ASAP, I'll improve it as more feedback is collected. Thanks everyone for your (potential) participation!

What is 6.0 going to look like?

No internal transformers. None. Zero. Zilch.

This will be coupled with the removal of the following options:

  • whitelist
  • blacklist
  • optional
  • loose
  • stage

All of these options are redundant when you're manually specifying transformers.

This dramatically reduces complexity in the transformer options. Right now there's way too many ways to change the state of a transformer. This will reduce friction and make it easier to reason about what's actually enabled.

There's also a major problem with including very experimental syntax/transformers in core. If a big change was made to their semantics it would be a breaking change and would require a major version bump of Babel. In the interest of stability and being reactive to changes in the standardisation process, it makes sense to version them independently.

When?

idk

idk whenever

Where will all the current builtin transformers go?

Into userland plugins.

Wont this make it harder to use 6.x like we use 5.x?

Nope! 6.0 will also introduce the concept of presets. These are modules distributed via npm that specify a set of options (plugins etc) that will be merged into your main configuration.

Recommended

This means that the current ES6 to ES5 configuration would be distributed on npm via the babel-preset-es2015 package. It would have the index.js of:

module.exports = {
  plugins: [
    require("babel-plugin-arrow-functions"),
    require("babel-plugin-classes"),
    ...
  ]
};

To use this you'd just specify the following in your .babelrc:

{
  "plugins": ["preset-es2015"]
}

Community-specific

These can be even more specific. For example, the React community may have an official preset called babel-preset-react that will have the following index.js:

module.exports = {
  plugins: [
    require("babel-plugin-jsx"), // enables jsx syntax
    require("babel-plugin-flow"), // enables flow syntax

    require("babel-plugin-react-jsx"), // transforms jsx to flow
    require("babel-plugin-flow-comments"), // transforms type annotations to flow
  ]
};

Just like the es2015 preset, this could be enabled with the following .babelrc:

{
  "plugins": ["preset-es2015", "preset-react"]
}

Isn't this a dramatic shift in focus?

Nope, this is a part of the long term vision for Babel and everything has been leading up to this (cue dramatic music). I bought this up in #568 back in January where I said:

Ideally I'd like for 6to5 to be a more general JavaScript of the future transpiler. 6to5 already supports Flow/JSX as well as experimental ES7 features so the name isn't even representative of the project in it's current state although it is in how it's widely used.

A JavaScript transpiler based on future standards and specifications, whether ECMAScript or not, I think is an extremely noble goal. I think there's a large use case for 6to5 beyond just ES6. Having an interopable platform to base code transformations on I think is a very powerful idea. This may mean exposing a very feature-rich core that contains transforms or even exposing a public API.

What about syntax extensions?

I'll be holding out on allowing arbitrary syntax extensions for the timebeing. If we're going to do them at all, we're going to do them right. No point half assing a very critical and fragile piece such as syntax extension.

But if there's no syntax extensions then how would existing transformer that enable special syntax work?

So, the syntax would be implemented in the Babel parser Babylon, the "syntax plugins" would just toggle some parser options via an API. So the actual parser code would still live in Babylon. It's a neat solution until we support syntax extensions properly.

What else is coming?

Plugin options (#1833)

Plugin options are something that sorely needed.

Specifying options

These can be specified via a multidimensional array. For example, say you have a babel-plugin-pancakes plugin, you could specify options to it like so:

.babelrc

{
  "plugins": [["pancakes", { "syrup": "maple" }]]
}

But how would you specify options for plugins defined in a preset? One possible way is to specify them in the options to a preset, so if you had a preset like:

node_modules/babel-preset-breakfast/index.js

module.exports = {
  plugins: [require("babel-plugin-pancakes")]
};

Then you could specify the options for babel-plugin-pancakes like so:

.babelrc

{
  "plugins": [["preset-breakfast", {
    "pancakes": { "syrup": true }
  }]]
}

Accessing them from a plugin

export default function ({ Plugin }) {
  return new Plugin("pancakes", {
    visitor: {
      ObjectExpression(node, parent, scope, state) {
        if (state.options.syrup !== "maple") {
          throw this.errorWithNode("No objects allowed unless I get maple syrup >:(");
        }
      }
    }
  });
}

Swappable parser

Add a parser option to allow use of another Babel AST compatible parser.

Plugin hooks (#1485)

There's currently no good way to perform initialisation of a plugin. Currently you can use the Program visitor to kinda simulate this, but those callbacks are only called once the traversal has already started. The introduce of a init and post method to a Plugin will make this make nicer:

export default function ({ Plugin }) {
  return new Plugin("pancakes", {
    init(state) {
      // initialise
    },

    post(state) {
      // teardown
    }
  });
}

Way to provide the entire dependency graph to Babel

Another thing that I want to provide is a way to give Babel your entire dependency graph. This will allow cross file transformations. It'll allow us to catch more bugs (such as importing something from another module that wasn't exported).

This also allows us to simplify code (thus making it more performant) with access to other files. For example, we can drop the module interop output if we know that a file imported is ES6.

Minification plugins

I believe we can do minification better (if not equivalent) as UglifyJS. With the potential type information available this has the potential to lead to huge wins. I've already written quite a few plugins already and I believe with some time investment and the help of community plugins we can have a kickass minification pipeline.

Optimisation plugins

Babel plugins put a lot of potential for optimisations on the table. These optimisations fall into two categories:

Unreliable transformations

These transformations modify JavaScript semantics, they're pretty dangerous and fairly irresponsible. If you're a small devshop or independent developer it's probably way too risky to do this but if you're a largish tech company then you can weigh the risks and it may come out in favor of doing these sorts of transforms. The engine can't infer these kind of changes, you have to tell it that you don't care.

Want to assume all function expressions are constant value types and hoist them? Do it via a plugin.

Want to turn all function expressions that don't use this or arguments into arrow functions? Do it via a plugin. (Arrow functions are currently faster than normal functions in Firefox and likely all other browsers in the future)

Want to manually inline functions, removing the overhead of adding a frame to the call stack, potentially improving perf even if the function has been JIT inlined? Do it via a plugin.

Want to lazy load modules, assuming that the order they're imported doesn't matter as they're side effect free? Do it via a plugin.

You can kinda see how these assumptions can lead to fairly large wins. You just have to decide whether or not it's a good idea to do them.

Reliable transformations

These are transformations that can be done with 100% confidence. These can be performed without possibly breaking any code. With Flow integration and access to the dependency graph a lot of code can be statically inferrable.

But don't engines already do these? Different engines do different things. Some optimisations are too heavy for JITs to do but we have a bit more leeway since we're preprocessing offline. We also potentially have access to more information than engines (type annotations) and so can do some smarter things.

Debugging

Better debugging information will be absolutley necessary as Babel grows in complexity. A particular useful feature for userland would the ability to tell exactly what transforms are breaking or slowing down your build will be critical in this modulrisation.

Performance

5.x performance has improved drastically since 4.x. It could be better though. Performance will never stop being an issue.

If there's one part of Babel that is quite slow due to the overhead of JavaScript, there's the potential to provide two implementations of it. A fast version implemented via a native module that's used in Node and a pure JavaScript one that can be used in the browser. If parts of Babel get implemented as native modules there will always be a pure JavaScript version available.

See issue #1486 for related performance discussion.

Async API

Why?

This will allow an RPC with a long running server such as Flow. This will allow access to a large amount of type info. This will also allow IO to be done.

What about integrations that only allow a synchronous API?

A synchronous API will still be available for those limited integrations. If you attempt to use the synchronous API with plugins that have async visitors then an error will be thrown. Most of the systems that Babel has to integrate with are already async so this shouldn't be a concern for 90% of developers.

Anything else?

Probably forgetting something, I'll add more to this issue as I remember and feedback is collected.


cc everyone

@glenjamin
Copy link

This all sounds ace! it would be cool to bake-in per-plugin perf profiling from the start, so slow plugins can be identified & optimised/disabled.

@MoOx
Copy link
Contributor

MoOx commented Aug 5, 2015

I am sad to see this direction (no more easy transformations by default), probably because I was doing the same with cssnext, but at the same time I totally understand the "Why".
It's nice to see that Babel will more look like PostCSS. These 2 projects didn't start with the same goal but are more and more similar (parsers/transformers).
Your approach looks good to me!

@sebmck
Copy link
Contributor Author

sebmck commented Aug 5, 2015

@MoOx I've thought about how to make it the easiest and the current solution is basically what I landed on. All that will be required to get 5.x behaviour is having the following .babelrc:

{
  "plugins": ["preset-es2015"]
}

(Preset might be called something different but you get the point)

@glenjamin Oh that'd definently be cool.

@brianblakely
Copy link

You shouldn't require extra configuration just to get Babel's bread and butter (ES transpilation). I understand your vision for Babel, and it's great, but please keep it simple for the common use-case.

All the future-future stuff sounds super exciting!

@MoOx
Copy link
Contributor

MoOx commented Aug 5, 2015

@sebmck Yeah that's why said I like the approach. Thanks for your awesome work. Good direction.

@sebmck
Copy link
Contributor Author

sebmck commented Aug 5, 2015

@brianblakely Trying to keep it as simple as possible but keeping any transforms enabled by default isn't very proactive.

@jamiebuilds jamiebuilds added this to the 6.0.0 milestone Aug 5, 2015
@sebmck
Copy link
Contributor Author

sebmck commented Aug 5, 2015

Forgot to mention that I'm also putting a feature freeze on 5.x

@glenjamin
Copy link

You could have a generator/cli as the primary method for installation, so that doing

babel-cli es2015

Would npm install --save-dev babel babel-preset-es2015 and generate the .babelrc

@brianblakely
Copy link

Having a preset for every subsequent version of ES (2015, 2016, etc) could get confusing to manage in a couple years. Perhaps it would be more enabling to relegate that stuff to an "esnext" preset instead, which makes Babel work for users the way it does today. Then you just update the preset on NPM and never need to touch your RC again.

@sebmck
Copy link
Contributor Author

sebmck commented Aug 5, 2015

@brianblakely In the next couple of years people are going to be targetting completely different things depending on their requirements. Having a blanket version doesn't really work, especially when ES versions aren't going to mean anything anymore.

@brianblakely
Copy link

I think the majority are still going to want to work with the latest ES features. Installing language features a la carte or looking up which preset to install is not a great experience for those users or their teams. Babel is just one tool of many, and should strive to be as zero-config as possible.

@sebmck
Copy link
Contributor Author

sebmck commented Aug 5, 2015

Do you not think making Babel much much more powerful is a worthy tradeoff for literally 1 line of config?

@glenjamin
Copy link

I think the majority are still going to want to work with the latest ES features.

I don't believe this is true at all.

The current babel users I would expect are largely made up of early adopters and those who happen to be in the same teams / on the same projects as early adopters.

Using experimental babel features is not dissimilar to using coffee-script, it's a reasonable choice, but not one that the mainstream will definitely latch on to.

@MoOx
Copy link
Contributor

MoOx commented Aug 5, 2015

I was thinking like you @brianblakely (I speak as the creator of "cssnext"), but I have to admit that handling the evolution of specs can be a pain, and can easily become a dangerous game (it's even harder for CSS because specs are exploded as different modules...).

@mathieumg
Copy link
Contributor

I added some gifs

gif* :(

In all seriousness, future looks great! Looking forward to these changes.

@glenjamin
Copy link

As another data-point, another popular JS tool with a large set of configuration options recently switched to off-by-default - and survived.

http://eslint.org/docs/user-guide/migrating-to-1.0.0

@samccone
Copy link
Contributor

samccone commented Aug 5, 2015

Nailed it well done 👍👍👍👍

@MoOx
Copy link
Contributor

MoOx commented Aug 5, 2015

@glenjamin everything off !== everything out ;)

@hzoo
Copy link
Member

hzoo commented Aug 5, 2015

Yeah, JSCS has always had no options set by default; some wanted a certain preset (airbnb) to be default for 2.0.0 but didn't get enough support.

@brianblakely
Copy link

The current babel users I would expect are largely made up of early adopters and those who happen to be in the same teams / on the same projects as early adopters.

In the last year I've been the early adopter teaching ES6 to non-early teams via Babel.

ESLint's "extends": "eslint:recommended" option is a really decent solution. My "preset-esnext" idea was kind of similar--Babel curates/updates a list of new ES language features as time goes on for the benefit of its users. Perhaps a lot to ask, as per @MoOx's comment.

@jamiebuilds
Copy link
Contributor

I want to cut off this discussion about what should be included in Babel by default as it's not been productive so far.

Babel is a compiler. At it's heart it is a system for building transforms that take JavaScript in and spit JavaScript back out, and in between it can run all sorts of really complex operations on JavaScript. Babel has a lot built into it for making this easy.

There are many applications for a compiler: transpiling, minifying, linting, type checking, etc. it's a very useful tool to have in many contexts.

So to assert that it should have some default behavior as the "common use case" is misguided. Yes, transpiling of ES-next features will always be a supported by the Babel team, it's not necessarily the one it will be used for.

Babel is meant for building an ES2015 transpiler (not being one), as well as many other tools. That's the use case Babel is going for and that's why this decision is being made.

@leebyron
Copy link
Contributor

leebyron commented Aug 5, 2015

This sounds like a great direction. I agree with the sentiment of making the common case as easy as possible, but also strongly agree with documenting exactly what transforms a library requires. With the ability to put babel config into package.json, we end up neatly describing important characteristics of the source.

@jamiebuilds
Copy link
Contributor

but also strongly agree with documenting exactly what transforms a library requires. With the ability to put babel config into package.json

This touches on something that I've been wanting to discuss. (Movie trailer voice) In a world where developers put non-compiled code on npm, do we want the ability to compile all of that down in Babel?* In other words, should a module bundler using Babel be able to require files that need different transforms based on the module being loaded?

My understanding is that Browserify can do this via package.json (via the browser and browserify fields) although I'm not sure how it handles loading transforms listed in devDependencies if they don't get installed.

Should .babelrc's be somehow required for distribution?

* Example use case: I wrote my library with a bunch of ES2015 features, rather than compile it forever I'm going to distribute the ES2015 version and have a .babelrc file for people who want to import it with a Babel module loader.

@dashed
Copy link
Contributor

dashed commented Aug 5, 2015

This sounds like it'll play very nice with webpack 2, especially with concord.

/cc @sokra

@jackfranklin
Copy link

Babel is meant for building an ES2015 transpiler (not being one), as well as many other tools. That's the use case Babel is going for and that's why this decision is being made.

+1000 for that, a really succinct way of putting it that explains this new direction. To me this sounds like a fantastic approach and one I'm really looking forward to working with.

@thejameskyle I'd be really interested in being able to publish "raw" code rather than code that's been generated by Babel.

I wrote my library with a bunch of ES2015 features, rather than compile it forever I'm going to distribute the ES2015 version and have a .babelrc file for people who want to import it with a Babel module loader.

Not sure if .babelrc is better than options in a package.json but that's definitely a latter discussion, I'd be really keen to see and explore how this approach might work. Running some Babel task in an npm postinstall kills me a bit inside ;)

Edit: you can use package.json, as @sebmck pointed out. I stand very much corrected :)

@sebmck
Copy link
Contributor Author

sebmck commented Aug 5, 2015

@jackfranklin You can specify your .babelrc file via package.json already which is what I believe @leebyron was referring to.

@hzoo
Copy link
Member

hzoo commented Aug 7, 2015

If you have to specify all the transformers you need then you might as well just specify them without the preset concept at all right?

@dashed
Copy link
Contributor

dashed commented Aug 7, 2015

I'm starting to think the CLI to manage config is the correct approach ....

This approach, babel install <preset>, reminds me of what docpad does: http://docpad.org/docs/plugins

After some digging, the reasons for this seem to stem on npm and peer dependencies: docpad/docpad#927 (comment)


I'm hoping the CLI would still be optional.

@inikulin
Copy link

inikulin commented Aug 7, 2015

@hzoo Nope. At first you will need to npm install all of them, 11 installs vs 1 for my example. Then you will need to jump over the packages to find out documentation for each of them, instead of using one hub package with all the stuff you need.

@hzoo
Copy link
Member

hzoo commented Aug 7, 2015

Oh ok you're saying the preset npm installs all of the transforms but you specify the ones you want

@inikulin
Copy link

inikulin commented Aug 7, 2015

Right. Wasn't it the purpose of the presets and I'm missing something?

@navaru
Copy link

navaru commented Aug 7, 2015

Why don't we use the following naming for packages?

  • require('@babel/core')
  • require('@babel/preset-es2015')
  • require('@babel/plugin-arrow-functions')

It's easier to understand what's official and what's not.

@sebmck
Copy link
Contributor Author

sebmck commented Aug 7, 2015

@teugen That was already bought up by @tgriesser here:

Have you considered using npm's "scoped packages" feature to be able to properly namespace and differentiate "officially" maintained plugins/presets from packages which just happen to begin with babel-?

@navaru
Copy link

navaru commented Aug 7, 2015

@sebmck peerDependencies will be deprecated in npm 3.0, so no point in taking that into consideration.

I would really like to see more use of scoped packages in projects like babel which target a very large audience.

Really like the roadmap, would be a lot easier to get involved in fixing bugs for specific plugins. First time I tried to wrap my head around babel's source was very overwhelming.

@glenjamin
Copy link

peerDependencies will be deprecated in npm 3.0, so no point in taking that into consideration

I'm pretty sure this is no longer the case, peerDeps are staying, but will no longer auto-install, they'll just tell you what to add to your normal dependencies.

@jmm
Copy link
Member

jmm commented Aug 8, 2015

@thejameskyle

My understanding is that Browserify can do this via package.json (via the browser and browserify fields) although I'm not sure how it handles loading transforms listed in devDependencies if they don't get installed.

It doesn't handle that. Per the README:

Make sure to add transforms to your package.json dependencies field.

@jugglinmike

That last concern could be mitigated by responsible plugin
maintainers that backport changes to previous version branches, but despite the
general consensus for the "many small modules" approach, I haven't witnessed
many Node.js developers honoring this contract.

That's a contract?


I don't have a solution to propose right now for presets, but I'm not enthused about a solution that requires a CLI.

@sebmck @thejameskyle Since the subject of presets has so far dominated the discussion here, and there still seems to be a lot more to discuss, do you think it makes sense to try to direct future discussion to #1827?

@abritinthebay
Copy link

As long as the CLI and require hook both stay useful and easy to use I think these changes are all great.

Keeping the code better abstracted for long term use is great but it shouldn't compromise the interface to the code for users.

@navaru
Copy link

navaru commented Aug 18, 2015

I like the idea behind rollup (Next-generation ES6 module bundler), would this be considered going forward?

@stefanpenner
Copy link
Member

peerDependencies will be deprecated in npm 3.0, so no point in taking that into consideration
I'm pretty sure this is no longer the case, peerDeps are staying, but will no longer auto-install, they'll just tell you what to add to your normal dependencies.

correct

@ghost
Copy link

ghost commented Aug 28, 2015

Way to provide the entire dependency graph to Babel

If this is what I think it is, I'm very excited for it. I'd love to be able to have the bundler / module formatters be able to use custom resolution algorithms(i.e. npm, bower, etc) and it sounds like this would enable that?

@ahdinosaur
Copy link

No internal transformers. None. Zero. Zilch.

awesome. 👍 😄

@dead-claudia
Copy link

+1000. I ❤️ it! 👍 😄

@ForbesLindesay
Copy link
Contributor

peerDependencies have never been deprecated, it's always been just a case of the behaviour changing slightly. All it means is that if your plugins peer depend on babel, you will still need to install babel yourself. npm will warn that you are missing the dependency rather than installing it for you.

@sebmck
Copy link
Contributor Author

sebmck commented Oct 11, 2015

Please refrain from 👍 it's hard enough already to filter through the babel/babel repo noise.

@babel babel locked and limited conversation to collaborators Oct 19, 2015
@sebmck sebmck closed this as completed Oct 28, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests