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 19 commits
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
183 changes: 183 additions & 0 deletions _posts/2016-08-26-babili.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
---
layout: post
title: "Releasing Babili (beta)"
author: Henry Zhu
date: 2016-08-29 09:30:00
categories: announcements
share_text: "Releasing Babili (beta)"
---

# Babili (babel-minify)

We released [Babili](https://github.com/babel/babili) as beta (0.0.1) a few days ago under an MIT license!

There are a lot of (valid) questions about why a new minifier is a good idea, so this post should help with that.

> There's also a [#minify](https://babeljs.slack.com/messages/minify/) slack room!

TL;DR: Babili can accept ES2015+ input, while current minifiers are mostly limited to ES5, requiring code to be transpiled before minification. This is becoming unwanted as people begin to ship ES6 to clients. Babili is also modular/flexible (it is a [Babel preset](http://babeljs.io/docs/plugins/#presets) and thus supports user plugins) and can be used as a preset or cli tool. Babili should also be able to do ES2015+ specific optimizations.
Copy link
Contributor

Choose a reason for hiding this comment

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

cli to CLI


## Pronunciation

```bash
# sounds like "bah billy"
say Babili
Copy link
Contributor

Choose a reason for hiding this comment

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

```

> If you can't remember the name, babel-minify works too.

## Why minify?

At a basic level, [minification](https://en.wikipedia.org/wiki/Minification_(programming)) removes unnecessary characters from a program without changing its functionality -- things like comments, whitespace, newlines, and extra parentheses. Advanced minification may transform programs into smaller equivalents and remove redundant/unreachable code.

Minification is primarily useful for decreasing the size of the Javascript payload sent from the server to the client: users will download less code to use your website. Advanced minification can also result in shorter parse time (less code to parse) and in some cases faster runtime (e.g. advanced optimizations like function inlining).
Copy link
Member

Choose a reason for hiding this comment

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

s/Javascript/JavaScript/ 😄


## Current minifiers

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

We currently use tools like Babel to compile ES2015 code down to ES5 code to support older browsers. Then we use something like Uglify to cut down on the bundle size.

As browsers implement more ES2015 features and we drop support for older browser versions, there is a sliding window of the version of ECMAScript you write in and the target ECMAScript version you minify to. However since Uglify cannot parse ES2015+, you would still have to compile down to ES5 anyway.

## Babili

That's where Babili comes in.

Babili is ES2015+ aware because it is built using the Babel toolchain.
It is written as a set of babel plugins, consumable with the [`babili` preset](https://github.com/babel/babili/tree/master/packages/babel-preset-babili).
Copy link
Contributor

Choose a reason for hiding this comment

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

Babel


Babel was originally a specific transpiler for ES2016 to ES5 (called [6to5](http://babeljs.io/blog/2015/02/15/not-born-to-die)). Babili is an example of the many kinds of projects that Babel that help with.
Copy link
Member

Choose a reason for hiding this comment

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

second sentence ... ???

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok just going to remove that


## Example

Say we're targeting the latest versions of Chrome, Firefox and Safari -- all of which support [ES2015 classes](http://babeljs.io/docs/learn-es2015/#classes). Then, compiling ES2015 classes to a constructor function and prototype methods (ES5) results in more code (and potentially loses any optimizations browsers might have for classes).

```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.

```js
// ES2015 code -> Babel -> Uglify/Babili -> Minified ES5 Code
var a=function a(b){_classCallCheck(this,a),this.program=b};a();
```

With Babili, you can just run the minifier which works on ES2015 code.

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

Also it's important to note that this isn't specific to ES2015. 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.
Copy link
Member

Choose a reason for hiding this comment

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

👍


In the future, we might make use of the ES2015+ syntax information we have at compile time (e.g. we know that given function is an arrow function or that a given binding is block-scoped etc) to do advanced optimizations. And we can make use of the knowledge that we're targeting an ES2015+ environment in creative ways. We're just getting started so let us know if you have any ideas!

## Usage

### Babel Preset

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.

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"]
}
}
}
```

### Babili CLI

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). You could run this after transpiling (or not) in place of Uglify.
Copy link
Contributor

Choose a reason for hiding this comment

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

CLI


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

```bash
# equivalent to
# babel src -d lib --presets=babili --no-babelrc
$ 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

```

### Webpack

You can either just use the preset option above with `babel-loader`, or use it seperately with the [babili-webpack-plugin](https://github.com/boopathi/babili-webpack-plugin) (made by [@boopathi](https://github.com/boopathi/), who also works on babili).
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.

Using it with babel-loader will only minify the body of the modules loaded with babel-loader, but not any of the files loaded or generated by webpack, e.g. the bootstrap, the module wrapping function, or css modules exports.

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.

A more reasonable approach, IIUC, would be to transpile down to es2015 with babel-loader, let webpack bundle es2015, as acorn understands it, and then use (a modified version of?) babili-webpack-plugin to minify the entire bundle at the once (and transpile down to es5 in the same step should you need to).

Copy link
Member

Choose a reason for hiding this comment

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

Will the babili-webpack-plugin be moved into core? Like the babel-loader?

Copy link
Member

@boopathi boopathi Aug 29, 2016

Choose a reason for hiding this comment

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

The current build sequence is transpile -> bundle -> minify ... As we don't traverse through Objects and its properties, I think there will not be much optimizations on the bundler generated code (modules[moduleId].call()) other than mangling and whitespace/comments removal. It can be made (transpile + minify) -> bundle if the bundler already produces mangled and has an option to output minified (just the syntax and comments) code. So I was thinking in terms of,

  1. transpile + minify (mangle=false)
  2. bundle - remove dead code inter module level (tree-shaking?)
  3. transform(bundledcode, {minified: true, compact: true, comments: false, plugins: ["mangle"]}) as the last step after bundling.

So, I'm not sure if such a webpack plugin should be the optimal way to use babili. I used it for testing and just polished and published so others can try babili in the current toolchain quick. If this turns out to be a good way to use babili, we can move it to babel org, maybe?

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.

Because of the way webpack does tree-shaking (by just removing the exporting, but leaving the declaration there), the tree-shaking step has to run before minify, or at least before DCE.

I wonder how "complete" the support it; e.g. would it know enough to mark exp from 'module' in import { exp } from 'module'; if (false) { exp(); } as unused? This might require DCE both before and after tree-shaking.

Copy link
Member

@boopathi boopathi Aug 29, 2016

Choose a reason for hiding this comment

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

Probably will be moved to webpack.optimize. webpack-contrib/babel-minify-webpack-plugin#1 - we can discuss in that repo instead.


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

```js
// webpack.config.js
const BabiliPlugin = require("babili-webpack-plugin");
module.exports = {
entry: //...,
output: //...,
plugins: [
new BabiliPlugin(options)
]
}
```

We want to have a better story with integration with webpack/bundlers in the near future! Ref [#100](https://github.com/babel/babili/issues/100).

## Pros/Cons

Uglify Pros
- No change to existing tooling if you are already minifying.
- Battle-tested/production ready (been around for years, and has wide adoption so there's less bugs/issues).
- It's fast and outputs small code already.

Uglify Cons
- Custom parser/tooling, so difficult to output/minify ES2015+ and more.
- Not modular, no way to create own plugins/minification strategies.

Babili Pros:
- ES2015+ aware (nothing special needs to be done because we can use the babylon parser) and Babel will update as standards/browsers update.
- Uses the existing Babel toolchain, can consume as a Babel preset or standalone.
- Potential for custom smart transforms for React/Flow, etc.
- Could use flow/typescript annotations to help with minification.
Copy link
Contributor

Choose a reason for hiding this comment

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

Does Babel now support TypeScript annotation parsing like it does Flow or is this referring to something else?

Copy link
Member Author

Choose a reason for hiding this comment

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

It doesn't, yeah I guess it should just say flow or just "type annotations"

Copy link
Contributor

Choose a reason for hiding this comment

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

"Flow/Typescript"

- Each minification step can be split into its own plugin, and there’s plenty of options for customization. This makes it easier to contribute and to find/submit issues for specific problems. It also means that people can independently create their own experimental plugins before upstreaming them into core.
- For example: [this](https://github.com/babel/babili/tree/master/packages/babel-plugin-transform-minify-booleans) just turns `true` into `!0` which is straightforward to write.
- Should be an easy transition if people are familiar with transpiling with Babel already.

Babili Cons:
- We released it early, so there aren't many users yet. Early adopters will have to deal with a tool that isn't as battle-tested as Uglify at first.
- Right now, the performance is worse/size is worse than Uglify on our benchmark tests. However, this is something we'll be focusing on improving.

TL;DR: Babili should be able to keep up with the ECMAScript standard as new features get added as well as target the environments you need to support. It has a lot of potential: it may not be as production-ready as Uglify at the moment since it was just released but as we continue to optimize with more users it should be more than capable.

## How to Help

[Amjad](https://twitter.com/amasad) had been working on this project for a while but we decided to release it earlier as a beta to allow the community to test it out and both contribute through reporting bugs and patches.

It's still early days for this project so there's a lot to help out with.

- Documentation: Explanations of each plugin
- Testing on more codebases: This will help everyone greatly. Because a minifier runs on all code it has potential for a lot of edge cases/bugs not covered in our basic unit tests. Hopefully we can setup a way to report issues easily; now that the [repl](babeljs.io/repl/) supports the minifier it should be easier to reproduce/link bugs. In the future we will want to be able to specify specific plugins so we can pinpoint minimal reproduction steps.
- Project infrastructure/maintenance: We want to create more robust benchmarking, setup integration tests on popular open source projects (run the minifier, and then run all the project's unit tests).
- Check the output: If something can be more simplified, it should be straightforward to create an issue and suggest a new transformation to an existing plugin or create a new one. We have the benefit of being modular so anyone can also make their own plugins and then we can figure out whether to include them in the core preset.

Huge thanks to [Amjad (@amasad)](https://github.com/amasad) for starting this project and Facebook for allowing us to release this under the Babel organization as an MIT licensed project! [Sebastian (@kittens)](https://github.com/kittens) was obviously a big part of this given this wouldn't have been possible without Babel. Also thanks to [James @thejameskyle](https://github.com/thejameskyle), [Juriy (@kangax)](https://github.com/kangax) for helping see this through to release! Also want give a shoutout to [Boopathi (@boopathi)](https://github.com/boopathi) who we invited to help us out after seeing the work on his own [babel-minify](https://github.com/boopathi/babel-minify) project!