fix: skip terser-webpack-plugin versions that leave bundles unminified - #1444
fix: skip terser-webpack-plugin versions that leave bundles unminified#1444giaBaoJS wants to merge 1 commit into
Conversation
terser-webpack-plugin 5.6.0 added per-minimizer asset filters and its terser implementation only accepts `.js`, `.cjs` and `.mjs` files. Re.Pack emits `.bundle` files, so every asset is filtered out before minification runs. No error or warning is reported and production bundles ship unminified. This affects both Rspack and webpack. Read the version of the resolved plugin and keep preferring the copy installed in the project root only while it can still minify Re.Pack's assets. Otherwise fall back to the copy shipped with Re.Pack and warn about the version that was skipped.
|
@giaBaoJS is attempting to deploy a commit to the Callstack Team on Vercel. A member of the Team first needs to authorize it. |
🦋 Changeset detectedLatest commit: 2259ebd The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
| function isSupportedTerserPlugin({ version }: TerserPluginCandidate): boolean { | ||
| const coerced = version ? semver.coerce(version) : null; | ||
| // when the version cannot be determined, assume the plugin works | ||
| if (!coerced) return true; | ||
| return semver.lt(coerced, FIRST_UNSUPPORTED_TERSER_PLUGIN_VERSION); | ||
| } | ||
|
|
||
| function resolveTerserPluginVersion(options?: { paths: string[] }) { | ||
| try { | ||
| terserPluginPath = require.resolve('terser-webpack-plugin', { | ||
| paths: [rootDir], | ||
| }); | ||
| const manifestPath = require.resolve( | ||
| 'terser-webpack-plugin/package.json', | ||
| options | ||
| ); | ||
| return (require(manifestPath) as { version: string }).version; | ||
| } catch { | ||
| terserPluginPath = require.resolve('terser-webpack-plugin'); | ||
| return undefined; | ||
| } | ||
| } | ||
|
|
||
| function resolveTerserPluginCandidate( | ||
| paths?: string[] | ||
| ): TerserPluginCandidate | undefined { | ||
| const options = paths ? { paths } : undefined; | ||
| try { | ||
| const pluginPath = require.resolve('terser-webpack-plugin', options); | ||
| return { pluginPath, version: resolveTerserPluginVersion(options) }; | ||
| } catch { |
There was a problem hiding this comment.
wdyt about checking plugin’s actual capability instead of its manifest version?
terser-webpack-plugin/package.json may be hidden by an exports map (node docs), causing version to be undefined & affected plugin to be accepted.
since 5.6.x exposes filter that rejects .bundle files (source), could we load the candidate & check:
const filter = Plugin.terserMinify?.filter;
return typeof filter !== 'function' || filter('index.bundle') !== false;
this directly covers current & future versions, version can remain only for warning text
Summary
terser-webpack-pluginand only prefer the copy installed in the project root while it can still minify Re.Pack's.bundleassetsgetMinimizerConfigunit tests covering the selectionWhy
terser-webpack-plugin5.6.0 added per-minimizer asset filters, and its terser implementation declaresfilter = (name) => /\.[cm]?js(\?.*)?$/i.test(name). Re.Pack emitsindex.bundleand[name].chunk.bundle, so every asset is rejected by the filter and dropped before minification runs. Nothing is reported: no error, no warning, and the asset is not flagged[minimized]in stats. Production bundles simply ship unminified.The report in #1390 attributes this to webpack internals missing under Rspack, but that is not the cause. Reproducing with the exact options Re.Pack passes, on a trivial entry, with only the plugin version changed:
minimizedminimizedSo webpack users are affected too, and the fix should not be scoped to Rspack.
Pinning
terser-webpack-pluginto 5.5.0 inpackages/repack/package.jsoncovers the fallback branch ofgetTerserPlugin, but not the root-first branch: a project that resolves 5.6.0 or newer at its own root still gets the silent no-op. That is the common case on pnpm and on hoisted layouts where another dependency pulls in a newer release.Implementation notes
The version gate is expressed against
terser-webpack-plugin, not against a bundler release, so it does not interact with the ongoing Rspack 2 work. When the version cannot be determined the plugin is assumed usable, which keeps the previous behaviour rather than failing a build over an unreadable manifest.Closes #1390.
Validation
pnpm --filter @callstack/repack test: 34 suites, 303 tests passedpnpm test: 10 tasks successfulpnpm typecheck,pnpm lint: cleangetMinimizerConfig.tswhile keeping the new tests turns the two selection tests red on the assertion (the project's incompatible plugin is chosen), not on an import or compile errorterser-webpack-plugin@5.6.1: before the change the asset is 1347 bytes and not minimized, after it is 210 bytes and minimized, with the fallback warning printed