Skip to content

Transpilation

This lesson explains Transpilation with clear examples, use cases, and best practices so you can use modern JavaScript confidently in real projects.

ES6+ Transpilation Overview

Transpilation is the process of converting modern JavaScript into older JavaScript that more browsers can understand. It lets developers write ES6+ syntax such as arrow functions, classes, modules, and async/await while still supporting older runtime environments.

Transpilers such as Babel do not usually change what your code does. They rewrite syntax into an equivalent older form. This is different from polyfills, which add missing runtime features such as Promise or Array.prototype.includes().

Feature Description
Process Name Transpilation
Popular Tool Babel
Input Modern JavaScript (ES6+)
Output Older compatible JavaScript
Common Preset @babel/preset-env
Common Uses Browser support, legacy apps, library publishing

Basic Transpilation Example

// Modern source code

const greet = (name) => {
  return `Hello, ${name}!`;
};

console.log(greet("Alex"));
// Transpiled output (simplified)

var greet = function greet(name) {
  return "Hello, " + name + "!";
};

console.log(greet("Alex"));

An arrow function with a template literal can be rewritten into a standard function and string concatenation. The behavior stays the same, but the output works in older browsers.

How Transpilation Works

A transpiler reads your source code, converts it into an abstract syntax tree, applies plugins and presets, and then generates new JavaScript code. Build tools such as Vite, Webpack, and Rollup often run Babel automatically during development and production builds.

Step Description Example
Write Modern Code Use ES6+ syntax in source files. const total = items.map(...)
Configure Babel Choose presets and target browsers. @babel/preset-env
Run Transpiler Convert source to compatible output. npx babel src --out-dir dist
Add Polyfills Fill missing runtime APIs if needed. core-js
Bundle App Ship final JavaScript to browsers. vite build
Test Targets Verify support in required browsers. browserslist

Transpilation vs Polyfills

Feature Transpilation Polyfill
What It Changes Syntax in your source code. Missing runtime APIs.
Example Input const x = () => 1; Promise, fetch()
Example Output var x = function() { return 1; }; Shim implementation added at runtime
Best For Arrow functions, classes, modules. New built-in methods and globals.

Basic Babel Configuration

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

Babel presets group common transformation rules. @babel/preset-env is the most common choice because it converts modern syntax based on your target browsers.

Target Browsers with Browserslist

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "browsers": [
            "last 2 versions",
            "not dead"
          ]
        }
      }
    ]
  ]
}
# .browserslistrc

last 2 versions
not dead
> 0.5%
IE 11

Browserslist tells Babel which browsers you support. Babel then transpiles only the features those browsers cannot run natively.

Transpile a Class Example

// Source

class User {
  constructor(name) {
    this.name = name;
  }

  greet() {
    return `Hi, ${this.name}`;
  }
}

const user = new User("Alex");
console.log(user.greet());
// Transpiled output (simplified)

function User(name) {
  this.name = name;
}

User.prototype.greet = function greet() {
  return "Hi, " + this.name;
};

var user = new User("Alex");
console.log(user.greet());

ES6 classes are syntactic sugar over constructor functions and prototypes. Babel rewrites them for environments without native class support.

Transpile async/await

// Source

async function loadUsers() {
  const response = await fetch("/api/users");
  return response.json();
}

loadUsers()
  .then((users) => console.log(users))
  .catch((error) => console.error(error));
// Transpiled output (simplified)

function loadUsers() {
  return _asyncToGenerator(function* () {
    const response = yield fetch("/api/users");
    return response.json();
  })();
}

async/await is converted into generator-based helper code or Promise chains. This often requires both transpilation and a Promise polyfill for very old browsers.

Add Polyfills with preset-env

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": "defaults",
        "useBuiltIns": "usage",
        "corejs": 3
      }
    ]
  ]
}
// Source

const total =
  [1, 2, 3].includes(2);

console.log(total);

With useBuiltIns: "usage", Babel can inject only the polyfills your code actually needs, such as Array.prototype.includes(), instead of loading all of core-js.

Use Babel in a Build Pipeline

project/
  src/
    app.js
  dist/
    app.js
  babel.config.json
  package.json
{
  "scripts": {
    "build": "babel src --out-dir dist"
  },
  "devDependencies": {
    "@babel/cli": "^7.0.0",
    "@babel/core": "^7.0.0",
    "@babel/preset-env": "^7.0.0"
  }
}

Many modern projects do not run Babel manually because tools like Vite, Webpack, and Create React App integrate it into the build process automatically.

Common Transpilation Tools

Tool Role Common Use
Babel Main JavaScript transpiler. ES6+ to older JavaScript.
@babel/preset-env Smart preset based on browser targets. Production app builds.
core-js Polyfill library for missing APIs. Legacy browser support.
TypeScript Compiles TS and can downlevel JS output. Typed codebases.
Vite / Webpack Run Babel during bundling. Modern frontend workflows.

Common Transpilation Use Cases

  • Supporting older browsers while writing modern JavaScript.
  • Using ES modules, classes, and async/await in legacy projects.
  • Publishing libraries that must work across many environments.
  • Standardizing syntax across teams and codebases.
  • Preparing code for production bundlers and minifiers.
  • Gradually upgrading old JavaScript applications to ES6+.

Transpilation Best Practices

  • Define browser targets clearly with Browserslist.
  • Use @babel/preset-env instead of transpiling everything manually.
  • Separate syntax transpilation from runtime polyfills in your mental model.
  • Prefer useBuiltIns: "usage" to avoid unnecessary polyfills.
  • Test output in your minimum supported browser, not only modern Chrome.
  • Let your bundler handle Babel during build when possible.
  • Keep source code modern and readable; do not write for the transpiled output.

Common Transpilation Mistakes

  • Assuming transpilation alone fixes all browser compatibility issues.
  • Forgetting polyfills for missing runtime APIs.
  • Transpiling to ES5 when your target browsers support modern syntax.
  • Shipping huge polyfill bundles without checking actual usage.
  • Not defining browser targets and over-transpiling by default.
  • Debugging transpiled output instead of readable source code.
  • Confusing TypeScript compilation with JavaScript polyfilling.

When Transpilation Is Less Needed

Scenario Why Transpilation May Be Minimal
Modern browser-only apps Latest Chrome, Firefox, Safari, and Edge support most ES6+ features.
Node.js backends Recent Node versions support modern syntax natively.
Internal tools Controlled environments reduce legacy support needs.
Framework defaults Build tools may already optimize targets for you.

Key Takeaways

  • Transpilation converts modern JavaScript syntax into older compatible syntax.
  • Babel is the most common transpiler in the ES6+ ecosystem.
  • @babel/preset-env and Browserslist control what gets transformed.
  • Polyfills are still needed for missing runtime APIs in old browsers.
  • Write modern source code, configure targets carefully, and test real browser support.

Pro Tip

Think of transpilation as syntax conversion and polyfills as runtime patching. Most real-world ES6+ projects need both, but only for the browsers and features they actually support.