Skip to content

Commit 73e805a

Browse files
reeceyangConvex, Inc.
authored andcommitted
Add typescriptCompiler option to convex.json (#44027)
GitOrigin-RevId: af88d968d773b1f860d9784cc658264af8b9716d
1 parent 342d732 commit 73e805a

File tree

16 files changed

+572
-7
lines changed

16 files changed

+572
-7
lines changed

npm-packages/common/config/rush/pnpm-lock.yaml

Lines changed: 80 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

npm-packages/convex/schemas/convex.schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@
7676
"default": false
7777
}
7878
}
79+
},
80+
"typescriptCompiler": {
81+
"type": "string",
82+
"enum": ["tsc", "tsgo"],
83+
"description": "TypeScript compiler to use for typechecking (`@typescript/native-preview` must be installed to use `tsgo`)"
7984
}
8085
},
8186
"additionalProperties": false

npm-packages/convex/src/cli/lib/config.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { EOL } from "os";
44
import path from "path";
55
import { z } from "zod";
66
import { Context } from "../../bundler/context.js";
7+
import { TypescriptCompiler } from "./typecheck.js";
78
import {
89
changeSpinner,
910
logError,
@@ -92,6 +93,8 @@ export interface ProjectConfig {
9293
legacyComponentApi?: boolean;
9394
fileType?: "ts" | "js/dts";
9495
};
96+
97+
typescriptCompiler?: TypescriptCompiler;
9598
}
9699

97100
/** Type written to convex.json (where we elide deleted default values) */
@@ -204,6 +207,12 @@ const createProjectConfigSchema = (strict: boolean) => {
204207
staticDataModel: false,
205208
}),
206209
generateCommonJSApi: z.boolean().default(false),
210+
typescriptCompiler: z
211+
.enum(["tsc", "tsgo"])
212+
.optional()
213+
.describe(
214+
"TypeScript compiler to use for typechecking (`@typescript/native-preview` must be installed to use `tsgo`)",
215+
),
207216

208217
// Optional $schema field for JSON schema validation in editors
209218
$schema: z.string().optional(),

npm-packages/convex/src/cli/lib/typecheck.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,26 @@ import { logError, logFailure, showSpinner } from "../../bundler/log.js";
55
import * as Sentry from "@sentry/node";
66
import * as semver from "semver";
77
import { spawnAsync } from "./utils/utils.js";
8+
import { readProjectConfig } from "./config.js";
89

910
export type TypecheckResult = "cantTypeCheck" | "success" | "typecheckFailed";
1011

1112
export type TypeCheckMode = "enable" | "try" | "disable";
1213

