Skip to content

Commit c6b3bef

Browse files
authored
feat(config): enable watch for all layer configs and load in parallel (#2929)
1 parent c2c98d8 commit c6b3bef

File tree

3 files changed

+34
-41
lines changed

3 files changed

+34
-41
lines changed

src/module.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import { generateCollectionInsert, generateCollectionTableDefinition } from './u
2222
import { componentsManifestTemplate, contentTypesTemplate, fullDatabaseRawDumpTemplate, manifestTemplate, moduleTemplates } from './utils/templates'
2323
import type { ResolvedCollection } from './types/collection'
2424
import type { ModuleOptions, SqliteDatabaseConfig } from './types/module'
25-
import { getContentChecksum, localDatabase, logger, watchContents, chunks, watchComponents, watchConfig, startSocketServer } from './utils/dev'
26-
import { loadLayersConfig } from './utils/config'
25+
import { getContentChecksum, localDatabase, logger, watchContents, chunks, watchComponents, startSocketServer } from './utils/dev'
26+
import { loadContentConfig } from './utils/config'
2727
import { createParser } from './utils/content'
2828
import { installMDCModule } from './utils/mdc'
2929
import { findPreset } from './presets'
@@ -104,7 +104,7 @@ export default defineNuxtModule<ModuleOptions>({
104104
await mkdir(dirname((options.database as SqliteDatabaseConfig).filename), { recursive: true }).catch(() => {})
105105
}
106106

107-
const { collections } = await loadLayersConfig(nuxt)
107+
const { collections } = await loadContentConfig(nuxt)
108108
manifest.collections = collections
109109

110110
// Module Options
@@ -213,7 +213,6 @@ export default defineNuxtModule<ModuleOptions>({
213213
if (nuxt.options.dev) {
214214
addPlugin({ src: resolver.resolve('./runtime/plugins/websocket.dev'), mode: 'client' })
215215
await watchComponents(nuxt)
216-
await watchConfig(nuxt)
217216
const socket = await startSocketServer(nuxt, options, manifest)
218217
dumpGeneratePromise.then(async () => {
219218
await watchContents(nuxt, options, manifest, socket)

src/utils/config.ts

+29-36
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import { stat } from 'node:fs/promises'
2-
import { loadConfig, createDefineConfig } from 'c12'
1+
import { loadConfig, watchConfig, createDefineConfig } from 'c12'
2+
import { relative } from 'pathe'
33
import type { Nuxt } from '@nuxt/schema'
4-
import { join } from 'pathe'
5-
import type { ResolvedCollection, DefinedCollection } from '../types'
4+
import type { DefinedCollection } from '../types'
65
import { defineCollection, resolveCollections } from './collection'
76
import { logger } from './dev'
87

@@ -21,47 +20,41 @@ const defaultConfig: NuxtContentConfig = {
2120

2221
export const defineContentConfig = createDefineConfig<NuxtContentConfig>()
2322

24-
export async function loadContentConfig(rootDir: string, opts: { defaultFallback?: boolean } = {}) {
23+
export async function loadContentConfig(nuxt: Nuxt, options: { defaultFallback?: boolean } = {}) {
24+
const loader: typeof watchConfig = nuxt.options.dev
25+
? opts => watchConfig({
26+
...opts,
27+
onWatch: (e) => {
28+
logger.info(relative(nuxt.options.rootDir, e.path) + ' ' + e.type + ', restarting the Nuxt server...')
29+
nuxt.hooks.callHook('restart', { hard: true })
30+
},
31+
})
32+
: loadConfig as typeof watchConfig;
33+
2534
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2635
(globalThis as any).defineContentConfig = (c: any) => c
27-
const { config, configFile } = await loadConfig<NuxtContentConfig>({ name: 'content', cwd: rootDir })
36+
37+
const contentConfigs = await Promise.all(
38+
nuxt.options._layers.reverse().map(
39+
layer => loader<NuxtContentConfig>({ name: 'content', cwd: layer.config.rootDir, defaultConfig: options.defaultFallback ? defaultConfig : undefined }),
40+
),
41+
)
42+
2843
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2944
delete (globalThis as any).defineContentConfig
3045

31-
if ((!configFile || configFile === 'content.config') && opts.defaultFallback) {
32-
logger.warn('`content.config.ts` is not found, falling back to default collection. In order to have full control over your collections, create the config file in project root. See: https://content.nuxt.com/getting-started/installation')
33-
return {
34-
collections: resolveCollections(defaultConfig.collections),
35-
}
46+
if (nuxt.options.dev) {
47+
nuxt.hook('close', () => Promise.all(contentConfigs.map(c => c.unwatch())).then(() => {}))
3648
}
3749

38-
return {
39-
collections: resolveCollections(config.collections || {}),
40-
}
41-
}
50+
const collectionsConfig = contentConfigs.reduce((acc, curr) => ({ ...acc, ...curr.config?.collections }), {} as Record<string, DefinedCollection>)
51+
const hasNoCollections = Object.keys(collectionsConfig || {}).length === 0
4252

43-
export async function loadLayersConfig(nuxt: Nuxt) {
44-
const collectionMap = {} as Record<string, ResolvedCollection>
45-
const _layers = [...nuxt.options._layers].reverse()
46-
for (const layer of _layers) {
47-
const rootDir = layer.config.rootDir
48-
const configStat = await stat(join(rootDir, 'content.config.ts')).catch(() => null)
49-
if (configStat && configStat.isFile()) {
50-
const { collections } = await loadContentConfig(rootDir, { defaultFallback: false })
51-
for (const collection of collections) {
52-
collectionMap[collection.name] = collection
53-
}
54-
}
53+
if (hasNoCollections) {
54+
logger.warn('No content configuration found, falling back to default collection. In order to have full control over your collections, create the config file in project root. See: https://content.nuxt.com/getting-started/installation')
5555
}
5656

57-
if (Object.keys(collectionMap).length === 0) {
58-
const collections = resolveCollections(defaultConfig.collections)
59-
for (const collection of collections) {
60-
collectionMap[collection.name] = collection
61-
}
62-
}
57+
const collections = resolveCollections(hasNoCollections ? defaultConfig.collections : collectionsConfig)
6358

64-
return {
65-
collections: Object.values(collectionMap),
66-
}
59+
return { collections }
6760
}

test/base.test.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { fileURLToPath } from 'node:url'
22
import fs from 'node:fs/promises'
33
import { setup, $fetch } from '@nuxt/test-utils'
4+
import type { Nuxt } from '@nuxt/schema'
45
import { afterAll, describe, expect, test } from 'vitest'
56
import { loadContentConfig } from '../src/utils/config'
67
import { decompressSQLDump } from '../src/runtime/internal/dump'
@@ -33,7 +34,7 @@ describe('empty', async () => {
3334
})
3435
test('Default collection is defined', async () => {
3536
const rootDir = fileURLToPath(new URL('./fixtures/empty', import.meta.url))
36-
const config = await loadContentConfig(rootDir, { defaultFallback: true })
37+
const config = await loadContentConfig({ options: { _layers: [{ config: { rootDir } }] } } as Nuxt, { defaultFallback: true })
3738

3839
// Pages collection + info collection
3940
expect(config.collections.length).toBe(2)

0 commit comments

Comments
 (0)