feat(cpa): update existing payload installation (#6193)

Updates create-payload-app to update an existing payload installation

- Detects existing Payload installation. Fixes #6517 
- If not latest, will install latest and grab the `(payload)` directory
structure (ripped from `templates/blank-3.0`
This commit is contained in:
Elliot DeNolf
2024-05-28 11:38:33 -04:00
committed by GitHub
parent ea48ca377e
commit 10c94b3665
6 changed files with 237 additions and 66 deletions

View File

@@ -6,24 +6,24 @@ import execa from 'execa'
import fs from 'fs'
import fse from 'fs-extra'
import globby from 'globby'
import { fileURLToPath } from 'node:url'
import path from 'path'
import { promisify } from 'util'
import type { CliArgs, DbType, NextAppDetails, NextConfigType, PackageManager } from '../types.js'
import { copyRecursiveSync } from '../utils/copy-recursive-sync.js'
import { debug as origDebug, warning } from '../utils/log.js'
import { moveMessage } from '../utils/messages.js'
import { installPackages } from './install-packages.js'
import { wrapNextConfig } from './wrap-next-config.js'
const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
import { fileURLToPath } from 'node:url'
import type { CliArgs, DbType, PackageManager } from '../types.js'
import { copyRecursiveSync } from '../utils/copy-recursive-sync.js'
import { debug as origDebug, warning } from '../utils/log.js'
import { moveMessage } from '../utils/messages.js'
import { wrapNextConfig } from './wrap-next-config.js'
type InitNextArgs = Pick<CliArgs, '--debug'> & {
dbType: DbType
nextAppDetails?: NextAppDetails
@@ -32,8 +32,6 @@ type InitNextArgs = Pick<CliArgs, '--debug'> & {
useDistFiles?: boolean
}
type NextConfigType = 'cjs' | 'esm'
type InitNextResult =
| {
isSrcDir: boolean
@@ -55,7 +53,8 @@ export async function initNext(args: InitNextArgs): Promise<InitNextResult> {
nextAppDetails.nextAppDir = createdAppDir
}
const { hasTopLevelLayout, isSrcDir, nextAppDir, nextConfigType } = nextAppDetails
const { hasTopLevelLayout, isPayloadInstalled, isSrcDir, nextAppDir, nextConfigType } =
nextAppDetails
if (!nextConfigType) {
return {
@@ -228,37 +227,10 @@ async function installDeps(projectDir: string, packageManager: PackageManager, d
packagesToInstall.push(`@payloadcms/db-${dbType}@beta`)
let exitCode = 0
switch (packageManager) {
case 'npm': {
;({ exitCode } = await execa('npm', ['install', '--save', ...packagesToInstall], {
cwd: projectDir,
}))
break
}
case 'yarn':
case 'pnpm': {
;({ exitCode } = await execa(packageManager, ['add', ...packagesToInstall], {
cwd: projectDir,
}))
break
}
case 'bun': {
warning('Bun support is untested.')
;({ exitCode } = await execa('bun', ['add', ...packagesToInstall], { cwd: projectDir }))
break
}
}
// Match graphql version of @payloadcms/next
packagesToInstall.push('graphql@^16.8.1')
return { success: exitCode === 0 }
}
type NextAppDetails = {
hasTopLevelLayout: boolean
isSrcDir: boolean
nextAppDir?: string
nextConfigPath?: string
nextConfigType?: NextConfigType
return await installPackages({ packageManager, packagesToInstall, projectDir })
}
export async function getNextAppDetails(projectDir: string): Promise<NextAppDetails> {
@@ -267,6 +239,7 @@ export async function getNextAppDetails(projectDir: string): Promise<NextAppDeta
const nextConfigPath: string | undefined = (
await globby('next.config.*js', { absolute: true, cwd: projectDir })
)?.[0]
if (!nextConfigPath || nextConfigPath.length === 0) {
return {
hasTopLevelLayout: false,
@@ -275,6 +248,16 @@ export async function getNextAppDetails(projectDir: string): Promise<NextAppDeta
}
}
const packageObj = await fse.readJson(path.resolve(projectDir, 'package.json'))
if (packageObj.dependencies?.payload) {
return {
hasTopLevelLayout: false,
isPayloadInstalled: true,
isSrcDir,
nextConfigPath,
}
}
let nextAppDir: string | undefined = (
await globby(['**/app'], {
absolute: true,
@@ -288,7 +271,7 @@ export async function getNextAppDetails(projectDir: string): Promise<NextAppDeta
nextAppDir = undefined
}
const configType = await getProjectType(projectDir, nextConfigPath)
const configType = getProjectType({ nextConfigPath, packageObj })
const hasTopLevelLayout = nextAppDir
? fs.existsSync(path.resolve(nextAppDir, 'layout.tsx'))
@@ -297,7 +280,11 @@ export async function getNextAppDetails(projectDir: string): Promise<NextAppDeta
return { hasTopLevelLayout, isSrcDir, nextAppDir, nextConfigPath, nextConfigType: configType }
}
async function getProjectType(projectDir: string, nextConfigPath: string): Promise<'cjs' | 'esm'> {
function getProjectType(args: {
nextConfigPath: string
packageObj: Record<string, unknown>
}): 'cjs' | 'esm' {
const { nextConfigPath, packageObj } = args
if (nextConfigPath.endsWith('.mjs')) {
return 'esm'
}
@@ -305,7 +292,6 @@ async function getProjectType(projectDir: string, nextConfigPath: string): Promi
return 'cjs'
}
const packageObj = await fse.readJson(path.resolve(projectDir, 'package.json'))
const packageJsonType = packageObj.type
if (packageJsonType === 'module') {
return 'esm'