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

babili #898

Merged
merged 28 commits into from
Aug 30, 2016
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions _posts/2016-08-26-babili.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
layout: post
title: "Releasing Babili (beta)"
author: Henry Zhu
date: 2016-08-26 09:30:00
categories: announcements
share_text: "Releasing Babili (beta)"
---

Babili (babel-minify)

We released [babili](https://github.com/babel/babili) yesterday! (under an MIT license)

There seem to be a lot of (valid) questions about why a new minifier is necessary so we want to write a post about some reasons and the future.

## Why minify?

## Issues with current minifiers

Tools such as [uglify](https://github.com/mishoo/UglifyJS2) don't currently support targeting the latest version of Javascript ([yet](https://github.com/mishoo/UglifyJS2/issues/448)).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uglify -> Uglify

Copy link
Contributor

@mathiasbynens mathiasbynens Aug 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/Javascript/JavaScript/ (or maybe it should say ECMAScript?)


We currently to use tools like Babel to compile ES6 code down to ES5 code to support older browsers. Then we use something like uglify to minify our code to cut down on the bundle size.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra " to "?


However as browsers implement more ES6 features and we drop support for older browser versions, there will be a point where you wouldn't have to compile ES6 code to ES5 because all the support targets already understand ES6. However b ecause uglify cannot parse ES6, you would still have to compile down to ES5 anyway.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😱 I had no idea!

I think that saying "there will be a point where you wouldn't have to compile ES6 code to ES5" should maybe be left out for two reasons:

  1. It's a little presumptuous since the community seems content to use transpilers to get the latest and greatest
  2. Since babel6 babel can use plugins to do all kinds of things and it will be good to keep it in the toolchain.

Re: the uglify bit - that needs to be an h1 at the top of the page in big bold block letters. I had no clue and that would have been pretty annoying to find out on my own.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change the wording but i'm talking specifically about ES6 - I'm not saying you wouldn't use babel anymore since you'll need it for jsx/flow/experimental stuff/whatever the browser doesn't support. I'm just saying we can change the target output to be es5, es6, etc


## Babili

That's where Babili comes in.

Babili is ES6+ aware because it is built using the Babel toolchain. More specifically, it is a set of babel plugins + a preset just like with the `es2015` preset.

Like described in [Not Born to Die](http://babeljs.io/blog/2015/02/15/not-born-to-die) when Babel was renamed from 6to5, Babel was originally a specific transpiler for ES6 to ES5. A transpiler is just a compiler. The same techniques work to compile ES6 as it is to minify javascript.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"As Described in"


## Example

When it's possible to only target browsers that support newer ES features, code sizes can be smaller because you don't have to transpile and then minify.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already bing down for server builds (SSR of React for example) a lot of people use things like babel-preset-es2015-node4. Would be cool to mention that some of thes features could make SSR faster.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This point has been covered making this sentence feel redundant. Maybe merge with the next sentence and say:

Say we're targeting the latest versions of Chrome, Firefox and Safari -- all of which support ES2015 classes. Then, compiling ES2015 classes to a constructor function and prototype methods (ES5) will result in more code (and potentially lose any optimizations browsers might have for classes).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 but s/will result in/results in/ (http://blog.stoyanstefanov.com/technical-writing-checklist/)


For example: say we want to minify a file that contains a ES6 class and we want to target the latest version of the chrome.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/contains a ES6/contains an ES6
s/of the chrome/of Chrome

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow so embarassing haha.. need spellcheck

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you win all the internets.


```js
class Mangler {
constructor(program) {
this.program = program;
}
}
// need this since otherwise Mangler isn't used
new Mangler();
```

Before, we might run Babel to transpile [the class into a function](http://babeljs.io/docs/plugins/transform-es2015-classes) and run uglify on the compiled code to send to the browser.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/uglify/Uglify/g


```js
// ES6 code -> Babel -> Uglify -> Minified ES5 Code
var Mangler=function a(b){_classCallCheck(this,a),this.program=b};Mangler();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example doesn't seem quite fair because it seems like Uglify here left in Mangler because it assumed it was a global, whereas we assume files are modules.

Copy link
Member

@Jessidhia Jessidhia Aug 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's even less fair if you don't actually instantiate (new Mangler()) but have a class member other than the constructor. Uglify will still leave the class definition because the transform converts the class into an IIFE, and uglify can't remove reachable code, even if it's a pure function with unused result.

It seems babili can't properly remove class definitions that have a superclass (class X extends Y {} is left alone. Adding a var Y will leave the var around).

Copy link
Member

@Jessidhia Jessidhia Aug 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class X {
  y () {}
}

Babili, as long as it can see the code before es2015-classes runs, can eliminate it; but Uglify (with preset es2015's output) has to preserve it. Wrapping the code given to uglify in an IIFE (as would effectively be done by a bundler) to make it non-global does let uglify also mangle the var and the babel helper names, but that's about it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tangentially related: why is the _createClass helper a var instead of a function? Wouldn't function minify better?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed with @loganfsmyth let's wrap in an IIFE for proper comparison

Copy link
Member Author

@hzoo hzoo Aug 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah a bad example (I didn't really think about it) - I just wanted to show an example with minifying es6 vs transpiling + minify

Copy link
Member Author

@hzoo hzoo Aug 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used Babili to do the minification ^ btw

I'm just going to use a different example without these issues?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Example ES2015 Code
const { op: a, lhs: { op: b }, rhs: c } = getASTNode();

Before

// ES2015+ code -> Babel -> Babili/Uglify -> Minified ES5 Code
;var _getASTNode=getASTNode(),a=_getASTNode.op,b=_getASTNode.lhs.op,c=_getASTNode.rhs;

After

// ES2015+ code -> Babili -> Minified ES2015+ Code
const{op:a,lhs:{op:b},rhs:c}=getASTNode();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can include any example from es2015 code golf - http://codegolf.stackexchange.com/questions/37624/tips-for-golfing-in-ecmascript-6

```

With the babel minifier, you can just run the minifier which will work on ES6 code.

```js
// ES6 code -> Babili -> Minified ES6 Code
class a{constructor(b){this.program=b}}new a;
```

Also it's important to note that this isn't specific to ES6. Because Babel updates as ECMAScript updates (with [ES2015, ES2016, and now ES2017](http://babeljs.io/docs/plugins/#official-presets)) and follows the proposal process for experimental features (with our [stage-x presets](http://babeljs.io/docs/plugins/#stage-x-experimental-presets)), the minifier should be able to output whatever version of ECMAScript that is supported.

## Usage

If you already use Babel, you can just add the [babili](https://github.com/babel/babili#babel-preset) preset (babel-preset-babili) to your config.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth noting that most people use Babel with Webpack + browserify which will run it over your owned files and not the final bundle. If you use it this way and simply add it to your .babelrc (in place of Uglify) you COULD see an increase in bundle size since you won't be running minification over vendor files.


You probably want to enable this only in production, so use the [env option](http://babeljs.io/docs/usage/babelrc/#env-option) which uses either `process.env.BABEL_ENV` or `process.env.NODE_ENV`

```bash
$ npm install babel-preset-babili --save-dev
```

```js
// previous .babelrc
{ "presets": ["es2015"] }
// .babelrc
{
"presets": ["es2015"],
"env": {
"production": {
"presets": ["babili"]
}
}
}
```

If you don't use Babel, you can use our standalone cli tool [`babili`](https://github.com/babel/babili#cli). (Currently it's just a wrapper for babel-cli + the preset)

```bash
$ npm install babili --save-dev
```

```bash
# equivalent to
# babel src -d lib --presets=babili
$ babili src -d lib
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just looked at this since I was curious. Do we want this to also pass in --no-babelrc? It seems potentially surprising that this would also attempt to use whatever .babelrc was in this folder.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed with @loganfsmyth; this surprised/confused me when I first tried babili.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point, we can certainly change that

```