|
1 | 1 | importtype{PackageJson}from'pkg-types' |
2 | 2 |
|
| 3 | +importtype{InstallResult}from'../utils/install' |
| 4 | + |
3 | 5 | import{existsSync}from'node:fs' |
4 | 6 | importprocessfrom'node:process' |
5 | 7 |
|
6 | | -import{cancel,intro,isCancel,note,outro,select,spinner,tasks}from'@clack/prompts' |
| 8 | +import{cancel,intro,isCancel,note,outro,select,spinner}from'@clack/prompts' |
7 | 9 | import{defineCommand}from'citty' |
8 | | -import{addDependency,dedupeDependencies,detectPackageManager}from'nypm' |
| 10 | +import{detectPackageManager}from'nypm' |
9 | 11 | import{dirname,relative,resolve}from'pathe' |
10 | 12 | importcolorsfrom'picocolors' |
11 | 13 | import{findWorkspaceDir,readPackageJSON}from'pkg-types' |
12 | 14 |
|
| 15 | +import{createInstallLog,runDedupe,runInstall,takeUnreportedIgnoredBuilds}from'../utils/install' |
13 | 16 | import{loadKit}from'../utils/kit' |
14 | 17 | import{logger}from'../utils/logger' |
15 | 18 | import{cleanupNuxtDirs,nuxtVersionToGitIdentifier}from'../utils/nuxt' |
@@ -188,59 +191,53 @@ export default defineCommand({ |
188 | 191 |
|
189 | 192 | constversionType=ctx.args.channel==='nightly' ? 'nightly' : `latest ${ctx.args.channel}` |
190 | 193 |
|
191 | | -constspin=spinner() |
192 | | -spin.start('Upgrading Nuxt') |
193 | | - |
194 | | -awaittasks([ |
195 | | -{ |
196 | | -title: `Installing ${versionType} Nuxt ${nuxtVersion} release`, |
197 | | -task: async()=>{ |
198 | | -awaitaddDependency(npmPackages,{ |
199 | | - cwd, |
200 | | - packageManager, |
201 | | -dev: nuxtDependencyType==='devDependencies', |
202 | | -workspace: packageManager?.name==='pnpm'&&existsSync(resolve(cwd,'pnpm-workspace.yaml')), |
203 | | -}) |
204 | | -return'Nuxt packages installed' |
205 | | -}, |
206 | | -}, |
207 | | - ...(method==='force' |
208 | | - ? [{ |
209 | | -title: `Recreating ${forceRemovals}`, |
210 | | -task: async()=>{ |
211 | | -awaitdedupeDependencies({recreateLockfile: true}) |
212 | | -return'Lockfile recreated' |
213 | | -}, |
214 | | -}] |
215 | | - : []), |
216 | | - ...(method==='dedupe' |
217 | | - ? [{ |
218 | | -title: 'Deduping dependencies', |
219 | | -task: async()=>{ |
220 | | -awaitdedupeDependencies() |
221 | | -return'Dependencies deduped' |
222 | | -}, |
223 | | -}] |
224 | | - : []), |
225 | | -{ |
226 | | -title: 'Cleaning up build directories', |
227 | | -task: async()=>{ |
228 | | -letbuildDir: string='.nuxt' |
229 | | -try{ |
230 | | -const{ loadNuxtConfig }=awaitloadKit(cwd) |
231 | | -constnuxtOptions=awaitloadNuxtConfig({ cwd }) |
232 | | -buildDir=nuxtOptions.buildDir |
233 | | -} |
234 | | -catch{ |
235 | | -// Use default buildDir (.nuxt) |
236 | | -} |
237 | | -awaitcleanupNuxtDirs(cwd,buildDir) |
238 | | -return'Build directories cleaned' |
239 | | -}, |
240 | | -}, |
241 | | -]) |
242 | | - |
243 | | -spin.stop() |
| 194 | +constverbose=ctx.args.logLevel==='verbose'||Boolean(process.env.DEBUG) |
| 195 | + |
| 196 | +constinstallFailed=awaitwithInstallSpinner( |
| 197 | +`Installing ${versionType} Nuxt ${nuxtVersion} release`, |
| 198 | +'Nuxt packages installed', |
| 199 | +{ verbose }, |
| 200 | +hooks=>runInstall({ |
| 201 | + cwd, |
| 202 | + packageManager, |
| 203 | +dependencies: npmPackages, |
| 204 | +dev: nuxtDependencyType==='devDependencies', |
| 205 | +workspace: packageManager.name==='pnpm'&&existsSync(resolve(cwd,'pnpm-workspace.yaml')), |
| 206 | + ...hooks, |
| 207 | +}), |
| 208 | +) |
| 209 | + |
| 210 | +if(installFailed){ |
| 211 | +process.exit(1) |
| 212 | +} |
| 213 | + |
| 214 | +if(method==='force'||method==='dedupe'){ |
| 215 | +constrecreateLockfile=method==='force' |
| 216 | +constfailed=awaitwithInstallSpinner( |
| 217 | +recreateLockfile ? `Recreating ${forceRemovals}` : 'Deduping dependencies', |
| 218 | +recreateLockfile ? 'Lockfile recreated' : 'Dependencies deduped', |
| 219 | +{ verbose }, |
| 220 | +hooks=>runDedupe({ cwd, packageManager, recreateLockfile, ...hooks}), |
| 221 | +) |
| 222 | + |
| 223 | +if(failed){ |
| 224 | +process.exit(1) |
| 225 | +} |
| 226 | +} |
| 227 | + |
| 228 | +constcleanupSpinner=spinner() |
| 229 | +cleanupSpinner.start('Cleaning up build directories') |
| 230 | +letbuildDir: string='.nuxt' |
| 231 | +try{ |
| 232 | +const{ loadNuxtConfig }=awaitloadKit(cwd) |
| 233 | +constnuxtOptions=awaitloadNuxtConfig({ cwd }) |
| 234 | +buildDir=nuxtOptions.buildDir |
| 235 | +} |
| 236 | +catch{ |
| 237 | +// Use default buildDir (.nuxt) |
| 238 | +} |
| 239 | +awaitcleanupNuxtDirs(cwd,buildDir,{silent: true}) |
| 240 | +cleanupSpinner.stop('Build directories cleaned') |
244 | 241 |
|
245 | 242 | if(method==='force'){ |
246 | 243 | logger.info(`If you encounter any issues, revert the changes and try with ${colors.cyan('--no-force')}`) |
@@ -276,6 +273,53 @@ export default defineCommand({ |
276 | 273 | }, |
277 | 274 | }) |
278 | 275 |
|
| 276 | +interfaceInstallHooks{ |
| 277 | +onOutput: (line: string)=>void |
| 278 | +onStatus: (message: string)=>void |
| 279 | +signal: AbortSignal |
| 280 | +} |
| 281 | + |
| 282 | +/** |
| 283 | + * Run a package manager step behind a spinner, surfacing its output only when it |
| 284 | + * fails (or when running verbosely). Returns whether the step failed. |
| 285 | + */ |
| 286 | +asyncfunctionwithInstallSpinner( |
| 287 | +title: string, |
| 288 | +success: string, |
| 289 | +options: {verbose: boolean}, |
| 290 | +run: (hooks: InstallHooks)=>Promise<InstallResult>, |
| 291 | +): Promise<boolean>{ |
| 292 | +constcontroller=newAbortController() |
| 293 | +constinstallLog=createInstallLog({verbose: options.verbose}) |
| 294 | +constspin=spinner({ |
| 295 | +indicator: 'timer', |
| 296 | +onCancel: ()=>controller.abort(), |
| 297 | +}) |
| 298 | + |
| 299 | +spin.start(title) |
| 300 | +constresult=awaitrun({ |
| 301 | +onOutput: installLog.onOutput, |
| 302 | +onStatus: message=>spin.message(message), |
| 303 | +signal: controller.signal, |
| 304 | +}) |
| 305 | + |
| 306 | +if(result.success){ |
| 307 | +spin.stop(success) |
| 308 | +} |
| 309 | +else{ |
| 310 | +spin.error(result.error??`${title} failed`) |
| 311 | +} |
| 312 | + |
| 313 | +installLog.finish(result) |
| 314 | + |
| 315 | +constignoredBuilds=takeUnreportedIgnoredBuilds(result.ignoredBuilds) |
| 316 | +if(ignoredBuilds.length>0){ |
| 317 | +logger.warn(`Build scripts were not run for ${ignoredBuilds.map(name=>colors.cyan(name)).join(', ')}.`) |
| 318 | +} |
| 319 | + |
| 320 | +return!result.success |
| 321 | +} |
| 322 | + |
279 | 323 | // Find which lock file is in use since `nypm.detectPackageManager` doesn't return this |
280 | 324 | exportfunctionfindLockFile(cwd: string,workspaceDir: string,lockFiles: string|Array<string>|undefined){ |
281 | 325 | constcandidates=typeoflockFiles==='string' ? [lockFiles] : lockFiles |
|
0 commit comments