Skip to content

Dead-code elimination of unused default parameters #15671

@bitjson

Description

@bitjson

Feature request

During dead-code elimination/tree shaking, default parameters that aren't used by the bundle can be removed.

What is the expected behavior?

For this simple example:

module.js:

const internalAdd = (a, b) => (a === '0' ? b : a + b); // should not appear in bundle
export const addAndLog = (a, b, impl = internalAdd) => console.log(impl(a, b));

app.js:

import { addAndLog } from './module.js';
const myAdd = (a, b) => a + b;
addAndLog(1, 2, myAdd); // => 3

The produced bundle should include only:

const addAndLog = (a, b, impl) => console.log(impl(a, b));
const myAdd = (a, b) => a + b;
addAndLog(1, 2, myAdd); // => 3

A detailed example (testing with all known bundlers) is available at this repo: https://github.com/bitjson/shake-default-params

What is motivation or use case for adding/changing the behavior?

I maintain Libauth, a library that offers WebAssembly crypto implementations (ripemd160, sha1, sha256, sha512, and secp256k1). As a pure ESM library, Libauth can asynchronously instantiate each WASM implementation internally, exporting simple interfaces that behave like collections of JS-only functions (with better performance). Many of Libauth's exported functions also use one of these built-in WASM instances as a default parameter. For example, decodeBase58Address has the definition:

export const decodeBase58Address = (
  address: string,
  sha256: { hash: (input: Uint8Array) => Uint8Array } = internalSha256
) => {
  // ...
};

Most applications can simply call decodeBase58Address(address) to automatically use the default, WASM-based sha256 implementation (internalSha256).

However, applications that already have another sha256 implementation can provide that implementation as the second parameter: decodeBase58Address(address, mySha256Implementation). In this case, the default parameter (internalSha256) is dead code and should be possible to eliminate from the application's bundle, saving hundreds of KBs from those bundles.

How should this be implemented in your opinion?

I'm not familiar enough with Webpack's internals to have an opinion on implementation.

Are you willing to work on this yourself?

Yes, though I'd likely need help.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions