chore: server hmr
This commit is contained in:
@@ -6,7 +6,14 @@ import mongoose from 'mongoose'
|
||||
|
||||
import type { MongooseAdapter } from '.'
|
||||
|
||||
export const connect: Connect = async function connect(this: MongooseAdapter) {
|
||||
export const connect: Connect = async function connect(
|
||||
this: MongooseAdapter,
|
||||
options = {
|
||||
hotReload: false,
|
||||
},
|
||||
) {
|
||||
const { hotReload } = options
|
||||
|
||||
if (this.url === false) {
|
||||
return
|
||||
}
|
||||
@@ -24,6 +31,8 @@ export const connect: Connect = async function connect(this: MongooseAdapter) {
|
||||
useFacet: undefined,
|
||||
}
|
||||
|
||||
if (hotReload) connectionOptions.autoIndex = false
|
||||
|
||||
try {
|
||||
this.connection = (await mongoose.connect(urlToConnect, connectionOptions)).connection
|
||||
|
||||
@@ -34,12 +43,15 @@ export const connect: Connect = async function connect(this: MongooseAdapter) {
|
||||
this.beginTransaction = undefined
|
||||
}
|
||||
|
||||
if (process.env.PAYLOAD_DROP_DATABASE === 'true') {
|
||||
this.payload.logger.info('---- DROPPING DATABASE ----')
|
||||
await mongoose.connection.dropDatabase()
|
||||
this.payload.logger.info('---- DROPPED DATABASE ----')
|
||||
if (!hotReload) {
|
||||
if (process.env.PAYLOAD_DROP_DATABASE === 'true') {
|
||||
this.payload.logger.info('---- DROPPING DATABASE ----')
|
||||
await mongoose.connection.dropDatabase()
|
||||
this.payload.logger.info('---- DROPPED DATABASE ----')
|
||||
}
|
||||
|
||||
this.payload.logger.info(successfulConnectionMessage)
|
||||
}
|
||||
this.payload.logger.info(successfulConnectionMessage)
|
||||
} catch (err) {
|
||||
this.payload.logger.error(`Error: cannot connect to MongoDB. Details: ${err.message}`, err)
|
||||
process.exit(1)
|
||||
|
||||
@@ -10,6 +10,7 @@ export const destroy: Destroy = async function destroy(this: MongooseAdapter) {
|
||||
await mongoose.connection.close()
|
||||
await this.mongoMemoryServer.stop()
|
||||
} else {
|
||||
await mongoose.connection.close()
|
||||
await mongoose.disconnect()
|
||||
}
|
||||
Object.keys(mongoose.models).map((model) => mongoose.deleteModel(model))
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import { buildGlobalModel } from './models/buildGlobalModel'
|
||||
import buildSchema from './models/buildSchema'
|
||||
import getBuildQueryPlugin from './queries/buildQuery'
|
||||
|
||||
export const init: Init = async function init(this: MongooseAdapter) {
|
||||
export const init: Init = function init(this: MongooseAdapter) {
|
||||
this.payload.config.collections.forEach((collection: SanitizedCollectionConfig) => {
|
||||
const schema = buildCollectionSchema(collection, this.payload.config)
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
"@payloadcms/eslint-config": "workspace:*",
|
||||
"@types/react": "18.2.15",
|
||||
"@types/react-dom": "18.2.7",
|
||||
"@types/ws": "^8.5.10",
|
||||
"css-loader": "^6.10.0",
|
||||
"css-minimizer-webpack-plugin": "^6.0.0",
|
||||
"file-loader": "6.2.0",
|
||||
@@ -78,7 +79,8 @@
|
||||
"path-to-regexp": "^6.2.1",
|
||||
"react-diff-viewer-continued": "3.2.6",
|
||||
"react-toastify": "8.2.0",
|
||||
"sass": "^1.71.1"
|
||||
"sass": "^1.71.1",
|
||||
"ws": "^8.16.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"http-status": "1.6.2",
|
||||
|
||||
@@ -7,13 +7,13 @@ import type {
|
||||
|
||||
import { initI18n } from '@payloadcms/translations'
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
import { getPayload } from 'payload'
|
||||
import { getAuthenticatedUser } from 'payload/auth'
|
||||
import { parseCookies } from 'payload/auth'
|
||||
import { getDataLoader } from 'payload/utilities'
|
||||
import { URL } from 'url'
|
||||
|
||||
import { getDataAndFile } from './getDataAndFile'
|
||||
import { getPayload } from './getPayload'
|
||||
import { getRequestLanguage } from './getRequestLanguage'
|
||||
import { getRequestLocales } from './getRequestLocales'
|
||||
|
||||
@@ -32,6 +32,7 @@ export const createPayloadRequest = async ({
|
||||
}: Args): Promise<PayloadRequest> => {
|
||||
const cookies = parseCookies(request.headers)
|
||||
const payload = await getPayload({ config: configPromise })
|
||||
|
||||
const { collections, config } = payload
|
||||
|
||||
let collection: Collection = undefined
|
||||
|
||||
72
packages/next/src/utilities/getPayload.ts
Normal file
72
packages/next/src/utilities/getPayload.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import type { GeneratedTypes, Payload } from 'payload'
|
||||
import type { InitOptions } from 'payload/config'
|
||||
|
||||
import { BasePayload } from 'payload'
|
||||
import WebSocket from 'ws'
|
||||
|
||||
let cached = global._payload
|
||||
|
||||
if (!cached) {
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
cached = global._payload = { payload: null, promise: null }
|
||||
}
|
||||
|
||||
export const getPayload = async (options: InitOptions): Promise<Payload> => {
|
||||
if (cached.payload) {
|
||||
const config = await options.config
|
||||
|
||||
if (cached.reload) {
|
||||
if (typeof cached.payload.db.destroy === 'function') {
|
||||
await cached.payload.db.destroy()
|
||||
}
|
||||
|
||||
cached.payload.config = config
|
||||
|
||||
cached.payload.collections = config.collections.reduce((collections, collection) => {
|
||||
collections[collection.slug] = { config: collection }
|
||||
return collections
|
||||
}, {})
|
||||
|
||||
// TODO: re-build payload.globals as well as any other properties
|
||||
// that may change on Payload singleton
|
||||
|
||||
await cached.payload.db.init()
|
||||
await cached.payload.db.connect({ hotReload: true })
|
||||
cached.reload = false
|
||||
}
|
||||
|
||||
return cached.payload
|
||||
}
|
||||
|
||||
if (!cached.promise) {
|
||||
cached.promise = new BasePayload<GeneratedTypes>().init(options)
|
||||
}
|
||||
|
||||
try {
|
||||
cached.payload = await cached.promise
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
try {
|
||||
const ws = new WebSocket('ws://localhost:3000/_next/webpack-hmr')
|
||||
|
||||
ws.onmessage = async (event) => {
|
||||
if (typeof event.data === 'string') {
|
||||
const data = JSON.parse(event.data)
|
||||
|
||||
if ('action' in data && data.action === 'serverComponentChanges') {
|
||||
console.log(data)
|
||||
cached.reload = true
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// swallow e
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
cached.promise = null
|
||||
throw e
|
||||
}
|
||||
|
||||
return cached.payload
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import { findLocaleFromCode } from '@payloadcms/ui'
|
||||
import { headers as getHeaders } from 'next/headers'
|
||||
import { redirect } from 'next/navigation'
|
||||
import { getPayload } from 'payload'
|
||||
import { parseCookies } from 'payload/auth'
|
||||
import { createLocalReq } from 'payload/utilities'
|
||||
import qs from 'qs'
|
||||
|
||||
@@ -29,25 +30,27 @@ type Args = {
|
||||
}
|
||||
|
||||
export const initPage = async ({
|
||||
config: configPromise,
|
||||
config,
|
||||
localeParam,
|
||||
redirectUnauthenticatedUser = false,
|
||||
route,
|
||||
searchParams,
|
||||
}: Args): Promise<InitPageResult> => {
|
||||
const headers = getHeaders()
|
||||
const cookies = parseCookies(headers)
|
||||
|
||||
const { cookies, permissions, user } = await auth({
|
||||
config: configPromise,
|
||||
const payload = await getPayload({ config })
|
||||
|
||||
const { permissions, user } = await auth({
|
||||
headers,
|
||||
payload,
|
||||
})
|
||||
|
||||
const config = await configPromise
|
||||
const routeSegments = route.replace(config.routes.admin, '').split('/').filter(Boolean)
|
||||
const routeSegments = route.replace(payload.config.routes.admin, '').split('/').filter(Boolean)
|
||||
const collectionSlug = routeSegments[0] === 'collections' ? routeSegments[1] : undefined
|
||||
const globalSlug = routeSegments[0] === 'globals' ? routeSegments[1] : undefined
|
||||
|
||||
const { collections, globals, localization, routes } = config
|
||||
const { collections, globals, localization, routes } = payload.config
|
||||
|
||||
if (redirectUnauthenticatedUser && !user && route !== '/login') {
|
||||
const stringifiedSearchParams = Object.keys(searchParams ?? {}).length
|
||||
@@ -57,15 +60,14 @@ export const initPage = async ({
|
||||
redirect(`${routes.admin}/login?redirect=${route + stringifiedSearchParams}`)
|
||||
}
|
||||
|
||||
const payload = await getPayload({ config })
|
||||
|
||||
const defaultLocale =
|
||||
localization && localization.defaultLocale ? localization.defaultLocale : 'en'
|
||||
const localeCode = localeParam || defaultLocale
|
||||
const locale = localization && findLocaleFromCode(localization, localeCode)
|
||||
const language = getRequestLanguage({ cookies, headers })
|
||||
|
||||
const i18n = initI18n({
|
||||
config: config.i18n,
|
||||
config: payload.config.i18n,
|
||||
context: 'client',
|
||||
language,
|
||||
translations,
|
||||
@@ -96,9 +98,11 @@ export const initPage = async ({
|
||||
|
||||
return {
|
||||
collectionConfig,
|
||||
cookies,
|
||||
globalConfig,
|
||||
locale,
|
||||
permissions,
|
||||
req,
|
||||
translations: i18n.translations,
|
||||
}
|
||||
}
|
||||
|
||||
5
packages/next/src/utilities/timestamp.ts
Normal file
5
packages/next/src/utilities/timestamp.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export const timestamp = (label: string) => {
|
||||
if (!process.env.PAYLOAD_TIME) process.env.PAYLOAD_TIME = String(new Date().getTime())
|
||||
const now = new Date()
|
||||
console.log(`[${now.getTime() - Number(process.env.PAYLOAD_TIME)}ms] ${label}`)
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { Translations } from '@payloadcms/translations'
|
||||
|
||||
import type { DocumentPermissions, Permissions, User } from '../../auth'
|
||||
import type { SanitizedCollectionConfig } from '../../collections/config/types'
|
||||
import type { SanitizedGlobalConfig } from '../../globals/config/types'
|
||||
@@ -30,10 +32,12 @@ export type EditViewProps = {
|
||||
|
||||
export type InitPageResult = {
|
||||
collectionConfig?: SanitizedCollectionConfig
|
||||
cookies: Map<string, string>
|
||||
globalConfig?: SanitizedGlobalConfig
|
||||
locale: Locale
|
||||
permissions: Permissions
|
||||
req: PayloadRequest
|
||||
translations: Translations
|
||||
}
|
||||
|
||||
export type ServerSideEditViewProps = EditViewProps & {
|
||||
|
||||
@@ -130,9 +130,13 @@ export interface BaseDatabaseAdapter {
|
||||
updateVersion: UpdateVersion
|
||||
}
|
||||
|
||||
export type Init = (payload: Payload) => Promise<void>
|
||||
export type Init = (payload: Payload) => Promise<void> | void
|
||||
|
||||
export type Connect = (payload: Payload) => Promise<void>
|
||||
type ConnectArgs = {
|
||||
hotReload: boolean
|
||||
}
|
||||
|
||||
export type Connect = (args?: ConnectArgs) => Promise<void>
|
||||
|
||||
export type Destroy = (payload: Payload) => Promise<void>
|
||||
|
||||
|
||||
@@ -316,6 +316,7 @@ export class BasePayload<TGeneratedTypes extends GeneratedTypes> {
|
||||
this.globals = {
|
||||
config: this.config.globals,
|
||||
}
|
||||
|
||||
this.config.collections.forEach((collection) => {
|
||||
this.collections[collection.slug] = {
|
||||
config: collection,
|
||||
@@ -330,7 +331,7 @@ export class BasePayload<TGeneratedTypes extends GeneratedTypes> {
|
||||
}
|
||||
|
||||
if (!options.disableDBConnect && this.db.connect) {
|
||||
await this.db.connect(this)
|
||||
await this.db.connect()
|
||||
}
|
||||
|
||||
this.logger.info('Starting Payload...')
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
export type LanguageTranslations = {
|
||||
[namespace: string]: {
|
||||
[key: string]: string
|
||||
}
|
||||
}
|
||||
|
||||
export type Translations = {
|
||||
[language: string]:
|
||||
| {
|
||||
$schema: string
|
||||
}
|
||||
| {
|
||||
[namespace: string]: {
|
||||
[key: string]: string
|
||||
}
|
||||
}
|
||||
| LanguageTranslations
|
||||
}
|
||||
|
||||
export type TFunction = (key: string, options?: Record<string, any>) => string
|
||||
@@ -19,6 +21,7 @@ export type I18n = {
|
||||
language: string
|
||||
/** Translate function */
|
||||
t: (key: string, options?: Record<string, unknown>) => string
|
||||
translations: Translations
|
||||
}
|
||||
|
||||
export type I18nOptions = {
|
||||
@@ -29,11 +32,7 @@ export type I18nOptions = {
|
||||
| {
|
||||
$schema: string
|
||||
}
|
||||
| {
|
||||
[namespace: string]: {
|
||||
[key: string]: string
|
||||
}
|
||||
}
|
||||
| LanguageTranslations
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +40,10 @@ export type InitTFunction = (args: {
|
||||
config: I18nOptions
|
||||
language?: string
|
||||
translations?: Translations
|
||||
}) => TFunction
|
||||
}) => {
|
||||
t: TFunction
|
||||
translations: Translations
|
||||
}
|
||||
|
||||
export type InitI18n = (args: {
|
||||
config: I18nOptions
|
||||
|
||||
Reference in New Issue
Block a user