npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

babel-preset-modules

v0.0.2

Published

nothing to see here

Readme

babel-preset-modules

A carefully crafted Babel preset that targets browsers with ES Modules support.

Use this instead of @babel/preset-env's target.esmodules option for smaller bundle size and improved startup performance.

Features Supported

  • JSX uses native Object Spread properties for JSX spread attributes instead of a helper.
  • Default, destructured and optional parameters are all natively supported.
  • Tagged Templates are fully supported, patched for Safari 10+ and Edge 16+.

How?

@babel/preset-env is great, since it lets you define which Babel features are needed based on a browser support target. However, in order to make that plumbing work the preset has to group all of the possible JavaScript syntax features you might be using into fairly large groups. It enables or disables these groups based on the browser support target you specify, including targets.esmodules which is effectively an alias for the set of browsers that support ES Modules.

The problem is that one browser that supports ES Modules can spoil a whole set of features, since they're all grouped together. For example, all of the new syntax features relating to function parameters are grouped into the same Babel plugin (@babel/plugin-transform-function-parameters). That means because Edge 16 & 17 support ES Modules but have a bug related to parsing shorthand destructured parameters with default values within arrow functions, all functions get compiled from the new compact argument syntaxes down to ES5:

// this breaks in Edge 16:
const foo = ({ a = 1 }) => {};

// .. but this doesn't:
function foo({ a = 1, b }, ...args) {}

// ... and neither does this:
const foo = ({ a: a = 1 }) => {};

In fact, there are 23 syntax improvements for function parameters in ES2017, and only one of them is broken in ES Modules-supporting browsers. It seems like a shame to transpile all those great features down to ES5 just for Edge 16, right? I thought so.

This plugin takes a different approach than we've historically taken with JavaScript: it transpiles the broken syntax to the closest non-broken modern syntax. In the above case, here's what is generated to fix all ES Modules-supporting browsers:

input:

const foo = ({ a = 1 }, b = 2, ...args) => [a,b,args];

output:

const foo = ({ a: a = 1 }, b = 2, ...args) => [a,b,args];

That output works in all ES Modules-supporting browsers, and is only 59 bytes minified & gzipped.

Compare this to @babel/preset-env's targets.esmodules output for the above, at 147 bytes minified & gzipped:

const foo = function foo(_ref, b) {
 let { a = 1 } = _ref;

 if (b === void 0) { b = 2; }

 for (
   var _len = arguments.length,
     args = new Array(_len > 2 ? _len - 2 : 0),
     _key = 2;  _key < _len; _key++
 ) {
   args[_key - 2] = arguments[_key];
 }

 return [a, b, args];
};

The result is dramatically improved bundle size and performance, while supporting the same browsers. All from removing grouping.

Example Usage

{
  "env": {
    "modern": {
      "presets": ["babel-preset-modules"]
    },
    "legacy": {
      "presets": {
        ["@babel/preset-env", {
          "targets": {
            "browsers": ">1%, not dead"
          }
        }]
      }
    }
  }
}

Important: Minification

The output generated by this preset includes workarounds for Safari 10, however minifiers like Terser sometimes remove these workarounds. In order to avoid shipping broken code, it's important to tell Terser to preserve the workarounds, which can be done via the safari10 option. It's also generally the case that minifiers are configured to output ES5 by default, so you'll want to change the output syntax to ES2017.

With Terser Node API:

terser.minify({
  ecma: 8,
  safari10: true
})

With Terser CLI:

terser --ecma 8 --safari10 ...

With terser-webpack-plugin:

module.exports = {
  minifier: [
    new TerserPlugin({
      terserOptions: {
        ecma: 8,
        safari10: true
      }
    })
  ]
};

All of the above configurations apply work for uglify-es. UglifyJS (2.x and prior) does not support modern JavaScript, so it cannot be used in conjuction with this preset.

Bundle Size Comparison

Bundling an unmodified copy of the redux-todos codebase.

| Babel Preset / Configuration | Gzipped Bundle Size |-|-| | babel-preset-modules | 4.07kB | @babel/preset-env target.esmodules | 4.75kB | @babel/preset-env (default) | 5.33kB

The code is small because no dependencies are bundled, but imagine how this scales up. For an app is 10x this size, would you rather ship 40kB of JS, or 53kB?