14+
export type TypescriptCompiler = "tsc" | "tsgo";
15+
16+
/**
17+
* Resolves the TypeScript compiler to use based on CLI flag, config file, and default.
18+
* Precedence: CLI flag → config file → default "tsc"
19+
*/
20+
export async function resolveTypescriptCompiler(
21+
ctx: Context,
22+
cliOption?: TypescriptCompiler,
23+
): Promise<TypescriptCompiler> {
24+
const { projectConfig } = await readProjectConfig(ctx);
25+
return cliOption ?? projectConfig?.typescriptCompiler ?? "tsc";
26+
}
27+
1328
type TypecheckResultHandler = (
1429
result: TypecheckResult,
1530
logSpecificError?: () => void,
@@ -36,8 +51,10 @@ export async function typeCheckFunctionsInMode(
3651
if (typeCheckMode === "disable") {
3752
return;
3853
}
54+
const typescriptCompiler = await resolveTypescriptCompiler(ctx);
3955
await typeCheckFunctions(
4056
ctx,
57+
typescriptCompiler,
4158
functionsDir,
4259
async (result, logSpecificError, runOnError) => {
4360
if (
@@ -72,6 +89,7 @@ export async function typeCheckFunctionsInMode(
7289
// Runs TypeScript compiler to typecheck Convex query and mutation functions.
7390
export async function typeCheckFunctions(
7491
ctx: Context,
92+
typescriptCompiler: TypescriptCompiler,
7593
functionsDir: string,
7694
handleResult: TypecheckResultHandler,
7795
): Promise<void> {
@@ -84,20 +102,37 @@ export async function typeCheckFunctions(
84102
logError("Run `npx convex codegen --init` to create one.");
85103
});
86104
}
87-
await runTsc(ctx, ["--project", functionsDir], handleResult);
105+
await runTsc(
106+
ctx,
107+
typescriptCompiler,
108+
["--project", functionsDir],
109+
handleResult,
110+
);
88111
}
89112

90113
async function runTsc(
91114
ctx: Context,
115+
typescriptCompiler: TypescriptCompiler,
92116
tscArgs: string[],
93117
handleResult: TypecheckResultHandler,
94118
): Promise<void> {
95119
// Check if tsc is even installed
96-
const tscPath = path.join("node_modules", "typescript", "bin", "tsc");
120+
const tscPath =
121+
typescriptCompiler === "tsgo"
122+
? path.join(
123+
"node_modules",
124+
"@typescript",
125+
"native-preview",
126+
"bin",
127+
"tsgo.js",
128+
)
129+
: path.join("node_modules", "typescript", "bin", "tsc");
97130
if (!ctx.fs.exists(tscPath)) {
98131
return handleResult("cantTypeCheck", () => {
99132
logError(
100-
chalkStderr.gray("No TypeScript binary found, so skipping typecheck."),
133+
chalkStderr.gray(
134+
`No \`${typescriptCompiler}\` binary found, so skipping typecheck.`,
135+
),
101136
);
102137
});
103138
}

npm-packages/convex/src/cli/typecheck.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { chalkStderr } from "chalk";
22
import { functionsDir, ensureHasConvexDependency } from "./lib/utils/utils.js";
3-
import { Command } from "@commander-js/extra-typings";
3+
import { Command, Option } from "@commander-js/extra-typings";
44
import { readConfig } from "./lib/config.js";
5-
import { typeCheckFunctions } from "./lib/typecheck.js";
5+
import {
6+
typeCheckFunctions,
7+
resolveTypescriptCompiler,
8+
} from "./lib/typecheck.js";
69
import { oneoffContext } from "../bundler/context.js";
710
import { logFinishedStep, logMessage } from "../bundler/log.js";
811

@@ -17,16 +20,27 @@ export const typecheck = new Command("typecheck")
1720
"Run TypeScript typechecking on your Convex functions with `tsc --noEmit`.",
1821
)
1922
.allowExcessArguments(false)
20-
.action(async () => {
23+
.addOption(
24+
new Option(
25+
"--typescript-compiler <compiler>",
26+
"TypeScript compiler to use for typechecking (`@typescript/native-preview` must be installed to use `tsgo`)",
27+
).choices(["tsc", "tsgo"] as const),
28+
)
29+
.action(async (cmdOptions) => {
2130
const ctx = await oneoffContext({
2231
url: undefined,
2332
adminKey: undefined,
2433
envFile: undefined,
2534
});
35+
const typescriptCompiler = await resolveTypescriptCompiler(
36+
ctx,
37+
cmdOptions.typescriptCompiler,
38+
);
2639
const { configPath, config: localConfig } = await readConfig(ctx, false);
2740
await ensureHasConvexDependency(ctx, "typecheck");
2841
await typeCheckFunctions(
2942
ctx,
43+
typescriptCompiler,
3044
functionsDir(configPath, localConfig.projectConfig),
3145
async (typecheckResult, logSpecificError, runOnError) => {
3246
logSpecificError?.();
@@ -55,7 +69,7 @@ export const typecheck = new Command("typecheck")
5569
});
5670
} else {
5771
logFinishedStep(
58-
"Typecheck passed: `tsc --noEmit` completed with exit code 0.",
72+
`Typecheck passed: \`${typescriptCompiler} --noEmit\` completed with exit code 0.`,
5973
);
6074
return await ctx.flushAndExit(0);
6175
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
.env.local
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"typescriptCompiler": "tsgo",
3+
"$schema": "https://raw.githubusercontent.com/get-convex/convex-backend/refs/heads/main/npm-packages/convex/schemas/convex.schema.json"
4+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/* eslint-disable */
2+
/**
3+
* Generated `api` utility.
4+
*
5+
* THIS CODE IS AUTOMATICALLY GENERATED.
6+
*
7+
* To regenerate, run `npx convex dev`.
8+
* @module
9+
*/
10+
11+
import type * as example from "../example.js";
12+
13+
import type {
14+
ApiFromModules,
15+
FilterApi,
16+
FunctionReference,
17+
} from "convex/server";
18+
19+
declare const fullApi: ApiFromModules<{
20+
example: typeof example;
21+
}>;
22+
23+
/**
24+
* A utility for referencing Convex functions in your app's public API.
25+
*
26+
* Usage:
27+
* ```js
28+
* const myFunctionReference = api.myModule.myFunction;
29+
* ```
30+
*/
31+
export declare const api: FilterApi<
32+
typeof fullApi,
33+
FunctionReference<any, "public">
34+
>;
35+
36+
/**
37+
* A utility for referencing Convex functions in your app's internal API.
38+
*
39+
* Usage:
40+
* ```js
41+
* const myFunctionReference = internal.myModule.myFunction;
42+
* ```
43+
*/
44+
export declare const internal: FilterApi<
45+
typeof fullApi,
46+
FunctionReference<any, "internal">
47+
>;
48+
49+
export declare const components: {};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* eslint-disable */
2+
/**
3+
* Generated `api` utility.
4+
*
5+
* THIS CODE IS AUTOMATICALLY GENERATED.
6+
*
7+
* To regenerate, run `npx convex dev`.
8+
* @module
9+
*/
10+
11+
import { anyApi, componentsGeneric } from "convex/server";
12+
13+
/**
14+
* A utility for referencing Convex functions in your app's API.
15+
*
16+
* Usage:
17+
* ```js
18+
* const myFunctionReference = api.myModule.myFunction;
19+
* ```
20+
*/
21+
export const api = anyApi;
22+
export const internal = anyApi;
23+
export const components = componentsGeneric();

0 commit comments

Comments
 (0)