fix: get auto type-gen to work on turbo, by running type gen in a child process outside turbo/webpack (#6714)
Before on turbo: https://github.com/vercel/next.js/issues/66723
This commit is contained in:
@@ -2,7 +2,6 @@ import type { GeneratedTypes, Payload } from 'payload'
|
|||||||
import type { InitOptions, SanitizedConfig } from 'payload/config'
|
import type { InitOptions, SanitizedConfig } from 'payload/config'
|
||||||
|
|
||||||
import { BasePayload } from 'payload'
|
import { BasePayload } from 'payload'
|
||||||
import { generateTypes } from 'payload/bin'
|
|
||||||
import WebSocket from 'ws'
|
import WebSocket from 'ws'
|
||||||
|
|
||||||
let cached: {
|
let cached: {
|
||||||
@@ -39,7 +38,12 @@ export const reload = async (config: SanitizedConfig, payload: Payload): Promise
|
|||||||
|
|
||||||
// Generate types
|
// Generate types
|
||||||
if (config.typescript.autoGenerate !== false) {
|
if (config.typescript.autoGenerate !== false) {
|
||||||
void generateTypes(config, { log: false })
|
// We cannot run it directly here, as generate-types imports json-schema-to-typescript, which breaks on turbopack.
|
||||||
|
// see: https://github.com/vercel/next.js/issues/66723
|
||||||
|
void payload.bin({
|
||||||
|
args: ['generate:types'],
|
||||||
|
log: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
await payload.db.init()
|
await payload.db.init()
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ export const withPayload = (nextConfig = {}) => {
|
|||||||
'pino',
|
'pino',
|
||||||
'pino-pretty',
|
'pino-pretty',
|
||||||
'graphql',
|
'graphql',
|
||||||
'json-schema-to-typescript',
|
|
||||||
],
|
],
|
||||||
webpack: (webpackConfig, webpackOptions) => {
|
webpack: (webpackConfig, webpackOptions) => {
|
||||||
const incomingWebpackConfig =
|
const incomingWebpackConfig =
|
||||||
@@ -84,7 +83,6 @@ export const withPayload = (nextConfig = {}) => {
|
|||||||
'drizzle-kit/payload',
|
'drizzle-kit/payload',
|
||||||
'sharp',
|
'sharp',
|
||||||
'libsql',
|
'libsql',
|
||||||
'json-schema-to-typescript',
|
|
||||||
],
|
],
|
||||||
ignoreWarnings: [
|
ignoreWarnings: [
|
||||||
...(incomingWebpackConfig?.ignoreWarnings || []),
|
...(incomingWebpackConfig?.ignoreWarnings || []),
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ const componentWebpackConfig = {
|
|||||||
'payload/config',
|
'payload/config',
|
||||||
'react-image-crop',
|
'react-image-crop',
|
||||||
'payload/operations',
|
'payload/operations',
|
||||||
'payload/bin',
|
|
||||||
],
|
],
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
module: {
|
module: {
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import { register } from 'node:module'
|
|||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import { fileURLToPath, pathToFileURL } from 'node:url'
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
||||||
|
|
||||||
import { bin } from './dist/bin/index.js'
|
|
||||||
|
|
||||||
// Allow disabling SWC for debugging
|
// Allow disabling SWC for debugging
|
||||||
if (process.env.DISABLE_SWC !== 'true') {
|
if (process.env.DISABLE_SWC !== 'true') {
|
||||||
const filename = fileURLToPath(import.meta.url)
|
const filename = fileURLToPath(import.meta.url)
|
||||||
@@ -15,4 +13,9 @@ if (process.env.DISABLE_SWC !== 'true') {
|
|||||||
register('./dist/bin/loader/index.js', url)
|
register('./dist/bin/loader/index.js', url)
|
||||||
}
|
}
|
||||||
|
|
||||||
bin()
|
const start = async () => {
|
||||||
|
const { bin } = await import('./dist/bin/index.js')
|
||||||
|
bin()
|
||||||
|
}
|
||||||
|
|
||||||
|
void start()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { findUpSync, pathExistsSync } from 'find-up'
|
import { findUpSync, pathExistsSync } from 'find-up'
|
||||||
import fs from 'fs'
|
import { getTsconfig } from 'get-tsconfig'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -12,37 +12,30 @@ const getTSConfigPaths = (): {
|
|||||||
outPath?: string
|
outPath?: string
|
||||||
rootPath?: string
|
rootPath?: string
|
||||||
srcPath?: string
|
srcPath?: string
|
||||||
|
tsConfigPath?: string
|
||||||
} => {
|
} => {
|
||||||
const tsConfigPath = findUpSync('tsconfig.json')
|
const tsConfigResult = getTsconfig()
|
||||||
|
const tsConfig = tsConfigResult.config
|
||||||
if (!tsConfigPath) {
|
const tsConfigDir = path.dirname(tsConfigResult.path)
|
||||||
return {
|
|
||||||
rootPath: process.cwd(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Read the file as a string and remove trailing commas
|
const rootConfigDir = path.resolve(tsConfigDir, tsConfig.compilerOptions.baseUrl || '')
|
||||||
const rawTsConfig = fs
|
|
||||||
.readFileSync(tsConfigPath, 'utf-8')
|
|
||||||
.replace(/,\s*\]/g, ']')
|
|
||||||
.replace(/,\s*\}/g, '}')
|
|
||||||
|
|
||||||
const tsConfig = JSON.parse(rawTsConfig)
|
|
||||||
|
|
||||||
const rootPath = process.cwd()
|
|
||||||
const srcPath = tsConfig.compilerOptions?.rootDir || path.resolve(process.cwd(), 'src')
|
const srcPath = tsConfig.compilerOptions?.rootDir || path.resolve(process.cwd(), 'src')
|
||||||
const outPath = tsConfig.compilerOptions?.outDir || path.resolve(process.cwd(), 'dist')
|
const outPath = tsConfig.compilerOptions?.outDir || path.resolve(process.cwd(), 'dist')
|
||||||
const tsConfigDir = path.dirname(tsConfigPath)
|
let configPath = path.resolve(
|
||||||
let configPath = tsConfig.compilerOptions?.paths?.['@payload-config']?.[0]
|
rootConfigDir,
|
||||||
|
tsConfig.compilerOptions?.paths?.['@payload-config']?.[0],
|
||||||
|
)
|
||||||
|
|
||||||
if (configPath) {
|
if (configPath) {
|
||||||
configPath = path.resolve(tsConfigDir, configPath)
|
configPath = path.resolve(rootConfigDir, configPath)
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
configPath,
|
configPath,
|
||||||
outPath,
|
outPath,
|
||||||
rootPath,
|
rootPath: rootConfigDir,
|
||||||
srcPath,
|
srcPath,
|
||||||
|
tsConfigPath: tsConfigResult.path,
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error parsing tsconfig.json: ${error}`) // Do not throw the error, as we can still continue with the other config path finding methods
|
console.error(`Error parsing tsconfig.json: ${error}`) // Do not throw the error, as we can still continue with the other config path finding methods
|
||||||
@@ -70,6 +63,11 @@ export const findConfig = (): string => {
|
|||||||
|
|
||||||
const { configPath, outPath, rootPath, srcPath } = getTSConfigPaths()
|
const { configPath, outPath, rootPath, srcPath } = getTSConfigPaths()
|
||||||
|
|
||||||
|
// if configPath is absolute file, not folder, return it
|
||||||
|
if (path.extname(configPath) === '.js' || path.extname(configPath) === '.ts') {
|
||||||
|
return configPath
|
||||||
|
}
|
||||||
|
|
||||||
const searchPaths =
|
const searchPaths =
|
||||||
process.env.NODE_ENV === 'production'
|
process.env.NODE_ENV === 'production'
|
||||||
? [configPath, outPath, srcPath, rootPath]
|
? [configPath, outPath, srcPath, rootPath]
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
/**
|
|
||||||
* WARNING: This file contains exports that can only be safely used on the server.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export { generateTypes } from '../bin/generateTypes.js'
|
|
||||||
@@ -2,7 +2,10 @@ import type { ExecutionResult, GraphQLSchema, ValidationRule } from 'graphql'
|
|||||||
import type { OperationArgs, Request as graphQLRequest } from 'graphql-http'
|
import type { OperationArgs, Request as graphQLRequest } from 'graphql-http'
|
||||||
import type pino from 'pino'
|
import type pino from 'pino'
|
||||||
|
|
||||||
|
import { spawn } from 'child_process'
|
||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
import type { AuthArgs } from './auth/operations/auth.js'
|
import type { AuthArgs } from './auth/operations/auth.js'
|
||||||
import type { Result as ForgotPasswordResult } from './auth/operations/forgotPassword.js'
|
import type { Result as ForgotPasswordResult } from './auth/operations/forgotPassword.js'
|
||||||
@@ -47,7 +50,6 @@ import type { TypeWithVersion } from './versions/types.js'
|
|||||||
import { decrypt, encrypt } from './auth/crypto.js'
|
import { decrypt, encrypt } from './auth/crypto.js'
|
||||||
import { APIKeyAuthentication } from './auth/strategies/apiKey.js'
|
import { APIKeyAuthentication } from './auth/strategies/apiKey.js'
|
||||||
import { JWTAuthentication } from './auth/strategies/jwt.js'
|
import { JWTAuthentication } from './auth/strategies/jwt.js'
|
||||||
import { generateTypes } from './bin/generateTypes.js'
|
|
||||||
import localOperations from './collections/operations/local/index.js'
|
import localOperations from './collections/operations/local/index.js'
|
||||||
import { validateSchema } from './config/validate.js'
|
import { validateSchema } from './config/validate.js'
|
||||||
import { consoleEmailAdapter } from './email/consoleEmailAdapter.js'
|
import { consoleEmailAdapter } from './email/consoleEmailAdapter.js'
|
||||||
@@ -57,6 +59,9 @@ import flattenFields from './utilities/flattenTopLevelFields.js'
|
|||||||
import Logger from './utilities/logger.js'
|
import Logger from './utilities/logger.js'
|
||||||
import { serverInit as serverInitTelemetry } from './utilities/telemetry/events/serverInit.js'
|
import { serverInit as serverInitTelemetry } from './utilities/telemetry/events/serverInit.js'
|
||||||
|
|
||||||
|
const filename = fileURLToPath(import.meta.url)
|
||||||
|
const dirname = path.dirname(filename)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Payload
|
* @description Payload
|
||||||
*/
|
*/
|
||||||
@@ -302,6 +307,31 @@ export class BasePayload<TGeneratedTypes extends GeneratedTypes> {
|
|||||||
[slug: string]: any // TODO: Type this
|
[slug: string]: any // TODO: Type this
|
||||||
} = {}
|
} = {}
|
||||||
|
|
||||||
|
async bin({
|
||||||
|
args,
|
||||||
|
cwd,
|
||||||
|
log,
|
||||||
|
}: {
|
||||||
|
args: string[]
|
||||||
|
cwd?: string
|
||||||
|
log?: boolean
|
||||||
|
}): Promise<{ code: number }> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const spawned = spawn('node', [path.resolve(dirname, '../bin.js'), ...args], {
|
||||||
|
cwd,
|
||||||
|
stdio: log || log === undefined ? 'inherit' : 'ignore',
|
||||||
|
})
|
||||||
|
|
||||||
|
spawned.on('exit', (code) => {
|
||||||
|
resolve({ code })
|
||||||
|
})
|
||||||
|
|
||||||
|
spawned.on('error', (error) => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description delete one or more documents
|
* @description delete one or more documents
|
||||||
* @param options
|
* @param options
|
||||||
@@ -366,7 +396,12 @@ export class BasePayload<TGeneratedTypes extends GeneratedTypes> {
|
|||||||
|
|
||||||
// Generate types on startup
|
// Generate types on startup
|
||||||
if (process.env.NODE_ENV !== 'production' && this.config.typescript.autoGenerate !== false) {
|
if (process.env.NODE_ENV !== 'production' && this.config.typescript.autoGenerate !== false) {
|
||||||
void generateTypes(this.config, { log: false })
|
// We cannot run it directly here, as generate-types imports json-schema-to-typescript, which breaks on turbopack.
|
||||||
|
// see: https://github.com/vercel/next.js/issues/66723
|
||||||
|
void this.bin({
|
||||||
|
args: ['generate:types'],
|
||||||
|
log: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.db = this.config.db.init({ payload: this })
|
this.db = this.config.db.init({ payload: this })
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export const createTestHooks = async (testSuiteName = '_community') => {
|
|||||||
tsConfig.compilerOptions.paths['@payload-config'] = [`./test/${testSuiteName}/config.ts`]
|
tsConfig.compilerOptions.paths['@payload-config'] = [`./test/${testSuiteName}/config.ts`]
|
||||||
await writeFile(tsConfigPath, stringify(tsConfig, null, 2) + '\n')
|
await writeFile(tsConfigPath, stringify(tsConfig, null, 2) + '\n')
|
||||||
|
|
||||||
process.env.PAYLOAD_CONFIG_PATH = path.resolve(testSuiteName, 'config')
|
process.env.PAYLOAD_CONFIG_PATH = path.resolve(dirname, testSuiteName, 'config.ts')
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user