diff --git a/.gitignore b/.gitignore index 2aeecfa8..dce6d10d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules dist .vscode +.idea .nuxt nuxt-app .pnpm-store diff --git a/packages/nuxi/src/commands/upgrade.ts b/packages/nuxi/src/commands/upgrade.ts index 357d5e06..3aa59233 100644 --- a/packages/nuxi/src/commands/upgrade.ts +++ b/packages/nuxi/src/commands/upgrade.ts @@ -5,11 +5,10 @@ import process from 'node:process' import { defineCommand } from 'citty' import { colors } from 'consola/utils' -import { addDependency, detectPackageManager } from 'nypm' +import { addDependency, dedupeDependencies, detectPackageManager } from 'nypm' import { resolve } from 'pathe' import { readPackageJSON } from 'pkg-types' -import { rmRecursive, touchFile } from '../utils/fs' import { loadKit } from '../utils/kit' import { logger } from '../utils/logger' import { cleanupNuxtDirs, nuxtVersionToGitIdentifier } from '../utils/nuxt' @@ -78,6 +77,10 @@ export default defineCommand({ ...cwdArgs, ...logLevelArgs, ...legacyRootDirArgs, + dedupe: { + type: 'boolean', + description: 'Dedupe dependencies after upgrading', + }, force: { type: 'boolean', alias: 'f', @@ -131,23 +134,47 @@ export default defineCommand({ const forceRemovals = toRemove .map(p => colors.cyan(p)) .join(' and ') - if (ctx.args.force === undefined) { - ctx.args.force = await logger.prompt( - `Would you like to recreate ${forceRemovals} to fix problems with hoisted dependency versions and ensure you have the most up-to-date dependencies?`, - { - type: 'confirm', - default: true, - }, - ) === true + + let method: 'force' | 'dedupe' | 'skip' | undefined = ctx.args.force ? 'force' : ctx.args.dedupe ? 'dedupe' : undefined + + method ||= await logger.prompt( + `Would you like to dedupe your lockfile (recommended) or recreate ${forceRemovals}? This can fix problems with hoisted dependency versions and ensure you have the most up-to-date dependencies.`, + { + type: 'select', + initial: 'dedupe', + options: [ + { + label: 'dedupe lockfile', + value: 'dedupe' as const, + hint: 'recommended', + }, + { + label: `recreate ${forceRemovals}`, + value: 'force' as const, + }, + { + label: 'skip', + value: 'skip' as const, + }, + ], + }, + ) + + // user bails on the question with Ctrl+C + if (typeof method !== 'string') { + process.exit(1) } - if (ctx.args.force) { + + if (method === 'force') { logger.info( `Recreating ${forceRemovals}. If you encounter any issues, revert the changes and try with \`--no-force\``, ) - await rmRecursive(toRemove.map(file => resolve(cwd, file))) - if (lockFile) { - await touchFile(resolve(cwd, lockFile)) - } + await dedupeDependencies({ recreateLockfile: true }) + } + + if (method === 'dedupe') { + logger.info('Try deduping dependencies...') + await dedupeDependencies() } const versionType = ctx.args.channel === 'nightly' ? 'nightly' : 'latest stable' diff --git a/packages/nuxi/src/utils/fs.ts b/packages/nuxi/src/utils/fs.ts index 13258f08..d422241b 100644 --- a/packages/nuxi/src/utils/fs.ts +++ b/packages/nuxi/src/utils/fs.ts @@ -3,17 +3,6 @@ import { join } from 'pathe' import { logger } from '../utils/logger' -// Check if a file exists -async function exists(path: string) { - try { - await fsp.access(path) - return true - } - catch { - return false - } -} - export async function clearDir(path: string, exclude?: string[]) { if (!exclude) { await fsp.rm(path, { recursive: true, force: true }) @@ -45,12 +34,3 @@ export async function rmRecursive(paths: string[]) { }), ) } - -export async function touchFile(path: string) { - if (await exists(path)) { - return - } - await fsp.writeFile(path, '').catch(() => { - logger.error(`Failed to create file: ${path}`) - }) -}