@@ -412,17 +412,26 @@ export class ActionRunner {
412
412
} ;
413
413
414
414
// START deploy tool call
415
- // /
416
- // /
417
- // codegen `convex typecheck` includes typecheck of convex/ dir
418
- // + typecheck
419
- // |
420
- // |
421
- // app typecheck `tsc --noEmit --project tsconfig.app.json
422
- // \
423
- // \
415
+ // / \
416
+ // / \
417
+ // codegen \ `convex typecheck` includes typecheck of convex/ dir
418
+ // + typecheck \
419
+ // | ESLint `eslint` must not include rules that check imports
420
+ // | /
421
+ // app typecheck / `tsc --noEmit --project tsconfig.app.json
422
+ // \ /
423
+ // \ /
424
424
// deploy `deploy` can fail
425
425
426
+ // ESLint doesn't need to wait for codegen since we don't use rules like plugin-import to validate imports.
427
+ const runEslint = async ( ) => {
428
+ if ( await hasMatchingEslintConfig ( container ) ) {
429
+ // ESLint results don't stream to the terminal
430
+ return await run ( [ 'eslint' , 'convex' ] , outputLabels . convexLint ) ;
431
+ }
432
+ return '' ;
433
+ } ;
434
+
426
435
const runCodegenAndTypecheck = async ( onOutput ?: ( output : string ) => void ) => {
427
436
// Convex codegen does a convex directory typecheck, then tsc does a full-project typecheck.
428
437
let output = await run ( [ 'convex' , 'codegen' ] , outputLabels . convexTypecheck , onOutput ) ;
@@ -435,9 +444,14 @@ export class ActionRunner {
435
444
} ;
436
445
437
446
const t0 = performance . now ( ) ;
438
- result += await runCodegenAndTypecheck ( ( output ) => {
439
- this . terminalOutput . set ( output ) ;
440
- } ) ;
447
+ const [ eslintResult , codegenResult ] = await Promise . all ( [
448
+ runEslint ( ) ,
449
+ runCodegenAndTypecheck ( ( output ) => {
450
+ this . terminalOutput . set ( output ) ;
451
+ } ) ,
452
+ ] ) ;
453
+ result += codegenResult ;
454
+ result += eslintResult ;
441
455
result += await run ( [ 'convex' , 'dev' , '--once' , '--typecheck=disable' ] , outputLabels . convexDeploy ) ;
442
456
const time = performance . now ( ) - t0 ;
443
457
logger . info ( 'deploy action finished in' , time ) ;
@@ -513,3 +527,16 @@ function cleanConvexOutput(output: string) {
513
527
}
514
528
return result ;
515
529
}
530
+
531
+ async function hasMatchingEslintConfig ( container : WebContainer ) : Promise < boolean > {
532
+ // Only run eslint if the file we expect is present and contains '@convex-dev/eslint-plugin'.
533
+ let contents = '' ;
534
+ try {
535
+ contents = await container . fs . readFile ( 'eslint.config.js' , 'utf-8' ) ;
536
+ } catch ( e : any ) {
537
+ if ( ! e . message . includes ( 'ENOENT: no such file or directory' ) ) {
538
+ throw e ;
539
+ }
540
+ }
541
+ return contents . includes ( '@convex-dev/eslint-plugin' ) ;
542
+ }
0 commit comments