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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ololoepepe/babel-preset-default

v0.3.0

Published

Default Babel preset

Downloads

117

Readme

@ololoepepe/babel-preset-default

A default, browser-first (but universal) Babel preset built on @babel/preset-env plus a small, curated set of proposal plugins. It targets Babel 8 and is shipped as an ES module.

The preset deliberately sets no targets — it stays target-agnostic so every consumer controls its own output via their own browserslist.

It also polyfills modern built-ins — .at(), .toSorted(), Object.hasOwn(), Object.groupBy() and friends — with pure imports from core-js-pure, but only when you opt in by installing it. See Polyfills.

Configure browserslist. With polyfills enabled the browser/engine targets stop being a down-levelling detail and start deciding which polyfills get injected into your bundle. See Targets / browserslist.

Requirements

  • Node.js ≥ 20 (Babel 8 requirement).
  • Babel 8@babel/core@^8.

Installation

npm install --save-dev @ololoepepe/babel-preset-default

Peer dependencies

npm install --save-dev @babel/core@^8
npm install @babel/runtime@^8
  • @babel/core — required by @babel/preset-env and every included plugin.
  • @babel/runtime@babel/plugin-transform-runtime rewrites Babel's inline helpers into imports from @babel/runtime, so the output your build produces depends on it at runtime. Install it as a regular dependency of the project being compiled.

Two more peers are optional — they enable and back the polyfill layer, and are declared peerDependenciesMeta.optional so npm never installs them behind your back:

npm install core-js-pure@^3 @babel/runtime-corejs3@^8
  • core-js-pure — the polyfill implementations the compiled output imports. Installing it is what switches polyfilling on; leaving it out is what keeps a Node-only package free of ballast.
  • @babel/runtime-corejs3 — required together with core-js-pure, not instead of it: once the polyfill plugin is active, @babel/plugin-transform-runtime sources its helpers from @babel/runtime-corejs3 rather than @babel/runtime. Both are regular dependencies of the project being compiled.

Usage

Reference the preset by name in your Babel configuration.

babel.config.js:

export default {
  presets: ['@ololoepepe/babel-preset-default']
};

or .babelrc / babel.config.json:

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

ESM note: this package is an ES module ("type": "module"). Babel loads presets asynchronously in bundlers and @babel/cli, so ESM presets work out of the box there. Some tools that resolve Babel config synchronously (for example, certain babel-jest setups) cannot load an ESM preset directly — in those cases load your Babel config through an async path, or wrap the preset in a small config that your tool can consume.

What's included

The preset runs the following plugins (in order) and then @babel/preset-env:

| Piece | What it does | | --- | --- | | @babel/plugin-proposal-decorators (version: '2023-11') | Decorators per the 2023-11 standard. Class fields are handled by preset-env. | | @babel/plugin-proposal-export-default-from | export def from './mod'; re-export syntax. | | @babel/plugin-proposal-pipeline-operator (proposal: 'hack', topicToken: '%') | The Hack-style pipeline operator |> with % as the topic token. | | @babel/plugin-proposal-do-expressions | do { ... } expressions. | | babel-plugin-polyfill-corejs3 (method: 'usage-pure') | Rewrites built-ins your targets lack — .at(), .toSorted(), Object.hasOwn(), … — into pure core-js-pure imports. Only added when polyfilling is enabled; see Polyfills. | | @babel/plugin-transform-runtime | Deduplicates Babel's helpers by importing them from @babel/runtime — or from @babel/runtime-corejs3 when the polyfill plugin above is active (hence the peer dependencies). | | babel-plugin-add-module-exports | CJS interop: exposes a lone default export as module.exports so CommonJS consumers can require('mod') instead of require('mod').default. | | @babel/preset-env | Compiles modern ECMAScript (including now-standard proposals such as optional chaining, nullish coalescing, class fields, logical assignment, etc.) down to the consumer's targets. Configured with no targets. |

Syntax examples for the kept proposals:

// decorators (2023-11)
@logged
class Service {
  @bound handle() {}
}

// export-default-from
export def from './service.js';

// pipeline-operator (hack style, % topic)
const result = value |> double(%) |> increment(%);

// do-expressions
const label = do {
  if (ok) { 'yes'; } else { 'no'; }
};

Polyfills

