77

I've installed the latest version of babel. Currently 6.4.0. I create a file called myclass.js that has the following code.

class MyClass {
    constructor(name) {
        console.log("I am a MyClass object .. ", name);
    }
}

var myclass = new MyClass('1234');

after creating my class I do the following in the command line.

$> babel ./src/myclass.js --out-file ./out/app.js

I would expect my app.js file to have es5 compiled javascript but it has the same exact code in it that the myclass.js file has. What am I missing that may be causing this?

loganfsmyth
  • 156,129
  • 30
  • 331
  • 251
mattwallace
  • 4,132
  • 6
  • 43
  • 77

3 Answers3

85

You don't tell Babel to target ES5, you choose the necessary presets/plugins that do that for you. For example, if you use the es2015 preset, this will compile ES6 code to ES5-compatible code. You don't specify a "target".

The guide below will take you through using Babel to transform ES6 code into code that can run in an environment that supports ES <= 5.


0. A note on API changes from Babel 5

In the documentation for Babel 6:

The babel package is no more. Previously, it was the entire compiler and all the transforms plus a bunch of CLI tools, but this lead to unnecessarily large downloads and was a bit confusing. Now we’ve split it up into two separate packages: babel-cli and babel-core.

And:

Babel 6 ships without any default transforms, so when you run Babel on a file it will just print it back out to you without changing anything.

______

1. Install babel-cli

First, as in the docs, you need to install babel-cli:

$ npm install babel-cli

______

2. Define presets in .babelrc

Second, you need to use a .babelrc (docs) local to your files and explicitly define the presets that you want Babel to use. For example, for ES6+ features use the env preset.

...a smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms (and optionally, browser polyfills) are needed by your target environment(s).

Install it:

npm install @babel/preset-env

And then declare it in your .babelrc:

{
  "presets": ["@babel/preset-env"]
}

Note: if you are using Babel 7.x you may prefer to use a "project-wide configuration" (babel.config.js) (docs) which "applies broadly, even allowing plugins and presets to easily apply to files in node_modules or in symlinked packages".

______

3. Run babel

Now running the babel command as in your example should work:

$> babel ./src/myclass.js --out-file ./out/app.js

Alternatively, use a bundler like webpack, rollup, or browserify, with their respective babel plugin.

sdgluck
  • 24,894
  • 8
  • 75
  • 90
  • 80
    Though this answer has useful info, it does not answer the question: it does not explain how to compile to ES5. – Koert van Kleef Sep 05 '16 at 14:25
  • @KoertvanKleef In what way? – sdgluck Sep 05 '16 at 14:30
  • 17
    I stand corrected. Apparently the es2015 preset is how you get Babel to produce es5 compatible output. I replied while I was figuring this out. Is it just me or is that naming confusing. ES2015 = ES6 so they created a preset to target ES5 why call it "ES2015"? – Koert van Kleef Sep 05 '16 at 15:01
  • 6
    @KoertvanKleef The presets are what define the available language features, so these are what the names allude to. (How would you/Babel know the application uses ES6 if it said `preset: ES5`?) So `es2015` means you can use ES6 features and they will be transpiled. – sdgluck Sep 05 '16 at 15:05
  • 1
    Clearly I need to do more reading on the subject. So I would use the ES6 preset if my code uses ES6 features, and then use a plugin to target ES5? Is that how Babel knows what compatibility I need? – Koert van Kleef Sep 05 '16 at 15:10
  • 7
    @KoertvanKleef No need to specify targeting ES5; the preset is basically a list of plugins to use, and these all target the ES5 environment automatically. :-) – sdgluck Sep 05 '16 at 15:14
  • 4
    Why is this not accepted as answer ? It was more clear than documentation. Docs never mentioned the .babelrc and preset step. Here https://babeljs.io/docs/usage/cli/ +1. – HalfWebDev Dec 12 '16 at 13:14
  • My guess is that babel doesn't know what constructs you use in your code in advance hence does not support setting a target like ES5 or ES3 (typescript supports that BTW). It's you who has to know which constructs you used in your project, then select the proper preset accordingly. This way, babel will transpile it, to ES5 as it's the implicit target. – Clement JACOB Apr 28 '17 at 12:53
  • 2
    Thank you very much . For compililng a file using babel, --out-file directive and for compilling a directory, -d should be used. – shrawan_lakhe Nov 06 '17 at 16:47
  • @pjkundert Is this answer not working for you? Can you explain what you have done and why that is no sufficient please. – sdgluck Sep 06 '18 at 08:57
  • 2
    @kushalvm agree - the documentation is prolific, but still very confusing as it doesn't explain basic concepts. – Rob Grant Nov 17 '18 at 21:26
10

The exact answer using babel with nodejs (and using CLI):

Install babel and preset

npm install babel-cli babel-preset-es2015

Execute with npx

npx babel  ./src/myclass.js --out-file ./out/app.js --presets babel-preset-es2015

Note

When babel-cli is globally installed could be not working. So this is my definitive solution

3

Babel doesn't usually target (or you don't usually want it to target) a specific standard, instead what it does is targeting the concrete browser versions you passed in somehow - explicitly like "targets": { "chrome": 70} or implicitly in different ways, for example, like "targets": ">0.25%" (market share) - in config files (package.json, .babelrc or babel.config.js). To make it possible, Babel gets the information about browser usage & features support from a number of other projects like browserlist.

Then it transforms your code as down as possible & needed in terms of a set of ECMA features whose emulative implementations are defined by presets (groups of plugins, let's say preset-env). It finally comes to what can be run in the browsers you want your code to be run in.

For example, if you target browsers with market share > 15%, this code - let a = 5; - will stay the same since these popular browsers are highly likely to be the latest versions of Chrome that perfectly support let. On the other hand, if you indicate that you also want support for IE8, let a = 5; becomes var a = 5; since now Babel tries to make your code suitable for IE8 which knows nothing about let. Well, you get the idea.

Also it is important to understand, that Babel isn't a silver bullet - it doesn't add anything beyond ECMAScript spec. For example, it doesn't provide polyfills for browser APIs (fetch etc).

And if you gave no indications, then, as the documentation states:

Sidenote, if no targets are specified, @babel/preset-env will transform all ECMAScript 2015+ code by default. We don't recommend using preset-env this way because it doesn't take advantage of its ability to target specific browsers.

curveball
  • 4,320
  • 15
  • 39
  • 49