chore(create-payload-app): configure db in init next flow
This commit is contained in:
@@ -9,19 +9,27 @@ import { dbReplacements } from './packages.js'
|
||||
/** Update payload config with necessary imports and adapters */
|
||||
export async function configurePayloadConfig(args: {
|
||||
dbDetails: DbDetails | undefined
|
||||
projectDir: string
|
||||
projectDirOrConfigPath: { payloadConfigPath: string } | { projectDir: string }
|
||||
}): Promise<void> {
|
||||
if (!args.dbDetails) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const payloadConfigPath = (
|
||||
await globby('**/payload.config.ts', { absolute: true, cwd: args.projectDir })
|
||||
let payloadConfigPath: string | undefined
|
||||
if (!('payloadConfigPath' in args.projectDirOrConfigPath)) {
|
||||
payloadConfigPath = (
|
||||
await globby('**/payload.config.ts', {
|
||||
absolute: true,
|
||||
cwd: args.projectDirOrConfigPath.projectDir,
|
||||
})
|
||||
)?.[0]
|
||||
} else {
|
||||
payloadConfigPath = args.projectDirOrConfigPath.payloadConfigPath
|
||||
}
|
||||
|
||||
if (!payloadConfigPath) {
|
||||
warning('Unable to update payload.config.ts with plugins')
|
||||
warning('Unable to update payload.config.ts with plugins. Could not find payload.config.ts.')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -59,6 +67,8 @@ export async function configurePayloadConfig(args: {
|
||||
|
||||
fse.writeFileSync(payloadConfigPath, configLines.join('\n'))
|
||||
} catch (err: unknown) {
|
||||
warning('Unable to update payload.config.ts with plugins')
|
||||
warning(
|
||||
`Unable to update payload.config.ts with plugins: ${err instanceof Error ? err.message : ''}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ export async function createProject(args: {
|
||||
const spinner = ora('Checking latest Payload version...').start()
|
||||
|
||||
await updatePackageJSON({ projectDir, projectName })
|
||||
await configurePayloadConfig({ dbDetails, projectDir })
|
||||
await configurePayloadConfig({ dbDetails, projectDirOrConfigPath: { projectDir } })
|
||||
|
||||
// Remove yarn.lock file. This is only desired in Payload Cloud.
|
||||
const lockPath = path.resolve(projectDir, 'yarn.lock')
|
||||
@@ -125,6 +125,6 @@ export async function updatePackageJSON(args: {
|
||||
packageObj.name = projectName
|
||||
await fse.writeJson(packageJsonPath, packageObj, { spaces: 2 })
|
||||
} catch (err: unknown) {
|
||||
warning('Unable to update name in package.json')
|
||||
warning(`Unable to update name in package.json. ${err instanceof Error ? err.message : ''}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,16 +24,23 @@ import { moveMessage } from '../utils/messages.js'
|
||||
import { wrapNextConfig } from './wrap-next-config.js'
|
||||
|
||||
type InitNextArgs = Pick<CliArgs, '--debug'> & {
|
||||
nextConfigPath: string
|
||||
packageManager: PackageManager
|
||||
projectDir: string
|
||||
useDistFiles?: boolean
|
||||
}
|
||||
type InitNextResult = { nextAppDir?: string; reason?: string; success: boolean }
|
||||
type InitNextResult =
|
||||
| {
|
||||
nextAppDir: string
|
||||
payloadConfigPath: string
|
||||
success: true
|
||||
}
|
||||
| { reason: string; success: false }
|
||||
|
||||
export async function initNext(args: InitNextArgs): Promise<InitNextResult> {
|
||||
const { packageManager, projectDir } = args
|
||||
|
||||
// Get app directory
|
||||
// Get app directory. Could be top-level or src/app
|
||||
const nextAppDir = (
|
||||
await globby(['**/app'], {
|
||||
absolute: true,
|
||||
@@ -49,27 +56,28 @@ export async function initNext(args: InitNextArgs): Promise<InitNextResult> {
|
||||
// Check for top-level layout.tsx
|
||||
const layoutPath = path.resolve(nextAppDir, 'layout.tsx')
|
||||
if (fs.existsSync(layoutPath)) {
|
||||
// Output directions for user to move all files from app to top-level directory named `(name)`
|
||||
// Output directions for user to move all files from app to top-level directory named `(app)`
|
||||
log(moveMessage({ nextAppDir, projectDir }))
|
||||
return { reason: 'Found existing layout.tsx in app directory', success: false }
|
||||
}
|
||||
|
||||
const templateResult = await installAndConfigurePayload({
|
||||
const configurationResult = installAndConfigurePayload({
|
||||
...args,
|
||||
nextAppDir,
|
||||
useDistFiles: true, // Requires running 'pnpm pack-template-files' in cpa
|
||||
})
|
||||
if (!templateResult.success) return templateResult
|
||||
|
||||
if (!configurationResult.success) return configurationResult
|
||||
|
||||
const { success: installSuccess } = await installDeps(projectDir, packageManager)
|
||||
if (!installSuccess) {
|
||||
return { ...templateResult, reason: 'Failed to install dependencies', success: false }
|
||||
return { ...configurationResult, reason: 'Failed to install dependencies', success: false }
|
||||
}
|
||||
|
||||
// Add `@payload-config` to tsconfig.json `paths`
|
||||
await addPayloadConfigToTsConfig(projectDir)
|
||||
|
||||
return templateResult
|
||||
return configurationResult
|
||||
}
|
||||
|
||||
async function addPayloadConfigToTsConfig(projectDir: string) {
|
||||
@@ -93,10 +101,8 @@ async function addPayloadConfigToTsConfig(projectDir: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function installAndConfigurePayload(
|
||||
args: InitNextArgs & { nextAppDir: string },
|
||||
): Promise<InitNextResult> {
|
||||
const { '--debug': debug, nextAppDir, projectDir, useDistFiles } = args
|
||||
function installAndConfigurePayload(args: InitNextArgs & { nextAppDir: string }): InitNextResult {
|
||||
const { '--debug': debug, nextAppDir, nextConfigPath, projectDir, useDistFiles } = args
|
||||
|
||||
info('Initializing Payload app in Next.js project', 1)
|
||||
|
||||
@@ -108,32 +114,12 @@ async function installAndConfigurePayload(
|
||||
return { reason: `Could not find specified project directory at ${projectDir}`, success: false }
|
||||
}
|
||||
|
||||
// Next.js configs can be next.config.js, next.config.mjs, etc.
|
||||
const foundConfig = (await globby('next.config.*js', { absolute: true, cwd: projectDir }))?.[0]
|
||||
|
||||
if (!foundConfig) {
|
||||
throw new Error(`No next.config.js found at ${projectDir}`)
|
||||
}
|
||||
|
||||
const nextConfigPath = path.resolve(projectDir, foundConfig)
|
||||
if (!fs.existsSync(nextConfigPath)) {
|
||||
return {
|
||||
reason: `No next.config.js found at ${nextConfigPath}. Ensure you are in a Next.js project directory.`,
|
||||
success: false,
|
||||
}
|
||||
} else {
|
||||
if (debug) logDebug(`Found Next config at ${nextConfigPath}`)
|
||||
}
|
||||
|
||||
const templateFilesPath =
|
||||
// dirname.endsWith('dist') || useDistFiles
|
||||
// ? path.resolve(dirname, '../..', 'dist/template')
|
||||
// : path.resolve(dirname, '../../../../templates/blank-3.0')
|
||||
dirname.endsWith('dist') || useDistFiles
|
||||
? path.resolve(dirname, '../..', 'dist/template')
|
||||
: path.resolve(dirname, '../../../../templates/blank-3.0')
|
||||
|
||||
if (debug) logDebug(`Using template files from: ${templateFilesPath}`)
|
||||
logDebug(`Using template files from: ${templateFilesPath}`)
|
||||
|
||||
if (!fs.existsSync(templateFilesPath)) {
|
||||
return {
|
||||
@@ -141,13 +127,7 @@ async function installAndConfigurePayload(
|
||||
success: false,
|
||||
}
|
||||
} else {
|
||||
if (debug) logDebug('Found template source files')
|
||||
}
|
||||
|
||||
if (!fs.existsSync(nextAppDir)) {
|
||||
return { reason: `Could not find user app directory inside ${projectDir}`, success: false }
|
||||
} else {
|
||||
logDebug(`Found user app directory: ${nextAppDir}`)
|
||||
logDebug('Found template source files')
|
||||
}
|
||||
|
||||
logDebug(`Copying template files from ${templateFilesPath} to ${nextAppDir}`)
|
||||
@@ -162,7 +142,11 @@ async function installAndConfigurePayload(
|
||||
wrapNextConfig({ nextConfigPath })
|
||||
|
||||
success('Successfully initialized.')
|
||||
return { nextAppDir, success: true }
|
||||
return {
|
||||
nextAppDir,
|
||||
payloadConfigPath: path.resolve(nextAppDir, '../payload.config.ts'),
|
||||
success: true,
|
||||
}
|
||||
}
|
||||
|
||||
async function installDeps(projectDir: string, packageManager: PackageManager) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import path from 'path'
|
||||
|
||||
import type { CliArgs, PackageManager } from './types.js'
|
||||
|
||||
import { configurePayloadConfig } from './lib/configure-payload-config.js'
|
||||
import { createProject } from './lib/create-project.js'
|
||||
import { generateSecret } from './lib/generate-secret.js'
|
||||
import { initNext } from './lib/init-next.js'
|
||||
@@ -14,8 +15,13 @@ import { parseTemplate } from './lib/parse-template.js'
|
||||
import { selectDb } from './lib/select-db.js'
|
||||
import { getValidTemplates, validateTemplate } from './lib/templates.js'
|
||||
import { writeEnvFile } from './lib/write-env-file.js'
|
||||
import { debug, error, log, success } from './utils/log.js'
|
||||
import { helpMessage, successMessage, welcomeMessage } from './utils/messages.js'
|
||||
import { error, log, success } from './utils/log.js'
|
||||
import {
|
||||
helpMessage,
|
||||
successMessage,
|
||||
successfulNextInit,
|
||||
welcomeMessage,
|
||||
} from './utils/messages.js'
|
||||
|
||||
export class Main {
|
||||
args: CliArgs
|
||||
@@ -59,7 +65,9 @@ export class Main {
|
||||
}
|
||||
|
||||
async init(): Promise<void> {
|
||||
const initContext = {
|
||||
const initContext: {
|
||||
nextConfigPath: string | undefined
|
||||
} = {
|
||||
nextConfigPath: undefined,
|
||||
}
|
||||
|
||||
@@ -71,10 +79,10 @@ export class Main {
|
||||
log(welcomeMessage)
|
||||
|
||||
// Detect if inside Next.js project
|
||||
const foundConfig = (
|
||||
const nextConfigPath = (
|
||||
await globby('next.config.*js', { absolute: true, cwd: process.cwd() })
|
||||
)?.[0]
|
||||
initContext.nextConfigPath = foundConfig
|
||||
initContext.nextConfigPath = nextConfigPath
|
||||
|
||||
success('Next.js app detected.')
|
||||
|
||||
@@ -85,22 +93,38 @@ export class Main {
|
||||
}
|
||||
|
||||
const projectName = await parseProjectName(this.args)
|
||||
const projectDir = foundConfig
|
||||
? path.dirname(foundConfig)
|
||||
const projectDir = nextConfigPath
|
||||
? path.dirname(nextConfigPath)
|
||||
: path.resolve(process.cwd(), slugify(projectName))
|
||||
|
||||
const packageManager = await getPackageManager(this.args, projectDir)
|
||||
debug(`Using package manager: ${packageManager}`)
|
||||
|
||||
if (foundConfig) {
|
||||
const result = await initNext({ ...this.args, packageManager, projectDir })
|
||||
if (!result.success) {
|
||||
error(result.reason || 'Failed to initialize Payload app in Next.js project')
|
||||
if (nextConfigPath) {
|
||||
const result = await initNext({
|
||||
...this.args,
|
||||
nextConfigPath,
|
||||
packageManager,
|
||||
projectDir,
|
||||
})
|
||||
if (result.success === false) {
|
||||
error(result.reason)
|
||||
process.exit(1)
|
||||
} else {
|
||||
success('Payload app successfully initialized in Next.js project')
|
||||
}
|
||||
process.exit(result.success ? 0 : 1)
|
||||
|
||||
const dbDetails = await selectDb(this.args, projectName)
|
||||
await configurePayloadConfig({
|
||||
dbDetails,
|
||||
projectDirOrConfigPath: {
|
||||
payloadConfigPath: result.payloadConfigPath,
|
||||
},
|
||||
})
|
||||
|
||||
// TODO: This should continue the normal prompt flow
|
||||
success('Payload project successfully created')
|
||||
log(successfulNextInit())
|
||||
return
|
||||
}
|
||||
|
||||
const templateArg = this.args['--template']
|
||||
|
||||
@@ -68,6 +68,20 @@ export function successMessage(projectDir: string, packageManager: string): stri
|
||||
`
|
||||
}
|
||||
|
||||
export function successfulNextInit(): string {
|
||||
return `
|
||||
${header('Successful Payload Installation!')}
|
||||
|
||||
${header('Documentation:')}
|
||||
|
||||
- ${createTerminalLink(
|
||||
'Getting Started',
|
||||
'https://payloadcms.com/docs/getting-started/what-is-payload',
|
||||
)}
|
||||
- ${createTerminalLink('Configuration', 'https://payloadcms.com/docs/configuration/overview')}
|
||||
`
|
||||
}
|
||||
|
||||
export function moveMessage(args: { nextAppDir: string; projectDir: string }): string {
|
||||
return `
|
||||
${header('Next Steps:')}
|
||||
@@ -77,7 +91,7 @@ export function moveMessage(args: { nextAppDir: string; projectDir: string }): s
|
||||
${chalk.bold('To continue:')}
|
||||
|
||||
- Move all files from ${args.nextAppDir} to a top-level directory named ${chalk.bold(
|
||||
'(name)',
|
||||
'(app)',
|
||||
)} or similar.
|
||||
|
||||
Once moved, rerun the create-payload-app command again.
|
||||
|
||||
Reference in New Issue
Block a user