templates: pin all payload packages, improve gen-templates script (#11841)
This PR comes with a bunch of improvements to our template generation script that makes it safer and more reliable - bumps all our templates - Using `latest` as payload version in our templates has proven to be unreliable. This updates the gen-templates script to pin all payload packages to the latest version - adds the missing `website` entry for our template variations, thus ensuring its lockfile gets updated - adds importmap generation to the gen-templates script - adds new `script:gen-templates:build` script to verify that all templates still build correctly
This commit is contained in:
@@ -20,9 +20,9 @@ import minimist from 'minimist'
|
||||
import * as fs from 'node:fs/promises'
|
||||
import path from 'path'
|
||||
|
||||
type TemplateVariations = {
|
||||
type TemplateVariation = {
|
||||
/** Base template to copy from */
|
||||
base?: string
|
||||
base?: 'none' | ({} & string)
|
||||
configureConfig?: boolean
|
||||
db: DbType
|
||||
/** Directory in templates dir */
|
||||
@@ -56,9 +56,11 @@ async function main() {
|
||||
const args = minimist(process.argv.slice(2))
|
||||
const template = args['template'] // template directory name
|
||||
|
||||
const shouldBuild = args['build']
|
||||
|
||||
const templateRepoUrlBase = `https://github.com/payloadcms/payload/tree/main/templates`
|
||||
|
||||
let variations: TemplateVariations[] = [
|
||||
let variations: TemplateVariation[] = [
|
||||
{
|
||||
name: 'payload-vercel-postgres-template',
|
||||
db: 'vercel-postgres',
|
||||
@@ -143,6 +145,21 @@ async function main() {
|
||||
// so we do not configure the payload.config.ts file, which leaves the placeholder comments.
|
||||
configureConfig: false,
|
||||
},
|
||||
{
|
||||
name: 'website',
|
||||
db: 'mongodb',
|
||||
dirname: 'website',
|
||||
generateLockfile: true,
|
||||
sharp: true,
|
||||
skipConfig: true, // Do not copy the payload.config.ts file from the base template
|
||||
storage: 'localDisk',
|
||||
// The blank template is used as a base for create-payload-app functionality,
|
||||
// so we do not configure the payload.config.ts file, which leaves the placeholder comments.
|
||||
configureConfig: false,
|
||||
base: 'none',
|
||||
skipDockerCompose: true,
|
||||
skipReadme: true,
|
||||
},
|
||||
]
|
||||
|
||||
// If template is set, only generate that template
|
||||
@@ -154,33 +171,37 @@ async function main() {
|
||||
variations = [variation]
|
||||
}
|
||||
|
||||
for (const {
|
||||
name,
|
||||
base,
|
||||
configureConfig,
|
||||
db,
|
||||
dirname,
|
||||
envNames,
|
||||
generateLockfile,
|
||||
sharp,
|
||||
skipConfig = false,
|
||||
skipDockerCompose = false,
|
||||
skipReadme = false,
|
||||
storage,
|
||||
vercelDeployButtonLink,
|
||||
} of variations) {
|
||||
for (const variation of variations) {
|
||||
const {
|
||||
name,
|
||||
base,
|
||||
configureConfig,
|
||||
db,
|
||||
dirname,
|
||||
envNames,
|
||||
generateLockfile,
|
||||
sharp,
|
||||
skipConfig = false,
|
||||
skipDockerCompose = false,
|
||||
skipReadme = false,
|
||||
storage,
|
||||
vercelDeployButtonLink,
|
||||
} = variation
|
||||
|
||||
header(`Generating ${name}...`)
|
||||
const destDir = path.join(TEMPLATES_DIR, dirname)
|
||||
copyRecursiveSync(path.join(TEMPLATES_DIR, base || '_template'), destDir, [
|
||||
'node_modules',
|
||||
'\\*\\.tgz',
|
||||
'.next',
|
||||
'.env$',
|
||||
'pnpm-lock.yaml',
|
||||
...(skipReadme ? ['README.md'] : []),
|
||||
...(skipDockerCompose ? ['docker-compose.yml'] : []),
|
||||
...(skipConfig ? ['payload.config.ts'] : []),
|
||||
])
|
||||
if (base !== 'none') {
|
||||
copyRecursiveSync(path.join(TEMPLATES_DIR, base || '_template'), destDir, [
|
||||
'node_modules',
|
||||
'\\*\\.tgz',
|
||||
'.next',
|
||||
'.env$',
|
||||
'pnpm-lock.yaml',
|
||||
...(skipReadme ? ['README.md'] : []),
|
||||
...(skipDockerCompose ? ['docker-compose.yml'] : []),
|
||||
...(skipConfig ? ['payload.config.ts'] : []),
|
||||
])
|
||||
}
|
||||
|
||||
log(`Copied to ${destDir}`)
|
||||
|
||||
@@ -217,6 +238,15 @@ async function main() {
|
||||
})
|
||||
}
|
||||
|
||||
// Fetch latest npm version of payload package:
|
||||
const version = await getLatestPayloadVersion()
|
||||
|
||||
// Bump package.json versions
|
||||
await bumpPackageJson({
|
||||
templateDir: destDir,
|
||||
latestVersion: version,
|
||||
})
|
||||
|
||||
if (generateLockfile) {
|
||||
log('Generating pnpm-lock.yaml')
|
||||
execSyncSafe(`pnpm install --ignore-workspace`, { cwd: destDir })
|
||||
@@ -254,6 +284,15 @@ async function main() {
|
||||
})
|
||||
}
|
||||
|
||||
// Generate importmap
|
||||
log('Generating import map')
|
||||
execSyncSafe(`pnpm --ignore-workspace generate:importmap`, { cwd: destDir })
|
||||
|
||||
if (shouldBuild) {
|
||||
log('Building...')
|
||||
execSyncSafe(`pnpm --ignore-workspace build`, { cwd: destDir })
|
||||
}
|
||||
|
||||
// TODO: Email?
|
||||
|
||||
// TODO: Sharp?
|
||||
@@ -271,7 +310,7 @@ async function generateReadme({
|
||||
destDir,
|
||||
}: {
|
||||
data: {
|
||||
attributes: Pick<TemplateVariations, 'db' | 'storage'>
|
||||
attributes: Pick<TemplateVariation, 'db' | 'storage'>
|
||||
description: string
|
||||
name: string
|
||||
vercelDeployButtonLink?: string
|
||||
@@ -305,7 +344,7 @@ async function writeEnvExample({
|
||||
}: {
|
||||
dbType: DbType
|
||||
destDir: string
|
||||
envNames?: TemplateVariations['envNames']
|
||||
envNames?: TemplateVariation['envNames']
|
||||
}) {
|
||||
const envExamplePath = path.join(destDir, '.env.example')
|
||||
const envFileContents = await fs.readFile(envExamplePath, 'utf8')
|
||||
@@ -378,3 +417,48 @@ function execSyncSafe(command: string, options?: Parameters<typeof execSync>[1])
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const DO_NOT_BUMP = ['@payloadcms/eslint-config', '@payloadcms/eslint-plugin']
|
||||
async function bumpPackageJson({
|
||||
templateDir,
|
||||
latestVersion,
|
||||
}: {
|
||||
templateDir: string
|
||||
latestVersion: string
|
||||
}) {
|
||||
const packageJsonString = await fs.readFile(path.resolve(templateDir, 'package.json'), 'utf8')
|
||||
const packageJson = JSON.parse(packageJsonString)
|
||||
|
||||
for (const key of ['dependencies', 'devDependencies']) {
|
||||
const dependencies = packageJson[key]
|
||||
if (dependencies) {
|
||||
for (const [packageName, _packageVersion] of Object.entries(dependencies)) {
|
||||
if (
|
||||
(packageName === 'payload' || packageName.startsWith('@payloadcms')) &&
|
||||
!DO_NOT_BUMP.includes(packageName)
|
||||
) {
|
||||
dependencies[packageName] = latestVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write it out
|
||||
await fs.writeFile(
|
||||
path.resolve(templateDir, 'package.json'),
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
)
|
||||
}
|
||||
|
||||
async function getLatestPayloadVersion() {
|
||||
try {
|
||||
const response = await fetch('https://registry.npmjs.org/payload')
|
||||
const data = await response.json()
|
||||
const latestVersion = data['dist-tags'].latest
|
||||
|
||||
return latestVersion
|
||||
} catch (error) {
|
||||
console.error('Error fetching Payload version:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user