@@ -128,7 +128,7 @@ export async function runCodegen(
128128 url : credentials . url ,
129129 adminKey : credentials . adminKey ,
130130 generateCommonJSApi : options . commonjs ,
131- verbose : options . dryRun ,
131+ verbose : ! ! process . env . CONVEX_VERBOSE ,
132132 codegen : true ,
133133 liveComponentSources : options . liveComponentSources ,
134134 typecheckComponents : false ,
@@ -182,6 +182,7 @@ async function startComponentsPushAndCodegen(
182182 codegen : boolean ;
183183 liveComponentSources ?: boolean ;
184184 debugNodeApis : boolean ;
185+ codegenOnlyThisComponent ?: string | undefined ;
185186 } ,
186187) : Promise < StartPushResponse | null > {
187188 const convexDir = await getFunctionsDirectoryPath ( ctx ) ;
@@ -201,7 +202,34 @@ async function startComponentsPushAndCodegen(
201202 printedMessage : `Invalid component root directory (${ isComponent . why } ): ${ convexDir } ` ,
202203 } ) ;
203204 }
204- const rootComponent = isComponent . component ;
205+
206+ let rootComponent = isComponent . component ;
207+ if ( options . codegenOnlyThisComponent ) {
208+ const absolutePath = path . resolve ( options . codegenOnlyThisComponent ) ;
209+ let componentConfigPath : string ;
210+
211+ // Must be a directory containing a convex.config.ts
212+ componentConfigPath = path . join ( absolutePath , DEFINITION_FILENAME_TS ) ;
213+ if ( ! ctx . fs . exists ( componentConfigPath ) ) {
214+ return await ctx . crash ( {
215+ exitCode : 1 ,
216+ errorType : "invalid filesystem data" ,
217+ printedMessage : `Only directories with convex.config.ts files are supported, this directory does not: ${ absolutePath } ` ,
218+ } ) ;
219+ }
220+
221+ const syntheticConfigPath = path . join (
222+ rootComponent . path ,
223+ DEFINITION_FILENAME_TS ,
224+ ) ;
225+ rootComponent = {
226+ isRoot : true ,
227+ path : rootComponent . path ,
228+ definitionPath : syntheticConfigPath ,
229+ isRootWithoutConfig : false ,
230+ syntheticComponentImport : componentConfigPath ,
231+ } ;
232+ }
205233
206234 changeSpinner ( "Finding component definitions..." ) ;
207235 // Create a list of relevant component directories. These are just for knowing
@@ -226,8 +254,22 @@ async function startComponentsPushAndCodegen(
226254 changeSpinner ( "Generating server code..." ) ;
227255 await parentSpan . enterAsync ( "doInitialComponentCodegen" , ( ) =>
228256 withTmpDir ( async ( tmpDir ) => {
229- await doInitialComponentCodegen ( ctx , tmpDir , rootComponent , options ) ;
257+ // Skip the root in component cases
258+ if ( ! rootComponent . syntheticComponentImport ) {
259+ // Do root first so if a component fails, we'll at least have a working root.
260+ await doInitialComponentCodegen ( ctx , tmpDir , rootComponent , options ) ;
261+ }
230262 for ( const directory of components . values ( ) ) {
263+ if ( directory . isRoot ) {
264+ continue ;
265+ }
266+ // When --component-dir is used, only generate code for the target component
267+ if (
268+ rootComponent . syntheticComponentImport &&
269+ directory . definitionPath !== rootComponent . syntheticComponentImport
270+ ) {
271+ continue ;
272+ }
231273 await doInitialComponentCodegen ( ctx , tmpDir , directory , options ) ;
232274 }
233275 } ) ,
@@ -248,6 +290,7 @@ async function startComponentsPushAndCodegen(
248290 // Note that this *includes* the root component.
249291 [ ...components . values ( ) ] ,
250292 ! ! options . liveComponentSources ,
293+ options . verbose ,
251294 ) ,
252295 ) ;
253296
@@ -265,7 +308,8 @@ async function startComponentsPushAndCodegen(
265308 bundleImplementations (
266309 ctx ,
267310 rootComponent ,
268- [ ...components . values ( ) ] ,
311+ // When running codegen for a specific component, don't bundle the root.
312+ [ ...components . values ( ) ] . filter ( ( dir ) => ! dir . syntheticComponentImport ) ,
269313 projectConfig . node . externalPackages ,
270314 options . liveComponentSources ? [ "@convex-dev/component-source" ] : [ ] ,
271315 options . verbose ,
@@ -349,16 +393,31 @@ async function startComponentsPushAndCodegen(
349393 changeSpinner ( "Generating TypeScript bindings..." ) ;
350394 await parentSpan . enterAsync ( "doFinalComponentCodegen" , ( ) =>
351395 withTmpDir ( async ( tmpDir ) => {
352- await doFinalComponentCodegen (
353- ctx ,
354- tmpDir ,
355- rootComponent ,
356- rootComponent ,
357- startPushResponse ,
358- components ,
359- options ,
360- ) ;
396+ // TODO generating code for the root component last might be better DX
397+ // When running codegen for a specific component, don't generate types for the root
398+ if ( ! rootComponent . syntheticComponentImport ) {
399+ // Do the root first
400+ await doFinalComponentCodegen (
401+ ctx ,
402+ tmpDir ,
403+ rootComponent ,
404+ rootComponent ,
405+ startPushResponse ,
406+ components ,
407+ options ,
408+ ) ;
409+ }
361410 for ( const directory of components . values ( ) ) {
411+ if ( directory . isRoot ) {
412+ continue ;
413+ }
414+ // When --component-dir is used, only generate code for the target component
415+ if (
416+ rootComponent . syntheticComponentImport &&
417+ directory . definitionPath !== rootComponent . syntheticComponentImport
418+ ) {
419+ continue ;
420+ }
362421 await doFinalComponentCodegen (
363422 ctx ,
364423 tmpDir ,
@@ -375,9 +434,33 @@ async function startComponentsPushAndCodegen(
375434
376435 changeSpinner ( "Running TypeScript..." ) ;
377436 await parentSpan . enterAsync ( "typeCheckFunctionsInMode" , async ( ) => {
378- await typeCheckFunctionsInMode ( ctx , options . typecheck , rootComponent . path ) ;
437+ // When running codegen for a specific component, don't typecheck the root
438+ if ( ! rootComponent . syntheticComponentImport ) {
439+ await typeCheckFunctionsInMode (
440+ ctx ,
441+ options . typecheck ,
442+ rootComponent . path ,
443+ ) ;
444+ }
379445 if ( options . typecheckComponents ) {
380446 for ( const directory of components . values ( ) ) {
447+ if ( ! directory . isRoot ) {
448+ await typeCheckFunctionsInMode (
449+ ctx ,
450+ options . typecheck ,
451+ directory . path ,
452+ ) ;
453+ }
454+ }
455+ } else if ( rootComponent . syntheticComponentImport ) {
456+ // When running codegen for a specific component, only typecheck that component.
457+ for ( const directory of components . values ( ) ) {
458+ if (
459+ directory . isRoot ||
460+ directory . definitionPath !== rootComponent . syntheticComponentImport
461+ ) {
462+ continue ;
463+ }
381464 await typeCheckFunctionsInMode ( ctx , options . typecheck , directory . path ) ;
382465 }
383466 }
0 commit comments