Skip to content

Commit b29e03d

Browse files
feat: enhance GraphQL directive schema generation and file watching
1 parent 8245c29 commit b29e03d

File tree

8 files changed

+74
-33
lines changed

8 files changed

+74
-33
lines changed

src/core/scanning/common.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ import { join, relative } from 'pathe'
88
import { glob } from 'tinyglobby'
99
import { GLOB_SCAN_PATTERN } from '../constants'
1010

11+
// Default patterns to always ignore during scanning
12+
const DEFAULT_IGNORE_PATTERNS = [
13+
'**/node_modules/**',
14+
'**/.git/**',
15+
'**/.output/**',
16+
'**/.nitro/**',
17+
'**/.nuxt/**',
18+
'**/.graphql/**',
19+
]
20+
1121
/**
1222
* Scan a directory for files matching a glob pattern
1323
*/
@@ -20,7 +30,7 @@ export async function scanDirectory(
2030
const fileNames = await glob(join(subDir, globPattern), {
2131
cwd: baseDir,
2232
dot: true,
23-
ignore: ctx.ignorePatterns,
33+
ignore: [...DEFAULT_IGNORE_PATTERNS, ...ctx.ignorePatterns],
2434
absolute: true,
2535
}).catch((error) => {
2636
if ((error as NodeJS.ErrnoException)?.code === 'ENOTDIR') {

src/core/utils/directive-parser.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,12 @@ function getFilePath(ref: DirectiveFileRef): string {
288288
export const directiveParser = new DirectiveParser()
289289

290290
/**
291-
* Generate GraphQL schemas from an array of parsed directives
291+
* Generate GraphQL schema content from an array of parsed directives
292+
* Returns the schema string and optionally writes to buildDir/directives.graphql
292293
*/
293294
export async function generateDirectiveSchemas(
294-
nitro: { graphql: { buildDir: string } },
295295
directives: DirectiveFileRef[],
296+
buildDir?: string,
296297
): Promise<string | null> {
297298
if (directives.length === 0) {
298299
return null
@@ -323,16 +324,19 @@ export async function generateDirectiveSchemas(
323324
.map(d => generateDirectiveSchema(d))
324325
.join('\n\n')
325326

326-
const directivesPath = path.join(nitro.graphql.buildDir, '_directives.graphql')
327-
fs.mkdirSync(path.dirname(directivesPath), { recursive: true })
327+
// Write to .graphql/directives.graphql if buildDir provided
328+
if (buildDir) {
329+
const directivesPath = path.join(buildDir, 'directives.graphql')
330+
fs.mkdirSync(buildDir, { recursive: true })
328331

329-
// Only write if content changed to prevent unnecessary file watcher triggers
330-
const existingContent = fs.existsSync(directivesPath)
331-
? fs.readFileSync(directivesPath, 'utf-8')
332-
: null
333-
if (existingContent !== schemaContent) {
334-
fs.writeFileSync(directivesPath, schemaContent, 'utf-8')
332+
// Only write if content changed
333+
const existingContent = fs.existsSync(directivesPath)
334+
? fs.readFileSync(directivesPath, 'utf-8')
335+
: null
336+
if (existingContent !== schemaContent) {
337+
fs.writeFileSync(directivesPath, schemaContent, 'utf-8')
338+
}
335339
}
336340

337-
return directivesPath
341+
return schemaContent
338342
}

src/nitro/codegen.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ export async function generateServerTypes(
7272
}
7373
})
7474

75+
// Add inline directive schemas (generated from .directive.ts files)
76+
const directiveSchemas = nitro.graphql.directiveSchemas
77+
if (directiveSchemas) {
78+
validSchemas.push('<directives>')
79+
strings.push(directiveSchemas)
80+
}
81+
7582
if (!validateNoDuplicateTypes(validSchemas, strings))
7683
return
7784

src/nitro/setup.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ function initializeConfiguration(nitro: Nitro, serverEnabled: boolean): void {
136136
client: 'graphql',
137137
server: 'server',
138138
},
139+
directiveSchemas: null,
139140
}
140141

141142
// Initialize empty arrays for server-related scans (needed even if server disabled)
@@ -171,7 +172,8 @@ function validateConfiguration(nitro: Nitro): void {
171172
* Setup build directories
172173
*/
173174
function setupBuildDirectories(nitro: Nitro): void {
174-
const graphqlBuildDir = resolve(nitro.options.buildDir, 'graphql')
175+
// Use .graphql/ in root directory instead of .nitro/graphql/
176+
const graphqlBuildDir = resolve(nitro.options.rootDir, '.graphql')
175177
nitro.graphql.buildDir = graphqlBuildDir
176178

177179
// Update relative dir paths based on framework

src/nitro/setup/file-watcher.ts

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,29 @@ interface PendingChanges {
6060
* Watches for changes and triggers type regeneration and dev server reload
6161
*/
6262
export function setupFileWatcher(nitro: Nitro, watchDirs: string[]): FSWatcher {
63+
// Only watch graphql-related files, ignore everything else
64+
const ignored = (path: string) => {
65+
// Always ignore these directories
66+
if (path.includes('/node_modules/') || path.includes('/.git/')
67+
|| path.includes('/.output/') || path.includes('/.nitro/')
68+
|| path.includes('/.nuxt/') || path.includes('/.graphql/')) {
69+
return true
70+
}
71+
// Check if it's a directory (no extension or ends with /) - allow traversal
72+
if (!path.includes('.') || path.endsWith('/')) {
73+
return false
74+
}
75+
// Only watch graphql, resolver, and directive files
76+
const isGraphQL = GRAPHQL_EXTENSIONS.some(ext => path.endsWith(ext))
77+
const isResolver = RESOLVER_EXTENSIONS.some(ext => path.endsWith(ext))
78+
const isDirective = DIRECTIVE_EXTENSIONS.some(ext => path.endsWith(ext))
79+
return !isGraphQL && !isResolver && !isDirective
80+
}
81+
6382
const watcher = watch(watchDirs, {
6483
persistent: DEFAULT_WATCHER_PERSISTENT,
6584
ignoreInitial: DEFAULT_WATCHER_IGNORE_INITIAL,
66-
ignored: nitro.options.ignore,
85+
ignored,
6786
})
6887

6988
const pending: PendingChanges = { server: false, client: false, graphql: false }
@@ -76,17 +95,12 @@ export function setupFileWatcher(nitro: Nitro, watchDirs: string[]): FSWatcher {
7695
const directivesResult = await NitroAdapter.scanDirectives(nitro)
7796
nitro.scanDirectives = directivesResult.items
7897

79-
if (!nitro.scanSchemas)
80-
nitro.scanSchemas = []
98+
// Generate directive schemas and write to .graphql/directives.graphql
99+
const directiveSchemas = await generateDirectiveSchemas(directivesResult.items, nitro.graphql.buildDir)
100+
nitro.graphql.directiveSchemas = directiveSchemas
81101

82-
const directivesPath = await generateDirectiveSchemas(nitro, directivesResult.items)
83102
const schemasResult = await NitroAdapter.scanSchemas(nitro)
84-
const schemas = schemasResult.items
85-
86-
if (directivesPath && !schemas.includes(directivesPath))
87-
schemas.push(directivesPath)
88-
89-
nitro.scanSchemas = schemas
103+
nitro.scanSchemas = schemasResult.items
90104
nitro.scanResolvers = (await NitroAdapter.scanResolvers(nitro)).items
91105

92106
await resolveExtendConfig(nitro, { silent: true })

src/nitro/setup/scanner.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,13 @@ export async function scanLocalFiles(nitro: Nitro): Promise<ScanResult> {
6464
const directivesResult = await NitroAdapter.scanDirectives(nitro)
6565
nitro.scanDirectives = directivesResult.items
6666

67-
// Generate _directives.graphql file
68-
if (!nitro.scanSchemas)
69-
nitro.scanSchemas = []
70-
const directivesPath = await generateDirectiveSchemas(nitro, directivesResult.items)
67+
// Generate directive schemas and write to .graphql/directives.graphql
68+
const directiveSchemas = await generateDirectiveSchemas(directivesResult.items, nitro.graphql.buildDir)
69+
nitro.graphql.directiveSchemas = directiveSchemas
7170

7271
// Scan schemas
7372
const schemasResult = await NitroAdapter.scanSchemas(nitro)
74-
const schemas = schemasResult.items
75-
if (directivesPath && !schemas.includes(directivesPath))
76-
schemas.push(directivesPath)
77-
nitro.scanSchemas = schemas
73+
nitro.scanSchemas = schemasResult.items
7874

7975
// Scan documents and resolvers
8076
const docsResult = await NitroAdapter.scanDocuments(nitro)
@@ -84,7 +80,7 @@ export async function scanLocalFiles(nitro: Nitro): Promise<ScanResult> {
8480
nitro.scanResolvers = resolversResult.items
8581

8682
return {
87-
schemas: schemas.length,
83+
schemas: schemasResult.items.length,
8884
resolvers: resolversResult.items.length,
8985
directives: directivesResult.items.length,
9086
documents: docsResult.items.length,

src/nitro/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,8 @@ declare module 'nitro/types' {
279279
client: string
280280
server: string
281281
}
282+
/** Inline directive schemas generated from .directive.ts files */
283+
directiveSchemas: string | null
282284
/** Resolved extend paths from manifests (populated during setup) */
283285
resolvedExtend?: {
284286
schemas: string[]

src/nitro/virtual/generators.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ export const serverSchemas = {
4848
getCode: (nitro: Nitro): string => {
4949
// All schemas (local + manifest) are now in nitro.scanSchemas
5050
const schemas = [...nitro.scanSchemas, ...(nitro.options.graphql?.typedefs ?? [])]
51+
const directiveSchemas = nitro.graphql.directiveSchemas
5152

52-
if (!schemas.length) {
53+
if (!schemas.length && !directiveSchemas) {
5354
if (nitro.options.dev) {
5455
nitro.logger.warn('[nitro-graphql] No schemas found. Virtual module will export empty array.')
5556
}
@@ -59,6 +60,11 @@ export const serverSchemas = {
5960
const importStatements = schemas.map(s => `import ${getImportId(s)} from '${s}';`)
6061
const schemaArray = schemas.map(s => `{ def: ${getImportId(s)} }`)
6162

63+
// Add inline directive schemas if present
64+
if (directiveSchemas) {
65+
schemaArray.push(`{ def: ${JSON.stringify(directiveSchemas)} }`)
66+
}
67+
6268
return `${importStatements.join('\n')}\n\nexport const schemas = [\n${schemaArray.join(',\n')}\n];`
6369
},
6470
}

0 commit comments

Comments
 (0)