@babel/preset-env compiles syntax. It does not touch built-ins: [1, 2, 3].at(-1) and array.toSorted() survive compilation untouched and then throw on any engine that lacks them. This preset closes that gap with babel-plugin-polyfill-corejs3 in usage-pure mode, so a source file like

export const last = [1, 2, 3].at(-1);
export const sorted = [3, 1, 2].toSorted();

compiles (for targets that need it) to

import _atInstanceProperty from 'core-js-pure/features/instance/at.js';
import _toSortedInstanceProperty from 'core-js-pure/features/instance/to-sorted.js';

export const last = _atInstanceProperty(_ctx = [1, 2, 3]).call(_ctx, -1);
export const sorted = _toSortedInstanceProperty(_ctx2 = [3, 1, 2]).call(_ctx2);

Pure, not global: nothing is monkey-patched onto Array.prototype, so the output is safe to publish as a library. Only the built-ins you actually use are imported, and only when your targets lack them.

Switching it on and off

Polyfilling follows the presence of core-js-pure. The preset resolves core-js-pure/package.json at config time:

  • resolved → the plugin is added, pinned to that exact installed version.
  • not resolved → the plugin is not added at all. A Node-only package that never installs core-js-pure therefore carries no polyfill machinery whatsoever.

The version is read rather than hard-coded on purpose: babel-plugin-polyfill-corejs3 needs to know which modules exist in the core-js-pure you have, and a hard-coded number drifts out of sync the moment you upgrade — producing imports of modules that aren't there.

To disable polyfilling explicitly even though core-js-pure is installed (it may be present as some other package's transitive dependency), pass corejs: false:

export default {
  presets: [['@ololoepepe/babel-preset-default', {corejs: false}]]
};

Options

| Option | Type | Default | Meaning | | --- | --- | --- | --- | | corejs | boolean \| string \| {version?: string, proposals?: boolean} | true | true — auto-detect the installed core-js-pure. false — no polyfilling. A version string ('3.49.0') — force that version, e.g. when a strict package manager keeps core-js-pure out of the preset's resolution path. An object — the same, with control over proposals. |

Why proposals: true

The preset enables proposals by default, and this is not about running bleeding-edge proposals. core-js files a number of long-standard methods under esnext.*, and .at() is the notable one: in pure mode it resolves through esnext.string.at, which proposals: false filters out as "not stable". The practical effect of turning proposals off is that .at() is silently left unpolyfilled — no error, no warning, just a TypeError on an old engine at runtime.

The flip side is that esnext.string.at carries no compatibility data, so it counts as missing everywhere: .at() is polyfilled even on targets that support it natively. That is one tiny module, and it is the trade the preset takes. corejs: {proposals: false} is there if you want the other one.

Targets / browserslist

Because the preset sets no targets, the actual output is decided by the consumer's environment:

  • Under a bundler / caller that supports ESM, preset-env's default modules: 'auto' keeps ES modules; under Node's CommonJS resolution it emits CommonJS.
  • To control down-leveling, add your own browserslist config (a browserslist key in package.json, a .browserslistrc, or targets in your Babel config). preset-env picks it up automatically.

With polyfills enabled, configuring browserslist stops being optional in practice. The targets no longer merely decide how much syntax gets down-levelled — they decide which core-js-pure modules end up in your bundle. If you configure nothing, Babel falls back to browserslist's defaults query (> 0.5%, last 2 versions, Firefox ESR, not dead), which is a moving target: it is recomputed from the caniuse-lite data of whatever install you happen to have, so the same source can produce a different set of polyfill imports on two machines, or after a lockfile refresh. Pin it:

{
  "browserslist": ["last 2 versions", "not dead", "since 2020"]
}

or, for a package that only ever runs in Node:

{
  "browserslist": ["node 24"]
}

Scripts

  • npm run lint — lint ./src with ESLint v10 (flat config, eslint.config.js, extending @ololoepepe/eslint-config).
  • npm run test — run the test suite with the built-in Node test runner (node --test). The tests assert the preset's shape, transpile-smoke each kept proposal via @babel/core@8, and check the polyfill layer end to end: that modern built-ins turn into core-js-pure imports that actually resolve, that targets are honoured, and that the helper module follows the core-js switch.

License

UNLICENSED — see package.json.