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
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
},
"devDependencies": {
"@vitejs/plugin-react": "^4.2.0",
"@vitest/browser-playwright": "^4.0.0",
"oxfmt": "1",
"oxlint": "1",
"vite": "^7.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"dev": "vite"
},
"devDependencies": {
"@vitejs/plugin-react": "catalog:",
"vite": "catalog:"
},
"packageManager": "pnpm@10.20.0+sha512.cf9998222162dd85864d0a8102e7892e7ba4ceadebbf5a31f9c2fce48dfce317a9c53b9f6464d1ef9042cba2e02ae02a9f7c143a2b438cd93c91840f0192b9dd",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default defineConfig({
"prepare": "vp config"
},
"devDependencies": {
"@vitejs/plugin-react": "catalog:",
"vite": "catalog:",
"vite-plus": "catalog:"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"testnpm2": "1.0.0"
},
"devDependencies": {
"@vitejs/plugin-react": "catalog:",
"oxfmt": "catalog:",
"oxlint": "catalog:",
"vite": "catalog:",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ cat: .oxfmtrc.json: No such file or directory
"testnpm2": "1.0.0"
},
"devDependencies": {
"@vitejs/plugin-react": "catalog:",
"vite": "catalog:",
"vitest": "catalog:",
"vite-plus": "catalog:"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"testnpm2": "1.0.0"
},
"devDependencies": {
"@vitejs/plugin-react": "catalog:",
"oxfmt": "catalog:",
"oxlint": "catalog:",
"vite": "catalog:",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ cat: .oxlintrc.json: No such file or directory
"testnpm2": "1.0.0"
},
"devDependencies": {
"@vitejs/plugin-react": "catalog:",
"vite": "catalog:",
"vitest": "catalog:",
"vite-plus": "catalog:"
Expand Down
50 changes: 50 additions & 0 deletions packages/cli/src/migration/__tests__/compat.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { describe, expect, it } from 'vitest';

import { checkManualChunksCompat } from '../compat.js';
import { createMigrationReport } from '../report.js';

describe('checkManualChunksCompat', () => {
it('should warn when manualChunks is an object', () => {
const report = createMigrationReport();
checkManualChunksCompat({ manualChunks: { react: ['react', 'react-dom'] } }, report);
expect(report.warnings).toHaveLength(1);
expect(report.warnings[0]).toContain('Object-form');
expect(report.warnings[0]).toContain('codeSplitting');
});

it('should not warn when manualChunks is a function', () => {
const report = createMigrationReport();
checkManualChunksCompat({ manualChunks: () => undefined }, report);
expect(report.warnings).toHaveLength(0);
});

it('should not warn when manualChunks is not set', () => {
const report = createMigrationReport();
checkManualChunksCompat({}, report);
expect(report.warnings).toHaveLength(0);
});

it('should not warn when output is undefined', () => {
const report = createMigrationReport();
checkManualChunksCompat(undefined, report);
expect(report.warnings).toHaveLength(0);
});

it('should handle array of outputs', () => {
const report = createMigrationReport();
checkManualChunksCompat(
[{ manualChunks: () => undefined }, { manualChunks: { vendor: ['lodash'] } }],
report,
);
expect(report.warnings).toHaveLength(1);
});

it('should only add one warning for multiple object-form outputs', () => {
const report = createMigrationReport();
checkManualChunksCompat(
[{ manualChunks: { react: ['react'] } }, { manualChunks: { lodash: ['lodash'] } }],
report,
);
expect(report.warnings).toHaveLength(1);
});
});
41 changes: 39 additions & 2 deletions packages/cli/src/migration/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,22 @@ function showMigrationSummary(options: {
}
}

async function checkRolldownCompatibility(rootDir: string, report: MigrationReport): Promise<void> {
try {
const { resolveConfig } = await import('../index.js');
const { checkManualChunksCompat } = await import('./compat.js');
// Use 'runner' configLoader to avoid Rolldown bundling the config file,
// which prints UNRESOLVED_IMPORT warnings that cannot be suppressed via logLevel.
const config = await resolveConfig(
{ root: rootDir, logLevel: 'silent', configLoader: 'runner' },
'build',
);
checkManualChunksCompat(config.build?.rollupOptions?.output, report);
} catch {
// Config resolution may fail — skip compatibility check silently
}
}

async function executeMigrationPlan(
workspaceInfoOptional: WorkspaceInfoOptional,
plan: MigrationPlan,
Expand Down Expand Up @@ -637,7 +653,16 @@ async function executeMigrationPlan(
cancelAndExit('Vite+ cannot automatically migrate this project yet.', 1);
}

// 5. ESLint → Oxlint migration (before main rewrite so .oxlintrc.json gets picked up)
// 5. Check for Rolldown-incompatible config patterns (root + workspace packages)
updateMigrationProgress('Checking config compatibility');
await checkRolldownCompatibility(workspaceInfo.rootDir, report);
if (workspaceInfo.packages) {
for (const pkg of workspaceInfo.packages) {
await checkRolldownCompatibility(path.join(workspaceInfo.rootDir, pkg.path), report);
}
}

// 6. ESLint → Oxlint migration (before main rewrite so .oxlintrc.json gets picked up)
if (plan.migrateEslint) {
updateMigrationProgress('Migrating ESLint');
const eslintOk = await migrateEslintToOxlint(
Expand Down Expand Up @@ -725,6 +750,7 @@ async function executeMigrationPlan(
installArgs,
{ silent: true },
);

clearMigrationProgress();
return {
installDurationMs: initialInstallSummary.durationMs + finalInstallSummary.durationMs,
Expand Down Expand Up @@ -825,7 +851,18 @@ async function main() {
}
}

if (didMigrate) {
// Check for Rolldown-incompatible config patterns (root + workspace packages)
await checkRolldownCompatibility(workspaceInfoOptional.rootDir, report);
if (workspaceInfoOptional.packages) {
for (const pkg of workspaceInfoOptional.packages) {
await checkRolldownCompatibility(
path.join(workspaceInfoOptional.rootDir, pkg.path),
report,
);
}
}

if (didMigrate || report.warnings.length > 0) {
clearMigrationProgress();
showMigrationSummary({
projectRoot: workspaceInfoOptional.rootDir,
Expand Down
19 changes: 19 additions & 0 deletions packages/cli/src/migration/compat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { addMigrationWarning, type MigrationReport } from './report.js';

/**
* Check for Rolldown-incompatible manualChunks config patterns.
*/
export function checkManualChunksCompat(output: unknown, report: MigrationReport): void {
const outputs = Array.isArray(output) ? output : output ? [output] : [];
for (const out of outputs) {
if (out.manualChunks != null && typeof out.manualChunks !== 'function') {
addMigrationWarning(
report,
'Object-form `build.rollupOptions.output.manualChunks` is not supported by Rolldown. ' +
'Convert it to function form or use `build.rolldownOptions.output.codeSplitting`. ' +
'See: https://rolldown.rs/options/output#manualchunks and https://rolldown.rs/in-depth/manual-code-splitting',
);
break;
}
}
}
Loading