Skip to content

Commit a7589b5

Browse files
feat(cli): upgrade to tanstack start rc with workers / alchemy support
1 parent dfc6f1b commit a7589b5

File tree

8 files changed

+42
-128
lines changed

8 files changed

+42
-128
lines changed

apps/cli/src/constants.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const dependencyVersionMap = {
4545

4646
"@clerk/nextjs": "^6.31.5",
4747
"@clerk/clerk-react": "^5.45.0",
48-
"@clerk/tanstack-react-start": "^0.23.1",
48+
"@clerk/tanstack-react-start": "^0.25.1",
4949
"@clerk/clerk-expo": "^2.14.25",
5050

5151
"drizzle-orm": "^0.44.2",
@@ -146,14 +146,14 @@ export const dependencyVersionMap = {
146146
"@tanstack/solid-query-devtools": "^5.87.4",
147147
"@tanstack/solid-router-devtools": "^1.131.44",
148148

149-
wrangler: "^4.23.0",
150-
"@cloudflare/vite-plugin": "^1.9.0",
149+
wrangler: "^4.40.3",
150+
"@cloudflare/vite-plugin": "^1.13.8",
151151
"@opennextjs/cloudflare": "^1.6.5",
152152
"nitro-cloudflare-dev": "^0.2.2",
153153
"@sveltejs/adapter-cloudflare": "^7.2.1",
154154
"@cloudflare/workers-types": "^4.20250822.0",
155155

156-
alchemy: "^0.67.0",
156+
alchemy: "^0.70.0",
157157
// temporary workaround for alchemy + tanstack start
158158
nitropack: "^2.12.4",
159159

apps/cli/src/helpers/deployment/alchemy/alchemy-tanstack-start-setup.ts

Lines changed: 4 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export async function setupTanStackStartAlchemyDeploy(
1313
if (!(await fs.pathExists(webAppDir))) return;
1414

1515
await addPackageDependency({
16-
devDependencies: ["alchemy", "nitropack", "dotenv"],
16+
devDependencies: ["alchemy", "dotenv", "@cloudflare/vite-plugin"],
1717
projectDir: webAppDir,
1818
});
1919

@@ -57,24 +57,6 @@ export async function setupTanStackStartAlchemyDeploy(
5757
alchemyImport.setModuleSpecifier("alchemy/cloudflare/tanstack-start");
5858
}
5959

60-
const reactImport = sourceFile.getImportDeclaration(
61-
"@vitejs/plugin-react",
62-
);
63-
let reactPluginIdentifier = "viteReact";
64-
if (!reactImport) {
65-
sourceFile.addImportDeclaration({
66-
moduleSpecifier: "@vitejs/plugin-react",
67-
defaultImport: "viteReact",
68-
});
69-
} else {
70-
const defaultImport = reactImport.getDefaultImport();
71-
if (defaultImport) {
72-
reactPluginIdentifier = defaultImport.getText();
73-
} else {
74-
reactImport.setDefaultImport("viteReact");
75-
}
76-
}
77-
7860
const exportAssignment = sourceFile.getExportAssignment(
7961
(d) => !d.isExportEquals(),
8062
);
@@ -93,78 +75,16 @@ export async function setupTanStackStartAlchemyDeploy(
9375
}
9476

9577
if (Node.isObjectLiteralExpression(configObject)) {
96-
if (!configObject.getProperty("build")) {
97-
configObject.addPropertyAssignment({
98-
name: "build",
99-
initializer: `{
100-
target: "esnext",
101-
rollupOptions: {
102-
external: ["node:async_hooks", "cloudflare:workers"],
103-
},
104-
}`,
105-
});
106-
}
107-
10878
const pluginsProperty = configObject.getProperty("plugins");
10979
if (pluginsProperty && Node.isPropertyAssignment(pluginsProperty)) {
11080
const initializer = pluginsProperty.getInitializer();
11181
if (Node.isArrayLiteralExpression(initializer)) {
112-
const hasShim = initializer
82+
const hasAlchemy = initializer
11383
.getElements()
114-
.some((el) => el.getText().includes("alchemy"));
115-
if (!hasShim) {
84+
.some((el) => el.getText().includes("alchemy("));
85+
if (!hasAlchemy) {
11686
initializer.addElement("alchemy()");
11787
}
118-
119-
const tanstackElements = initializer
120-
.getElements()
121-
.filter((el) => el.getText().includes("tanstackStart"));
122-
123-
let needsReactPlugin = false;
124-
tanstackElements.forEach((element) => {
125-
if (Node.isCallExpression(element)) {
126-
const args = element.getArguments();
127-
if (args.length === 0) {
128-
element.addArgument(`{
129-
target: "cloudflare-module",
130-
customViteReactPlugin: true,
131-
}`);
132-
needsReactPlugin = true;
133-
} else if (
134-
args.length === 1 &&
135-
Node.isObjectLiteralExpression(args[0])
136-
) {
137-
const configObj = args[0];
138-
if (!configObj.getProperty("target")) {
139-
configObj.addPropertyAssignment({
140-
name: "target",
141-
initializer: '"cloudflare-module"',
142-
});
143-
}
144-
const hasCustomViteReactPlugin = !!configObj.getProperty(
145-
"customViteReactPlugin",
146-
);
147-
if (!hasCustomViteReactPlugin) {
148-
configObj.addPropertyAssignment({
149-
name: "customViteReactPlugin",
150-
initializer: "true",
151-
});
152-
}
153-
needsReactPlugin = true;
154-
}
155-
}
156-
});
157-
158-
const hasReactPlugin = initializer
159-
.getElements()
160-
.some(
161-
(el) =>
162-
Node.isCallExpression(el) &&
163-
el.getExpression().getText() === reactPluginIdentifier,
164-
);
165-
if (needsReactPlugin && !hasReactPlugin) {
166-
initializer.addElement(`${reactPluginIdentifier}()`);
167-
}
16888
}
16989
} else {
17090
configObject.addPropertyAssignment({
@@ -179,18 +99,4 @@ export async function setupTanStackStartAlchemyDeploy(
17999
console.warn("Failed to update vite.config.ts:", error);
180100
}
181101
}
182-
183-
// workaround for tanstack start + workers
184-
const nitroConfigPath = path.join(webAppDir, "nitro.config.ts");
185-
const nitroConfigContent = `import { defineNitroConfig } from "nitropack/config";
186-
187-
export default defineNitroConfig({
188-
preset: "cloudflare-module",
189-
cloudflare: {
190-
nodeCompat: true,
191-
},
192-
});
193-
`;
194-
195-
await fs.writeFile(nitroConfigPath, nitroConfigContent, "utf-8");
196102
}

apps/cli/src/helpers/deployment/workers/workers-tanstack-start-setup.ts

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export async function setupTanstackStartWorkersDeploy(
1818
if (!(await fs.pathExists(webAppDir))) return;
1919

2020
await addPackageDependency({
21-
devDependencies: ["wrangler"],
21+
devDependencies: ["wrangler", "@cloudflare/vite-plugin"],
2222
projectDir: webAppDir,
2323
});
2424

@@ -39,6 +39,18 @@ export async function setupTanstackStartWorkersDeploy(
3939
const sourceFile = tsProject.addSourceFileAtPathIfExists(viteConfigPath);
4040
if (!sourceFile) return;
4141

42+
const cfImport = sourceFile.getImportDeclaration("@cloudflare/vite-plugin");
43+
if (!cfImport) {
44+
sourceFile.addImportDeclaration({
45+
moduleSpecifier: "@cloudflare/vite-plugin",
46+
namedImports: [{ name: "cloudflare" }],
47+
});
48+
} else if (
49+
!cfImport.getNamedImports().some((ni) => ni.getName() === "cloudflare")
50+
) {
51+
cfImport.addNamedImport({ name: "cloudflare" });
52+
}
53+
4254
const reactImport = sourceFile.getImportDeclaration("@vitejs/plugin-react");
4355
let reactPluginIdentifier = "viteReact";
4456
if (!reactImport) {
@@ -73,19 +85,14 @@ export async function setupTanstackStartWorkersDeploy(
7385

7486
const pluginsArray = ensureArrayProperty(configObj, "plugins");
7587

76-
const tanstackPluginIndex = pluginsArray
88+
const hasCloudflare = pluginsArray
7789
.getElements()
78-
.findIndex((el) => el.getText().includes("tanstackStart("));
79-
80-
const tanstackPluginText =
81-
'tanstackStart({ target: "cloudflare-module", customViteReactPlugin: true })';
82-
83-
if (tanstackPluginIndex === -1) {
84-
pluginsArray.addElement(tanstackPluginText);
85-
} else {
86-
pluginsArray
87-
.getElements()
88-
[tanstackPluginIndex].replaceWithText(tanstackPluginText);
90+
.some((el) => el.getText().includes("cloudflare("));
91+
if (!hasCloudflare) {
92+
pluginsArray.insertElement(
93+
0,
94+
"cloudflare({ viteEnvironment: { name: 'ssr' } })",
95+
);
8996
}
9097

9198
const hasReactPlugin = pluginsArray

apps/cli/templates/auth/clerk/convex/web/react/tanstack-start/src/server.ts.hbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
} from "@tanstack/react-start/server";
77
import { createRouter } from "./router";
88

9+
// this is broken right now, waiting for a fix
910
const handlerFactory = createClerkHandler(
1011
createStartHandler({
1112
createRouter,

apps/cli/templates/deploy/wrangler/web/react/tanstack-start/wrangler.jsonc.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "./node_modules/wrangler/config-schema.json",
33
"name": "{{projectName}}",
4-
"main": ".output/server/index.mjs",
4+
"main": "@tanstack/react-start/server-entry",
55
"compatibility_date": "2025-07-05",
66
"compatibility_flags": ["nodejs_compat"],
77
"assets": {

apps/cli/templates/frontend/react/tanstack-start/package.json.hbs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
},
1010
"dependencies": {
1111
"radix-ui": "^1.4.2",
12-
"@tanstack/react-form": "^1.0.5",
12+
"@tanstack/react-form": "^1.23.5",
1313
"@tailwindcss/vite": "^4.1.8",
1414
"@tanstack/react-query": "^5.80.6",
15-
"@tanstack/react-router": "^1.121.0-alpha.27",
16-
"@tanstack/react-router-with-query": "^1.121.0",
17-
"@tanstack/react-start": "^1.121.0-alpha.27",
18-
"@tanstack/router-plugin": "^1.121.0",
15+
"@tanstack/react-router": "^1.132.31",
16+
"@tanstack/react-router-with-query": "^1.130.17",
17+
"@tanstack/react-start": "^1.132.31",
18+
"@tanstack/router-plugin": "^1.132.31",
1919
"class-variance-authority": "^0.7.1",
2020
"clsx": "^2.1.1",
2121
"lucide-react": "^0.525.0",
@@ -30,12 +30,12 @@
3030
"zod": "^4.0.2"
3131
},
3232
"devDependencies": {
33-
"@tanstack/react-router-devtools": "^1.121.0-alpha.27",
33+
"@tanstack/react-router-devtools": "^1.132.31",
3434
"@testing-library/dom": "^10.4.0",
3535
"@testing-library/react": "^16.2.0",
3636
"@types/react": "~19.1.10",
3737
"@types/react-dom": "^19.0.4",
38-
"@vitejs/plugin-react": "^5.0.1",
38+
"@vitejs/plugin-react": "^5.0.4",
3939
"jsdom": "^26.0.0",
4040
"typescript": "^5.7.2",
4141
"vite": "^7.0.2",

apps/cli/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,24 @@ import Loader from "@/components/loader";
3030
import { ClerkProvider, useAuth } from "@clerk/tanstack-react-start";
3131
import { getAuth } from "@clerk/tanstack-react-start/server";
3232
import { createServerFn } from "@tanstack/react-start";
33-
import { getWebRequest } from "@tanstack/react-start/server";
33+
import { getRequest } from "@tanstack/react-start/server";
3434
import { ConvexProviderWithClerk } from "convex/react-clerk";
3535

3636
const fetchClerkAuth = createServerFn({ method: "GET" }).handler(async () => {
37-
const auth = await getAuth(getWebRequest());
37+
const auth = await getAuth(getRequest());
3838
const token = await auth.getToken({ template: "convex" });
3939
return { userId: auth.userId, token };
4040
});
4141
{{else if (and (eq backend "convex") (eq auth "better-auth"))}}
4242
import { createServerFn } from "@tanstack/react-start";
43-
import { getWebRequest, getCookie } from "@tanstack/react-start/server";
43+
import { getRequest, getCookie } from "@tanstack/react-start/server";
4444
import { ConvexBetterAuthProvider } from "@convex-dev/better-auth/react";
4545
import { fetchSession, getCookieName } from "@convex-dev/better-auth/react-start";
4646
import { authClient } from "@/lib/auth-client";
4747
import { createAuth } from "@{{projectName}}/backend/convex/auth";
4848

4949
const fetchAuth = createServerFn({ method: "GET" }).handler(async () => {
50-
const { session } = await fetchSession(getWebRequest());
50+
const { session } = await fetchSession(getRequest());
5151
const sessionCookieName = getCookieName(createAuth);
5252
const token = getCookie(sessionCookieName);
5353
return {

apps/cli/templates/frontend/react/tanstack-start/vite.config.ts.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export default defineConfig({
88
plugins: [
99
tsconfigPaths(),
1010
tailwindcss(),
11-
tanstackStart({ customViteReactPlugin: true }),
11+
tanstackStart(),
1212
viteReact(),
1313
],
1414
});

0 commit comments

Comments
 (0)