Skip to content

Commit c5b1a4f

Browse files
committed
feat(watch): watch for cahnges in all local sources
1 parent 5810fc6 commit c5b1a4f

File tree

2 files changed

+46
-28
lines changed

2 files changed

+46
-28
lines changed

src/module.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ 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 } from './utils/dev'
25+
import { getContentChecksum, localDatabase, logger, watchContents, chunks, watchComponents, watchConfig, startSocketServer } from './utils/dev'
2626
import { loadLayersConfig } from './utils/config'
2727
import { parseContent } from './utils/content'
2828
import { installMDCModule } from './utils/mdc'
@@ -211,9 +211,12 @@ export default defineNuxtModule<ModuleOptions>({
211211
// Handle HMR changes
212212
if (nuxt.options.dev) {
213213
addPlugin({ src: resolver.resolve('./runtime/plugins/websocket.dev'), mode: 'client' })
214-
await watchContents(nuxt, options, manifest)
215214
await watchComponents(nuxt)
216215
await watchConfig(nuxt)
216+
const socket = await startSocketServer(nuxt, options, manifest)
217+
dumpGeneratePromise.then(async () => {
218+
await watchContents(nuxt, options, manifest, socket)
219+
})
217220
}
218221

219222
// Handle Studio mode

src/utils/dev.ts

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import micromatch from 'micromatch'
1111
import type { WebSocket } from 'ws'
1212
import { WebSocketServer } from 'ws'
1313
import { listen, type Listener } from 'listhen'
14+
import { withTrailingSlash } from 'ufo'
1415
import type { ModuleOptions, ResolvedCollection } from '../types'
1516
import type { Manifest } from '../types/manifest'
1617
import { generateCollectionInsert } from './collection'
@@ -20,23 +21,8 @@ import { parseSourceBase } from './source'
2021

2122
export const logger: ConsolaInstance = useLogger('@nuxt/content')
2223

23-
export async function watchContents(nuxt: Nuxt, options: ModuleOptions, manifest: Manifest) {
24-
const cwd = join(nuxt.options.rootDir, 'content')
24+
export async function startSocketServer(nuxt: Nuxt, options: ModuleOptions, manifest: Manifest) {
2525
const db = localDatabase(options._localDatabase!.filename)
26-
const collections = manifest.collections
27-
28-
const sourceMap = collections.flatMap((c) => {
29-
return c.source
30-
? c.source.filter(s => !s.repository).map(s => ({ collection: c, source: s }))
31-
: []
32-
})
33-
// const localCollections = collections.filter(c => c.source && !c.source.repository)
34-
35-
const watcher = chokidar.watch('.', { ignoreInitial: true, cwd })
36-
37-
watcher.on('add', onChange)
38-
watcher.on('change', onChange)
39-
watcher.on('unlink', onRemove)
4026

4127
let websocket: ReturnType<typeof createWebSocket>
4228
let listener: Listener
@@ -88,17 +74,47 @@ export async function watchContents(nuxt: Nuxt, options: ModuleOptions, manifest
8874
})
8975
}
9076

77+
nuxt.hook('close', async () => {
78+
// Close WebSocket server
79+
await websocket.close()
80+
await listener.server.close()
81+
})
82+
83+
return {
84+
broadcast,
85+
}
86+
}
87+
88+
export async function watchContents(nuxt: Nuxt, options: ModuleOptions, manifest: Manifest, socket: Awaited<ReturnType<typeof startSocketServer>>) {
89+
const db = localDatabase(options._localDatabase!.filename)
90+
const collections = manifest.collections
91+
92+
const sourceMap = collections.flatMap((c) => {
93+
return c.source
94+
? c.source.filter(s => !s.repository).map(s => ({ collection: c, source: s, cwd: withTrailingSlash(s.cwd) }))
95+
: []
96+
})
97+
const dirsToWatch = Array.from(new Set(sourceMap.map(({ source }) => source.cwd)))
98+
99+
const watcher = chokidar.watch(dirsToWatch, { ignoreInitial: true })
100+
101+
watcher.on('add', onChange)
102+
watcher.on('change', onChange)
103+
watcher.on('unlink', onRemove)
104+
91105
async function onChange(path: string) {
92-
const match = sourceMap.find(({ source }) => micromatch.isMatch(path, source!.include, { ignore: source!.exclude || [], dot: true }))
106+
const match = sourceMap.find(({ source, cwd }) => path.startsWith(cwd) && micromatch.isMatch(path.substring(cwd.length), source!.include, { ignore: source!.exclude || [], dot: true }))
93107
if (match) {
94-
const { collection, source } = match
108+
const { collection, source, cwd } = match
109+
// Remove the cwd prefix
110+
path = path.substring(cwd.length)
95111
logger.info(`File \`${path}\` changed on \`${collection.name}\` collection`)
96112
const { fixed } = parseSourceBase(source)
97113

98114
const filePath = path.substring(fixed.length)
99115
const keyInCollection = join(collection.name, source?.prefix || '', filePath)
100116

101-
const content = await readFile(join(nuxt.options.rootDir, 'content', path), 'utf8')
117+
const content = await readFile(join(cwd, path), 'utf8')
102118
const checksum = getContentChecksum(content)
103119
const localCache = db.fetchDevelopmentCacheForKey(keyInCollection)
104120

@@ -113,14 +129,16 @@ export async function watchContents(nuxt: Nuxt, options: ModuleOptions, manifest
113129
db.insertDevelopmentCache(keyInCollection, checksum, JSON.stringify(parsedContent))
114130

115131
const insertQuery = generateCollectionInsert(collection, parsedContent)
116-
await broadcast(collection, keyInCollection, insertQuery)
132+
await socket.broadcast(collection, keyInCollection, insertQuery)
117133
}
118134
}
119135

120136
async function onRemove(path: string) {
121-
const match = sourceMap.find(({ source }) => micromatch.isMatch(path, source!.include, { ignore: source!.exclude || [], dot: true }))
137+
const match = sourceMap.find(({ source, cwd }) => path.startsWith(cwd) && micromatch.isMatch(path.substring(cwd.length), source!.include, { ignore: source!.exclude || [], dot: true }))
122138
if (match) {
123-
const { collection, source } = match
139+
const { collection, source, cwd } = match
140+
// Remove the cwd prefix
141+
path = path.substring(cwd.length)
124142
logger.info(`File \`${path}\` removed from \`${collection.name}\` collection`)
125143
const { fixed } = parseSourceBase(source)
126144

@@ -129,16 +147,13 @@ export async function watchContents(nuxt: Nuxt, options: ModuleOptions, manifest
129147

130148
await db.deleteDevelopmentCache(keyInCollection)
131149

132-
await broadcast(collection, keyInCollection)
150+
await socket.broadcast(collection, keyInCollection)
133151
}
134152
}
135153

136154
nuxt.hook('close', async () => {
137155
watcher.close()
138156
db.close()
139-
// Close WebSocket server
140-
await websocket.close()
141-
await listener.server.close()
142157
})
143158
}
144159

0 commit comments

Comments
 (0)