Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 0 additions & 23 deletions examples/app-router-playground/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,29 +83,6 @@ export default defineConfig({
childEnvironments: ["ssr"],
},
}),

// Vite 8 (rolldown) warns on rollup-only keys injected by vinext.
// Strip those keys from the resolved client build config.
{
name: "strip-rolldown-incompatible-rollup-options",
configResolved(config) {
const clientRollupOptions = (config as any).environments?.client?.build?.rollupOptions;
if (!clientRollupOptions) return;

if (
clientRollupOptions.treeshake &&
typeof clientRollupOptions.treeshake === "object" &&
!Array.isArray(clientRollupOptions.treeshake)
) {
delete clientRollupOptions.treeshake.preset;
}

const output = clientRollupOptions.output;
if (output && typeof output === "object" && !Array.isArray(output)) {
delete output.experimentalMinChunkSize;
}
},
},
],

resolve: {
Expand Down
52 changes: 47 additions & 5 deletions packages/vinext/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,9 @@ const clientCodeSplittingConfig = {
* tryCatchDeoptimization: false, which can break specific libraries
* that rely on property access side effects or try/catch for feature detection
* - 'recommended' + 'no-external' gives most of the benefit with less risk
*
* @deprecated Use getClientTreeshakeConfigForVite(viteMajorVersion) instead
* for Vite version compatibility. Kept for backward compatibility.
*/
const clientTreeshakeConfig = {
preset: "recommended" as const,
Expand Down Expand Up @@ -634,6 +637,42 @@ function getClientOutputConfigForVite(viteMajorVersion: number) {
: clientOutputConfig;
}

/**
* Returns treeshake configuration appropriate for the Vite version.
*
* Rollup (Vite 7) supports presets like "recommended" which set multiple
* treeshake options at once. Rolldown (Vite 8+) doesn't support presets,
* so we only return moduleSideEffects for Vite 8+.
*
* The Rollup "recommended" preset sets:
* - annotations: true (Rolldown default is also true)
* - manualPureFunctions: [] (Rolldown default is also [])
* - propertyReadSideEffects: true (Rolldown equivalent is 'always', the default)
* - unknownGlobalSideEffects: false (Rolldown default is true β€” this is a known acceptable
* divergence. Slightly less aggressive DCE on unknown globals, acceptable for client bundles)
* - correctVarValueBeforeDeclaration and tryCatchDeoptimization (Rolldown handles these differently)
*
* The key optimization is moduleSideEffects: "no-external", which is supported
* by both bundlers and provides the DCE benefits for barrel-exporting libraries.
* It treats node_modules as side-effect-free (enabling aggressive DCE) while
* preserving side effects in local code.
*/
function getClientTreeshakeConfigForVite(viteMajorVersion: number) {
if (viteMajorVersion >= 8) {
// Rolldown (Vite 8+) - no preset support, only specific options.
// Rolldown's built-in defaults already cover what Rollup's 'recommended'
// preset provides (annotations, correctContext, tryCatchDeoptimization).
return {
moduleSideEffects: "no-external" as const,
};
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Rollup recommended preset sets more than just moduleSideEffects β€” it also enables annotations: true, correctContext: true, tryCatchDeoptimization: true, etc. Dropping these for Vite 8+ is probably fine if Rolldown's defaults already cover them, but worth confirming and documenting here. A one-liner like:

Suggested change
}
// Rolldown (Vite 8+) - no preset support, only specific options.
// Rolldown's built-in defaults already cover what Rollup's 'recommended'
// preset provides (annotations, correctContext, tryCatchDeoptimization).
return {

would help future readers understand this isn't an accidental loss of optimizations.

// Rollup (Vite 7) - supports presets for convenient option grouping
return {
preset: "recommended" as const,
moduleSideEffects: "no-external" as const,
};
}

type BundleBackfillChunk = {
type: "chunk";
fileName: string;
Expand Down Expand Up @@ -1441,14 +1480,16 @@ export default function vinext(options: VinextOptions = {}): PluginOption[] {
};
})(),
// Enable aggressive tree-shaking for client builds.
// See clientTreeshakeConfig for rationale.
// See getClientTreeshakeConfigForVite JSDoc for rationale.
// Only apply globally for standalone client builds (Pages Router
// CLI). For multi-environment builds (App Router, Cloudflare),
// treeshake is set per-environment on the client env below to
// avoid leaking into RSC/SSR environments where
// moduleSideEffects: 'no-external' could drop server packages
// that rely on module-level side effects.
...(!isSSR && !isMultiEnv ? { treeshake: clientTreeshakeConfig } : {}),
...(!isSSR && !isMultiEnv
? { treeshake: getClientTreeshakeConfigForVite(viteMajorVersion) }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not part of this diff, but the comment at line 1483 still references the deprecated clientTreeshakeConfig. Since you're updating all the call sites, worth updating that comment to point to getClientTreeshakeConfigForVite as well.

: {}),
// Code-split client bundles: separate framework (React/ReactDOM),
// vinext runtime (shims), and vendor packages into their own
// chunks so pages only load the JS they need.
Expand Down Expand Up @@ -1696,7 +1737,7 @@ export default function vinext(options: VinextOptions = {}): PluginOption[] {
...withBuildBundlerOptions(viteMajorVersion, {
input: { index: VIRTUAL_APP_BROWSER_ENTRY },
output: getClientOutputConfigForVite(viteMajorVersion),
treeshake: clientTreeshakeConfig,
treeshake: getClientTreeshakeConfigForVite(viteMajorVersion),
}),
},
},
Expand All @@ -1717,7 +1758,7 @@ export default function vinext(options: VinextOptions = {}): PluginOption[] {
...withBuildBundlerOptions(viteMajorVersion, {
input: { index: VIRTUAL_CLIENT_ENTRY },
output: getClientOutputConfigForVite(viteMajorVersion),
treeshake: clientTreeshakeConfig,
treeshake: getClientTreeshakeConfigForVite(viteMajorVersion),
}),
},
},
Expand All @@ -1743,7 +1784,7 @@ export default function vinext(options: VinextOptions = {}): PluginOption[] {
...withBuildBundlerOptions(viteMajorVersion, {
input: { index: VIRTUAL_CLIENT_ENTRY },
output: getClientOutputConfigForVite(viteMajorVersion),
treeshake: clientTreeshakeConfig,
treeshake: getClientTreeshakeConfigForVite(viteMajorVersion),
}),
},
},
Expand Down Expand Up @@ -4084,6 +4125,7 @@ export {
clientTreeshakeConfig,
computeLazyChunks,
getClientOutputConfigForVite,
getClientTreeshakeConfigForVite,
};
export { augmentSsrManifestFromBundle as _augmentSsrManifestFromBundle };
export { resolvePostcssStringPlugins as _resolvePostcssStringPlugins };
Expand Down
34 changes: 32 additions & 2 deletions tests/build-optimization.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { describe, it, expect, beforeEach, afterEach } from "vite-plus/test";
import {
clientManualChunks,
clientTreeshakeConfig,
getClientTreeshakeConfigForVite,
computeLazyChunks,
_augmentSsrManifestFromBundle,
_stripServerExports,
Expand Down Expand Up @@ -387,7 +388,6 @@ describe("treeshake config integration", () => {

// treeshake should be set on bundler options for non-SSR builds
expect(getBuildBundlerOptions(result).treeshake).toEqual({
preset: "recommended",
moduleSideEffects: "no-external",
});
} finally {
Expand Down Expand Up @@ -479,7 +479,6 @@ describe("treeshake config integration", () => {

// Client environment should have treeshake
expect(getEnvBuildBundlerOptions(result.environments.client).treeshake).toEqual({
preset: "recommended",
moduleSideEffects: "no-external",
});

Expand Down Expand Up @@ -1632,3 +1631,34 @@ export const getStaticPaths = () => [
expect(result).not.toContain("a;b");
});
});

// ─── getClientTreeshakeConfigForVite ──────────────────────────────────────────

describe("getClientTreeshakeConfigForVite", () => {
it("returns preset for Vite 7 (Rollup compatibility)", () => {
const config = getClientTreeshakeConfigForVite(7);
expect(config).toEqual({
preset: "recommended",
moduleSideEffects: "no-external",
});
});

it("returns config without preset for Vite 8 (Rolldown compatibility)", () => {
const config = getClientTreeshakeConfigForVite(8);
expect(config).toEqual({
moduleSideEffects: "no-external",
});
});

it("returns config without preset for Vite 9+", () => {
const config9 = getClientTreeshakeConfigForVite(9);
expect(config9).toEqual({
moduleSideEffects: "no-external",
});

const config10 = getClientTreeshakeConfigForVite(10);
expect(config10).toEqual({
moduleSideEffects: "no-external",
});
});
});
Loading