Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 39 additions & 12 deletions app/lib/runtime/action-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,17 +412,26 @@ export class ActionRunner {
};

// START deploy tool call
// /
// /
// codegen `convex typecheck` includes typecheck of convex/ dir
// + typecheck
// |
// |
// app typecheck `tsc --noEmit --project tsconfig.app.json
// \
// \
// / \
// / \
// codegen \ `convex typecheck` includes typecheck of convex/ dir
// + typecheck \
// | ESLint `eslint` must not include rules that check imports
// | /
// app typecheck / `tsc --noEmit --project tsconfig.app.json
// \ /
// \ /
// deploy `deploy` can fail

// ESLint doesn't need to wait for codegen since we don't use rules like plugin-import to validate imports.
const runEslint = async () => {
if (await hasMatchingEslintConfig(container)) {
// ESLint results don't stream to the terminal
return await run(['eslint', 'convex'], outputLabels.convexLint);
}
return '';
};

const runCodegenAndTypecheck = async (onOutput?: (output: string) => void) => {
// Convex codegen does a convex directory typecheck, then tsc does a full-project typecheck.
let output = await run(['convex', 'codegen'], outputLabels.convexTypecheck, onOutput);
Expand All @@ -435,9 +444,14 @@ export class ActionRunner {
};

const t0 = performance.now();
result += await runCodegenAndTypecheck((output) => {
this.terminalOutput.set(output);
});
const [eslintResult, codegenResult] = await Promise.all([
runEslint(),
runCodegenAndTypecheck((output) => {
this.terminalOutput.set(output);
}),
]);
result += codegenResult;
result += eslintResult;
result += await run(['convex', 'dev', '--once', '--typecheck=disable'], outputLabels.convexDeploy);
const time = performance.now() - t0;
logger.info('deploy action finished in', time);
Expand Down Expand Up @@ -513,3 +527,16 @@ function cleanConvexOutput(output: string) {
}
return result;
}

async function hasMatchingEslintConfig(container: WebContainer): Promise<boolean> {
// Only run eslint if the file we expect is present and contains '@convex-dev/eslint-plugin'.
let contents = '';
try {
contents = await container.fs.readFile('eslint.config.js', 'utf-8');
} catch (e: any) {
if (!e.message.includes('ENOENT: no such file or directory')) {
throw e;
}
}
return contents.includes('@convex-dev/eslint-plugin');
}
2 changes: 2 additions & 0 deletions app/lib/runtime/deployToolOutputLabels.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export const outputLabels = {
convexCodegen: 'ConvexCodegen',
convexTypecheck: 'ConvexTypecheck',
frontendTypecheck: 'FrontendTypecheck',
convexLint: 'ConvexLint',
convexDeploy: 'ConvexDeploy',
} as const;
export type OutputLabels = (typeof outputLabels)[keyof typeof outputLabels];
2 changes: 1 addition & 1 deletion app/lib/stores/startup/useContainerSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { getFileUpdateCounter } from '~/lib/stores/fileUpdateCounter';
import { chatSyncState } from '~/lib/stores/startup/history';
import { FILE_EVENTS_DEBOUNCE_MS } from '~/lib/stores/files';

const TEMPLATE_URL = '/template-snapshot-80c98556.bin';
const TEMPLATE_URL = 'template-snapshot-d5712743.bin';

export function useNewChatContainerSetup() {
const convex = useConvex();
Expand Down
Binary file added public/template-snapshot-d5712743.bin
Binary file not shown.
3 changes: 3 additions & 0 deletions template/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";
import convexPlugin from "@convex-dev/eslint-plugin";

export default tseslint.config(
{
Expand All @@ -15,6 +16,8 @@ export default tseslint.config(
"vite.config.ts",
],
},
// limited, commonsense Convex function rules
...convexPlugin.configs.recommended,
{
extends: [
js.configs.recommended,
Expand Down
1 change: 1 addition & 0 deletions template/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"dependencies": {
"@convex-dev/auth": "^0.0.80",
"@convex-dev/eslint-plugin": "0.0.1-alpha.4",
"clsx": "^2.1.1",
"convex": "1.21.1-alpha.1",
"react": "^19.0.0",
Expand Down