Skip to content

Commit 095f7e6

Browse files
feat: update ESLint rules, enhance package exports, and improve client and GraphQL watchers with dynamic imports
1 parent 6e8e87c commit 095f7e6

File tree

6 files changed

+128
-80
lines changed

6 files changed

+128
-80
lines changed

eslint.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default antfu({
1818
}, {
1919
rules: {
2020
'node/prefer-global/process': 'off',
21+
'no-new-func': 'off',
2122
},
2223
}, {
2324
files: ['playground/**/*.{ts,js,mjs,cjs}'],

package.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,26 @@
88
".": {
99
"types": "./dist/index.d.ts",
1010
"import": "./dist/index.js"
11+
},
12+
"./codegen": {
13+
"types": "./dist/codegen.d.ts",
14+
"import": "./dist/codegen.js"
15+
},
16+
"./watcher": {
17+
"types": "./dist/watcher.d.ts",
18+
"import": "./dist/watcher.js"
19+
},
20+
"./client-watcher": {
21+
"types": "./dist/client-watcher.d.ts",
22+
"import": "./dist/client-watcher.js"
23+
},
24+
"./context": {
25+
"types": "./dist/context.d.ts",
26+
"import": "./dist/context.js"
27+
},
28+
"./utils": {
29+
"types": "./dist/utils.d.ts",
30+
"import": "./dist/utils.js"
1131
}
1232
},
1333
"main": "./dist/index.js",

src/client-watcher.ts

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,23 @@ import { mergeTypeDefs } from '@graphql-tools/merge'
55
import { makeExecutableSchema } from '@graphql-tools/schema'
66
import { consola } from 'consola'
77
import { join } from 'pathe'
8-
import { generateClientTypes } from './client-codegen'
8+
// import { generateClientTypes } from './client-codegen' // Conditionally imported to prevent bundling
99
import { scanGraphQLFiles } from './scanner'
1010
import { debounce } from './utils'
1111

12+
const logger = consola.withTag('graphql')
13+
1214
async function regenerateClientTypes(nitro: Nitro, options: NitroGraphQLYogaOptions) {
1315
try {
1416
if (!options.client?.enabled)
1517
return
1618

17-
consola.start('[graphql] 🔄 Regenerating client types...')
19+
// Regenerating client types silently
1820

1921
// Get the server schema
2022
const scanResult = await scanGraphQLFiles(nitro)
2123
if (scanResult.typeDefs.length === 0) {
22-
consola.warn('[graphql] ⚠️ No server schema found for client type generation')
24+
logger.warn('⚠️ No server schema found for client type generation')
2325
return
2426
}
2527

@@ -37,7 +39,8 @@ async function regenerateClientTypes(nitro: Nitro, options: NitroGraphQLYogaOpti
3739
`!${join(nitro.options.srcDir, 'graphql/**/*')}`,
3840
]
3941

40-
// Generate client types
42+
// Generate client types using dynamic import
43+
const { generateClientTypes } = await import('./client-codegen')
4144
const generatedTypes = await generateClientTypes(
4245
schema,
4346
clientPatterns,
@@ -53,22 +56,22 @@ async function regenerateClientTypes(nitro: Nitro, options: NitroGraphQLYogaOpti
5356
await mkdir(typesDir, { recursive: true })
5457
await writeFile(outputPath, generatedTypes)
5558

56-
consola.success('[graphql] ✨ Client types updated at:', outputPath)
59+
logger.success('✨ Client types updated')
5760
}
5861
}
5962
catch (error) {
6063
const errorMessage = error instanceof Error ? error.message : String(error)
61-
consola.error('[graphql] ❌ Client type generation failed:', errorMessage)
64+
logger.error('❌ Client type generation failed:', errorMessage)
6265
}
6366
}
6467

6568
export async function setupClientWatcher(nitro: Nitro, options: NitroGraphQLYogaOptions) {
6669
if (!options.client?.enabled) {
67-
consola.info('[graphql] 🚫 Client type generation disabled')
70+
logger.info('🚫 Client type generation disabled')
6871
return
6972
}
7073

71-
consola.info('[graphql] 🔧 Setting up client file watcher...')
74+
// Setting up client file watcher
7275

7376
// Client GraphQL patterns
7477
const clientPatterns = options.client.watchPatterns || [
@@ -89,12 +92,7 @@ export async function setupClientWatcher(nitro: Nitro, options: NitroGraphQLYoga
8992
ignore: [join(nitro.options.srcDir, 'graphql/**/*')], // Exclude server files
9093
})
9194

92-
if (existingClientFiles.length > 0) {
93-
consola.info(`[graphql] 📁 Watching ${existingClientFiles.length} client GraphQL files`)
94-
}
95-
else {
96-
consola.info('[graphql] 📁 No client GraphQL files found to watch')
97-
}
95+
// Client file watching setup complete
9896

9997
const watchPatterns = existingClientFiles.length > 0 ? existingClientFiles : clientPatterns
10098

@@ -109,40 +107,30 @@ export async function setupClientWatcher(nitro: Nitro, options: NitroGraphQLYoga
109107
binaryInterval: 1000,
110108
})
111109

112-
watcher.on('ready', () => {
113-
consola.ready('[graphql] 👁️ Client watcher ready')
114-
})
115-
116-
watcher.on('change', (path) => {
117-
const fileName = path.split('/').pop()
118-
consola.info(`[graphql] 📝 Client file changed: ${fileName}`)
110+
watcher.on('change', (_path) => {
119111
generateClientTypesDebounced()
120112
})
121113

122-
watcher.on('add', (path) => {
123-
const fileName = path.split('/').pop()
124-
consola.info(`[graphql] ➕ Client file added: ${fileName}`)
114+
watcher.on('add', (_path) => {
125115
generateClientTypesDebounced()
126116
})
127117

128-
watcher.on('unlink', (path) => {
129-
const fileName = path.split('/').pop()
130-
consola.info(`[graphql] ➖ Client file removed: ${fileName}`)
118+
watcher.on('unlink', (_path) => {
131119
generateClientTypesDebounced()
132120
})
133121

134122
watcher.on('error', (error) => {
135123
const errorMessage = error instanceof Error ? error.message : String(error)
136-
consola.error('[graphql] ❌ Client watcher error:', errorMessage)
124+
logger.error('❌ Client watcher error:', errorMessage)
137125
})
138126

139127
nitro.hooks.hook('close', () => {
140-
consola.info('[graphql] 🔒 Closing client watcher')
128+
logger.info('🔒 Closing client watcher')
141129
watcher.close()
142130
})
143131

144132
// Generate initial types
145133
await generateClientTypesDebounced()
146134

147-
consola.success('[graphql] ✅ Client watcher ready')
135+
logger.success('✅ Client watcher ready')
148136
}

src/index.ts

Lines changed: 64 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import { makeExecutableSchema } from '@graphql-tools/schema'
66
import { consola } from 'consola'
77
import { defineNitroModule } from 'nitropack/kit'
88
import { join } from 'pathe'
9-
import { setupClientWatcher } from './client-watcher'
10-
import { generateTypes } from './codegen'
9+
// import { generateTypes } from './codegen' // Conditionally imported to prevent bundling
1110
import { scanGraphQLFiles } from './scanner'
12-
import { setupGraphQLWatcher } from './watcher'
11+
12+
const logger = consola.withTag('graphql')
1313

1414
export default defineNitroModule({
1515
name: 'nitro:graphql-yoga',
@@ -44,6 +44,31 @@ export default defineNitroModule({
4444

4545
// Access the internal rollup config and add our prefix
4646
nitro.hooks.hook('rollup:before', (nitro, rollupConfig) => {
47+
// Add codegen packages as external dependencies to prevent bundling
48+
rollupConfig.external = rollupConfig.external || []
49+
const codegenExternals = [
50+
'@graphql-codegen/core',
51+
'@graphql-codegen/typescript',
52+
'@graphql-codegen/typescript-resolvers',
53+
'@graphql-codegen/typescript-operations',
54+
'@graphql-codegen/typescript-generic-sdk',
55+
'@graphql-tools/graphql-file-loader',
56+
'@graphql-tools/load',
57+
]
58+
59+
if (Array.isArray(rollupConfig.external)) {
60+
rollupConfig.external.push(...codegenExternals)
61+
}
62+
else if (typeof rollupConfig.external === 'function') {
63+
const originalExternal = rollupConfig.external
64+
rollupConfig.external = (id, parent, isResolved) => {
65+
if (codegenExternals.some(external => id.includes(external))) {
66+
return true
67+
}
68+
return originalExternal(id, parent, isResolved)
69+
}
70+
}
71+
4772
// Add GraphQL path to chunkNamePrefixes
4873
const originalChunkFileNames = rollupConfig.output.chunkFileNames
4974
rollupConfig.output.chunkFileNames = (chunk) => {
@@ -82,24 +107,19 @@ export type { GraphQLContext } from 'nitro-graphql-yoga/context'
82107

83108
// Log resolver discovery for debugging
84109
if (scanResult.resolvers.length > 0) {
85-
consola.success(`[graphql] Found ${scanResult.resolvers.length} resolvers`)
86-
87-
if (nitro.options.dev) {
88-
consola.info('[graphql] Resolver files:')
89-
for (const resolver of scanResult.resolvers) {
90-
consola.info(` ${resolver.name} -> ${resolver.relativePath}`)
91-
}
92-
}
110+
logger.success(`Found ${scanResult.resolvers.length} resolvers`)
93111
}
94112

95-
// Generate initial types if we have GraphQL files
113+
// Generate types for both development and build modes
96114
if (scanResult.typeDefs.length > 0) {
97115
const mergedTypeDefs = mergeTypeDefs(scanResult.typeDefs)
98116
const schema = makeExecutableSchema({
99117
typeDefs: mergedTypeDefs,
100118
resolvers: {},
101119
})
102120

121+
// Use Function constructor to prevent bundling in production
122+
const { generateTypes } = await (new Function('return import("nitro-graphql-yoga/codegen")'))()
103123
const generatedTypes = await generateTypes(schema)
104124

105125
// Write to file
@@ -119,11 +139,37 @@ declare module 'nitro-graphql-yoga' {
119139
`
120140
await writeFile(graphqlDtsPath, graphqlDtsContent)
121141

122-
consola.success('[graphql] Generated types at:', outputPath)
142+
logger.success('Types generated')
143+
}
144+
else {
145+
// Create minimal types when no schema files found
146+
const typesDir = join(nitro.options.buildDir, 'types')
147+
await mkdir(typesDir, { recursive: true })
148+
149+
const minimalTypes = `// Generated by nitro-graphql-yoga (no schema found)
150+
export type Resolvers = any
151+
`
152+
const outputPath = join(typesDir, 'graphql-types.generated.ts')
153+
await writeFile(outputPath, minimalTypes)
154+
155+
const graphqlDtsPath = join(typesDir, 'graphql.d.ts')
156+
const graphqlDtsContent = `// Auto-generated by nitro-graphql-yoga
157+
import type { Resolvers as Test } from './graphql-types.generated'
158+
159+
declare module 'nitro-graphql-yoga' {
160+
interface Resolvers extends Test {}
161+
}
162+
`
163+
await writeFile(graphqlDtsPath, graphqlDtsContent)
164+
165+
logger.info('Created minimal types (no schema found)')
123166
}
124167

125-
// Setup file watchers in dev mode
168+
// Setup file watchers in dev mode - completely excluded from production
126169
if (nitro.options.dev) {
170+
// Use Function constructor to prevent bundling in production
171+
const setupGraphQLWatcher = (await (new Function('return import("nitro-graphql-yoga/watcher")'))()).setupGraphQLWatcher
172+
const setupClientWatcher = (await (new Function('return import("nitro-graphql-yoga/client-watcher")'))()).setupClientWatcher
127173
await setupGraphQLWatcher(nitro)
128174
await setupClientWatcher(nitro, options)
129175
}
@@ -165,7 +211,6 @@ import { defineEventHandler, readRawBody, setHeader, setResponseStatus } from 'h
165211
import { useStorage } from 'nitro/runtime'
166212
import { makeExecutableSchema } from '@graphql-tools/schema'
167213
import { mergeTypeDefs, mergeResolvers } from '@graphql-tools/merge'
168-
import { loadFilesSync } from '@graphql-tools/load-files'
169214
import { join } from 'pathe'
170215
// Types are generated at build time to .nitro/graphql-types.generated.ts
171216
@@ -204,26 +249,24 @@ async function loadResolvers() {
204249
205250
if (resolver) {
206251
resolverModules.push(resolver)
207-
console.log('[nitro-graphql-yoga] Loaded resolver:', i)
208252
}
209253
} catch (error) {
210-
console.warn('[nitro-graphql-yoga] Failed to load resolver:', i, error.message)
254+
console.warn('[graphql] Failed to load resolver:', i, error.message)
211255
}
212256
}
213257
214258
if (resolverModules.length > 0) {
215259
resolvers = mergeResolvers(resolverModules)
216-
console.log('[nitro-graphql-yoga] Successfully merged', resolverModules.length, 'resolvers')
217260
} else {
218-
console.warn('[nitro-graphql-yoga] No resolvers could be loaded')
261+
console.warn('[graphql] No resolvers could be loaded')
219262
resolvers = { Query: {}, Mutation: {} }
220263
}
221264
} else {
222-
console.warn('[nitro-graphql-yoga] No resolvers found')
265+
console.warn('[graphql] No resolvers found')
223266
resolvers = { Query: {}, Mutation: {} }
224267
}
225268
} catch (error) {
226-
console.warn('[nitro-graphql-yoga] Error loading resolvers:', error.message)
269+
console.warn('[graphql] Error loading resolvers:', error.message)
227270
resolvers = { Query: {}, Mutation: {} }
228271
}
229272
return resolvers

0 commit comments

Comments
 (0)