Skip to content

Default minimizer silently no-ops with terser-webpack-plugin >= 5.6.0 under Rspack — production bundles ship unminified #1390

@yunsung-miso

Description

@yunsung-miso

Environment

  • @callstack/repack: 5.2.5
  • @rspack/core: 1.7.0
  • terser-webpack-plugin: 5.6.1 (resolved from Re.Pack's own dependency range ^5.3.14)
  • Node 24, React Native 0.83.9, monorepo with pnpm (isolated node_modules)

Summary

Re.Pack's default minimizer (getMinimizerConfiggetTerserPlugin) prefers a project-root terser-webpack-plugin and falls back to the copy declared in Re.Pack's own dependencies (^5.3.14):

// dist/commands/common/config/getMinimizerConfig.js
try {
  terserPluginPath = require.resolve('terser-webpack-plugin', { paths: [rootDir] });
} catch {
  terserPluginPath = require.resolve('terser-webpack-plugin');
}

That range now resolves to 5.6.1, and terser-webpack-plugin >= 5.6.0 depends on webpack-only internals (e.g. compiler.webpack.javascript.JavascriptModulesPlugin.getCompilationHooks, ModuleFilenameHelpers.matchObject via compiler.webpack). Under Rspack it does nothing, without any error or warning — production bundles are emitted completely unminified (comments and whitespace included), and the asset is not marked [minimized] in stats.

The failure is easy to miss because of the resolution order:

  • yarn / npm hoisted layouts: some other dependency often hoists an older terser-webpack-plugin (5.3.x) to the workspace root, the root-first resolve picks it up, and everything works — by accident.
  • pnpm / isolated layouts: nothing is hoisted to the root, the fallback resolves Re.Pack's own 5.6.1, and every production bundle silently ships unminified.

We hit this while migrating a Module Federation monorepo from yarn (hoisted) to pnpm: identical source, identical configs, and the remote expose chunks grew ~37–60% (e.g. 1.68 MB → 2.68 MB Hermes bytecode for one remote) with zero build errors. Bisecting the bundler pipeline eventually surfaced the minimizer no-op.

Reproduction (minimal A/B)

Same trivial entry, Rspack 1.7.0, mode: 'production', only the terser-webpack-plugin version differs in optimization.minimizer (using exactly the options Re.Pack passes):

new TerserPlugin({
  test: /\.(js)?bundle(\?.*)?$/i,
  extractComments: false,
  terserOptions: { format: { comments: false } },
})
terser-webpack-plugin output
5.3.16 298 bytes, [minimized], mangled/compressed
5.3.17 298 bytes, [minimized]
5.4.0 298 bytes, [minimized]
5.5.0 298 bytes, [minimized]
5.6.0 1.24 KiB, untouched (comments/whitespace intact), no [minimized], no error
5.6.1 1.24 KiB, untouched, no error

So the break is exactly at 5.6.0.

Expected behavior

Either the bundles get minified, or the build fails loudly. A silent no-op in the production minimizer is the worst case — it shipped to our staging users unnoticed.

Suggested fixes

Any of these would prevent the silent regression:

  1. Constrain Re.Pack's dependency to >=5.3.14 <5.6.0 (5.6.0 effectively dropped Rspack compatibility).
  2. When the bundler is Rspack, skip terser-webpack-plugin resolution and use a known-good path (e.g. SwcJsMinimizerRspackPlugin, with whatever guard the 1.4.11-era issue requires).
  3. After the compilation, assert that production assets matching the minimizer test carry info.minimized, and fail or warn otherwise.

The root-first require.resolve is also worth reconsidering: it makes behavior depend on what other packages happen to hoist into the workspace root, which is how this stayed hidden on yarn and only surfaced on pnpm.

Happy to provide the full repro repo if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions