-
-
Notifications
You must be signed in to change notification settings - Fork 200
feat(cli): upgrade to expo 54 #574
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughMultiple CLI template updates: migrate several Babel/Tailwind/Metro/theme files to Handlebars templates, bump native/web deps, remove web +html wrappers and some ambient types, escape braces in Handlebars TSX, swap SafeAreaView import, add binary-file copy to template processor, and render pnpm-workspace via templating. Changes
Sequence Diagram(s)sequenceDiagram
participant TM as TemplateManager
participant TP as processTemplate
participant FS as FileSystem
TM->>TP: processTemplate(src, dest, context)
alt src has binary extension (.png/.ico/.svg)
TP->>FS: fs.copy(src, dest)
FS-->>TP: copied
TP-->>TM: done
else non-binary/template
TP->>FS: read src
TP->>TP: compile Handlebars (if .hbs) / render with context
TP->>TP: optional formatting (Prettier/biome)
TP->>FS: write dest
FS-->>TP: written
TP-->>TM: done
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Pre-merge checks (3 passed)✅ Passed checks (3 passed)
Poem
✨ Finishing touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (13)
apps/cli/templates/auth/better-auth/native/native-base/lib/auth-client.ts.hbs (1)
5-7
: Guard against missing EXPO_PUBLIC_SERVER_URL in devFail fast or warn in dev to avoid confusing auth/network errors if the env var isn’t set.
Example adjustment:
const baseURL = process.env.EXPO_PUBLIC_SERVER_URL; if (__DEV__ && !baseURL) { console.warn("EXPO_PUBLIC_SERVER_URL is undefined. Set it in your app config or .env."); } export const authClient = createAuthClient({ baseURL, plugins: [ expoClient({ storagePrefix: "my-better-t-app", storage: SecureStore, }), ], });apps/cli/templates/backend/server/next/package.json.hbs (1)
12-13
: Align @types/node with engines.node across templatesFound inconsistent @types/node versions in templates:
- apps/cli/templates/backend/server/next/package.json.hbs — "@types/node": "^20"
- apps/cli/templates/frontend/react/react-router/package.json.hbs — "^20"
- apps/cli/templates/frontend/react/next/package.json.hbs — "^20"
- apps/cli/templates/frontend/react/tanstack-router/package.json.hbs — "^22.13.13"
- apps/cli/templates/backend/convex/packages/backend/package.json.hbs — "^24.3.0"
If your repo’s engines.node is >=22, bump the backend/server/next template (currently ^20) to match the engine (e.g., ^22) for tighter Node API typings and consistency across templates.
apps/cli/templates/frontend/native/unistyles/app/_layout.tsx.hbs (3)
25-25
: Remove unused import or render StatusBar.StatusBar is imported but not used; this can trip noUnusedLocals/ESLint.
Apply one of:
- import { StatusBar } from "expo-status-bar"; + // import { StatusBar } from "expo-status-bar";Or add a StatusBar:
- <Stack + {/* Keep system defaults; override if needed */} + <StatusBar /> + <Stack
32-34
: Avoid silently defaulting Convex URL to an empty string. Fail fast or warn.An empty base URL may cause confusing runtime errors. Prefer explicit config failure or a dev-only warning.
-const convex = new ConvexReactClient(process.env.EXPO_PUBLIC_CONVEX_URL || "", { +const convexUrl = process.env.EXPO_PUBLIC_CONVEX_URL; +if (!convexUrl) { + throw new Error("EXPO_PUBLIC_CONVEX_URL is not set. Please configure it in your env."); +} +const convex = new ConvexReactClient(convexUrl, { unsavedChangesWarning: false, });If you want a softer approach in dev builds, log a warning instead of throwing.
31-35
: Prefer explicit Handlebars conditions over generic else.Guideline: avoid generic if/else in .hbs. Consider replacing the outer {{else}} that handles the non-convex path with {{#unless (eq backend "convex")}} … {{/unless}} for clarity.
apps/cli/templates/frontend/native/unistyles/babel.config.js.hbs (2)
5-12
: Ensure '@/…' alias actually resolves
autoProcessImports: ["@/components"]
assumes an alias. Confirm you add either ts/jsconfig paths and/orbabel-plugin-module-resolver
/Metro alias; otherwise imports will fail at runtime and the Unistyles plugin may not resolve components.I can provide a
module-resolver
snippet and the corresponding devDependency if you want to standardize this.
16-20
: Plugin ordering: keep the worklets/reanimated plugin lastBoth Worklets and Reanimated recommend being the last Babel plugin. Add a comment or enforce order to avoid accidental insertions breaking transforms later.
return { presets: ["babel-preset-expo"], - - plugins, + // Keep the worklets/reanimated plugin last + plugins, };apps/cli/templates/frontend/native/unistyles/package.json.hbs (3)
33-41
: React/Reanimated/Worklets compatibility checkYou have
react
19.1,react-native
0.81.4,react-native-reanimated
~4.1.0, andreact-native-worklets
^0.5.1 together. If standard templates or examples use Reanimated APIs, you’ll need the Reanimated Babel plugin; if you intend to use Worklets-only, remove Reanimated to avoid confusion and extra weight.Want me to generate a diff to drop Reanimated here (and in NativeWind) if going Worklets-only?
13-13
: Expo-managed lib version rangeUse tilde for Expo-managed libs to stay within the SDK’s supported range.
@expo/vector-icons
should match others using~
.- "@expo/vector-icons": "^15.0.2", + "@expo/vector-icons": "~15.0.2",
48-51
: Tooling version drift vs NativeWind templateThis template uses
@babel/core
^7.28.0 andtypescript
~5.9.2, while NativeWind uses ^7.26.10 and ~5.8.2. Consider aligning to a single set to reduce friction for consumers switching stacks.apps/cli/templates/frontend/native/nativewind/package.json.hbs (2)
23-43
: Confirm engine choice: Worklets vs ReanimatedDeps include both
react-native-reanimated
andreact-native-worklets
. The new NativeWind Babel config (per PR) adds Worklets. If Reanimated APIs are still used anywhere, ensure its Babel plugin is present; otherwise, drop Reanimated.I can send a follow-up diff either adding the Reanimated plugin to the NativeWind Babel template or removing the Reanimated dep.
45-49
: Dev tooling versions differ from Unistyles
@babel/core
andtypescript
versions differ between NativeWind and Unistyles templates. Consider unifying to avoid subtle template skew.apps/cli/templates/frontend/native/nativewind/tailwind.config.js.hbs (1)
43-47
: Remove radius from colors; it’s not a color token.Radius is a size variable used in borderRadius, not a color. Keeping it under colors introduces a bogus color key. (ui-private.shadcn.com)
- ring: "hsl(var(--ring))", - radius: "var(--radius)", + ring: "hsl(var(--ring))",
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (29)
apps/cli/templates/auth/better-auth/native/native-base/lib/auth-client.ts.hbs
(1 hunks)apps/cli/templates/backend/server/next/package.json.hbs
(2 hunks)apps/cli/templates/frontend/native/nativewind/app-env.d.ts
(0 hunks)apps/cli/templates/frontend/native/nativewind/app/(drawer)/(tabs)/_layout.tsx.hbs
(2 hunks)apps/cli/templates/frontend/native/nativewind/app/+html.tsx
(0 hunks)apps/cli/templates/frontend/native/nativewind/app/+not-found.tsx.hbs
(1 hunks)apps/cli/templates/frontend/native/nativewind/babel.config.js
(0 hunks)apps/cli/templates/frontend/native/nativewind/babel.config.js.hbs
(1 hunks)apps/cli/templates/frontend/native/nativewind/components/container.tsx.hbs
(1 hunks)apps/cli/templates/frontend/native/nativewind/components/header-button.tsx.hbs
(1 hunks)apps/cli/templates/frontend/native/nativewind/components/tabbar-icon.tsx.hbs
(1 hunks)apps/cli/templates/frontend/native/nativewind/package.json.hbs
(1 hunks)apps/cli/templates/frontend/native/nativewind/tailwind.config.js
(0 hunks)apps/cli/templates/frontend/native/nativewind/tailwind.config.js.hbs
(1 hunks)apps/cli/templates/frontend/native/unistyles/app/(drawer)/(tabs)/_layout.tsx.hbs
(2 hunks)apps/cli/templates/frontend/native/unistyles/app/+html.tsx
(0 hunks)apps/cli/templates/frontend/native/unistyles/app/+not-found.tsx.hbs
(1 hunks)apps/cli/templates/frontend/native/unistyles/app/_layout.tsx.hbs
(1 hunks)apps/cli/templates/frontend/native/unistyles/babel.config.js
(0 hunks)apps/cli/templates/frontend/native/unistyles/babel.config.js.hbs
(1 hunks)apps/cli/templates/frontend/native/unistyles/components/container.tsx.hbs
(1 hunks)apps/cli/templates/frontend/native/unistyles/components/header-button.tsx.hbs
(1 hunks)apps/cli/templates/frontend/native/unistyles/components/tabbar-icon.tsx.hbs
(1 hunks)apps/cli/templates/frontend/native/unistyles/expo-env.d.ts
(0 hunks)apps/cli/templates/frontend/native/unistyles/package.json.hbs
(2 hunks)apps/cli/templates/frontend/react/next/package.json.hbs
(2 hunks)apps/cli/templates/frontend/react/react-router/package.json.hbs
(2 hunks)apps/cli/templates/frontend/react/tanstack-router/package.json.hbs
(2 hunks)apps/cli/templates/frontend/react/tanstack-start/package.json.hbs
(2 hunks)
💤 Files with no reviewable changes (7)
- apps/cli/templates/frontend/native/nativewind/app-env.d.ts
- apps/cli/templates/frontend/native/nativewind/tailwind.config.js
- apps/cli/templates/frontend/native/unistyles/app/+html.tsx
- apps/cli/templates/frontend/native/nativewind/babel.config.js
- apps/cli/templates/frontend/native/unistyles/babel.config.js
- apps/cli/templates/frontend/native/nativewind/app/+html.tsx
- apps/cli/templates/frontend/native/unistyles/expo-env.d.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{hbs,handlebars}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
In Handlebars templates, avoid generic if/else blocks; write explicit conditions (e.g., if (eq orm "prisma") and else if (eq orm "drizzle")).
Files:
apps/cli/templates/frontend/native/nativewind/babel.config.js.hbs
apps/cli/templates/frontend/native/unistyles/app/+not-found.tsx.hbs
apps/cli/templates/frontend/native/unistyles/components/tabbar-icon.tsx.hbs
apps/cli/templates/frontend/native/unistyles/app/(drawer)/(tabs)/_layout.tsx.hbs
apps/cli/templates/frontend/native/unistyles/components/container.tsx.hbs
apps/cli/templates/frontend/native/nativewind/tailwind.config.js.hbs
apps/cli/templates/frontend/native/nativewind/components/container.tsx.hbs
apps/cli/templates/frontend/react/tanstack-router/package.json.hbs
apps/cli/templates/backend/server/next/package.json.hbs
apps/cli/templates/frontend/react/tanstack-start/package.json.hbs
apps/cli/templates/frontend/native/unistyles/app/_layout.tsx.hbs
apps/cli/templates/frontend/native/unistyles/babel.config.js.hbs
apps/cli/templates/frontend/native/nativewind/app/(drawer)/(tabs)/_layout.tsx.hbs
apps/cli/templates/frontend/native/nativewind/components/tabbar-icon.tsx.hbs
apps/cli/templates/frontend/native/nativewind/package.json.hbs
apps/cli/templates/frontend/native/nativewind/app/+not-found.tsx.hbs
apps/cli/templates/frontend/react/react-router/package.json.hbs
apps/cli/templates/frontend/native/unistyles/components/header-button.tsx.hbs
apps/cli/templates/frontend/react/next/package.json.hbs
apps/cli/templates/frontend/native/nativewind/components/header-button.tsx.hbs
apps/cli/templates/frontend/native/unistyles/package.json.hbs
apps/cli/templates/auth/better-auth/native/native-base/lib/auth-client.ts.hbs
🧠 Learnings (2)
📚 Learning: 2025-06-08T17:57:33.083Z
Learnt from: Vijayabaskar56
PR: AmanVarshney01/create-better-t-stack#310
File: apps/cli/templates/frontend/angular/src/app.component.html:1-7
Timestamp: 2025-06-08T17:57:33.083Z
Learning: The Angular frontend template uses Tailwind CSS v4, which doesn't require a traditional tailwind.config.js configuration file.
Applied to files:
apps/cli/templates/frontend/native/nativewind/tailwind.config.js.hbs
📚 Learning: 2025-08-24T18:00:39.152Z
Learnt from: CR
PR: AmanVarshney01/create-better-t-stack#0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-08-24T18:00:39.152Z
Learning: Applies to package.json : Add types/node to package.json when using Node.js built-in modules
Applied to files:
apps/cli/templates/backend/server/next/package.json.hbs
🔇 Additional comments (21)
apps/cli/templates/auth/better-auth/native/native-base/lib/auth-client.ts.hbs (1)
2-2
: LGTM on import reorderingThe change is benign and keeps imports clear. No runtime impact.
apps/cli/templates/frontend/native/unistyles/components/container.tsx.hbs (1)
2-14
: SafeAreaView change OK — remove manual bottom inset and ensure SafeAreaProvider is presentSafeAreaView + paddingBottom: rt.insets.bottom will double-apply the bottom inset. Apply the diff below (let SafeAreaView manage the inset or explicitly control edges) and confirm a SafeAreaProvider is present at the app root.
Apply:
- return <SafeAreaView style={styles.container}>{children}</SafeAreaView>; + return <SafeAreaView edges={["bottom"]} style={styles.container}>{children}</SafeAreaView>;container: { flex: 1, backgroundColor: theme.colors.background, - paddingBottom: rt.insets.bottom, },
rg shows react-native-safe-area-context declared in apps/cli/templates/frontend/native/{nativewind,unistyles}/package.json.hbs and SafeAreaView imported in apps/cli/templates/frontend/native/{nativewind,unistyles}/components/container.tsx.hbs; no SafeAreaProvider match found under apps/cli/templates — add/verify at app root.
apps/cli/templates/frontend/react/tanstack-router/package.json.hbs (1)
23-24
: Pinned React 19.1.0 — consistent across templates; verify TanStack React‑19 compatibility
- react / react-dom are pinned to 19.1.0 across templates (14 occurrences).
- @tanstack/* versions differ between templates (e.g. @tanstack/react-router @1.114.x vs @1.121.0‑alpha); confirm each package's peerDependencies accept React 19 and avoid mixing alpha/stable releases that could introduce incompatible peer ranges or duplicate React instances.
- Check these files for the variants: apps/cli/templates/frontend/react/tanstack-router/package.json.hbs (lines 23–24 for react/react-dom and surrounding TanStack deps), apps/cli/templates/frontend/react/tanstack-start/package.json.hbs, apps/cli/templates/frontend/native/nativewind/package.json.hbs, apps/cli/templates/frontend/react/next/package.json.hbs.
apps/cli/templates/frontend/react/tanstack-start/package.json.hbs (1)
23-24
: Approve — @types/react aligned across templatesVerified all templates reference "@types/react": "~19.1.10" (apps/cli/templates/backend/server/next/package.json.hbs; apps/cli/templates/frontend/native/nativewind/package.json.hbs; apps/cli/templates/frontend/native/unistyles/package.json.hbs; apps/cli/templates/frontend/react/next/package.json.hbs; apps/cli/templates/frontend/react/react-router/package.json.hbs; apps/cli/templates/frontend/react/tanstack-router/package.json.hbs; apps/cli/templates/frontend/react/tanstack-start/package.json.hbs). No action required; keep React/react-dom versions consistent across web templates.
apps/cli/templates/frontend/react/react-router/package.json.hbs (1)
22-23
: Confirm E2E compatibility of React 19.1.0 with React Router ^7.6.1apps/cli/templates/frontend/react/react-router/package.json.hbs pins react/[email protected] and react-router:^7.6.1 (lines 22–24). Run the template E2E, check for peerDependency warnings during install, and verify basic routing flows.
apps/cli/templates/frontend/native/unistyles/components/header-button.tsx.hbs (1)
6-24
: forwardRef not forwarding ref — fix generic and pass refFile: apps/cli/templates/frontend/native/unistyles/components/header-button.tsx.hbs (lines 6-24)
Change the forwardRef generic to React.ElementRef, forward the ref into , and add the React type import.
export const HeaderButton = forwardRef< - typeof Pressable, + React.ElementRef<typeof Pressable>, { onPress?: () => void } >(({ onPress }, ref) => { return ( - <Pressable onPress={onPress} style={styles.button}> + <Pressable ref={ref} onPress={onPress} style={styles.button}> {({ pressed }) => ( <FontAwesome name="info-circle" size={20} color={styles.icon.color} style=\{{ opacity: pressed ? 0.7 : 1, }} /> )} </Pressable> ); });Add this import (outside the range above):
import type React from "react";Unable to verify Handlebars brace-escaping in the sandbox — confirm generated TSX emits style={{ ... }} (not {{).
apps/cli/templates/frontend/native/nativewind/components/tabbar-icon.tsx.hbs (1)
7-7
: Brace-escaping for style propEscaping is correct — template contains
style=\{{ marginBottom: -3 }}
(apps/cli/templates/frontend/native/nativewind/components/tabbar-icon.tsx.hbs:7) and will emitstyle={{ marginBottom: -3 }}
in the generated file.apps/cli/templates/frontend/native/nativewind/app/(drawer)/(tabs)/_layout.tsx.hbs (1)
10-26
: Escaped object-literal braces in JSX props — verifiedTemplates intentionally use escaped braces (e.g. screenOptions={{ ... }} and options={{ ... }}) to prevent Handlebars from consuming
{{
; no change required.apps/cli/templates/frontend/native/unistyles/components/tabbar-icon.tsx.hbs (1)
7-7
: Brace escape is correct for TSX object literals.This will emit style={{ marginBottom: -3 }} in generated TSX as intended.
apps/cli/templates/frontend/native/unistyles/app/+not-found.tsx.hbs (1)
9-9
: Good use of Handlebars escape for JSX options.options={{ ... }} will render valid options={{ ... }} in the output.
apps/cli/templates/frontend/native/nativewind/components/header-button.tsx.hbs (1)
19-21
: Brace escape for style prop looks good.This avoids Handlebars parsing and renders proper style={{ ... }} in TSX.
apps/cli/templates/frontend/native/unistyles/app/(drawer)/(tabs)/_layout.tsx.hbs (3)
11-19
: Correctly escaped screenOptions object.screenOptions={{ ... }} will generate valid JSX and prevents Handlebars interpolation.
23-27
: Escaped options object for “index” tab is correct.No issues; will output options={{ ... }}.
30-36
: Escaped options object for “two” tab is correct.Consistent with the rest of the template.
apps/cli/templates/frontend/native/nativewind/app/+not-found.tsx.hbs (1)
8-8
: Brace escape for Stack.Screen options is correct.Generates valid options={{ title: "Oops!" }} in TSX.
apps/cli/templates/frontend/native/unistyles/app/_layout.tsx.hbs (1)
48-66
: Brace escapes across style/screenOptions blocks look consistent.Generation will produce valid JSX props in all branches.
apps/cli/templates/frontend/react/next/package.json.hbs (1)
18-19
: React 19.1.0 satisfies [email protected] peerDependencies — verify other templates.
- [email protected] peerDependencies include react: '^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0', so react/react-dom 19.1.0 is compatible.
- Location: apps/cli/templates/frontend/react/next/package.json.hbs (lines 18-19) — react/react-dom pinned to 19.1.0; ripgrep produced no matches for other template package.json.hbs files, so confirm all apps/cli/templates/**/package.json.hbs use consistent react/react-dom versions to avoid peer mismatches.
- Optional: align "@types/react-dom" to "~19.1.0" if you pin react-dom.
apps/cli/templates/frontend/native/unistyles/babel.config.js.hbs (1)
1-3
: LGTM: template baseline is correct
api.cache(true)
, preset, and structure look good.apps/cli/templates/frontend/native/nativewind/package.json.hbs (1)
1-12
: LGTM: scripts and entry
"main": "expo-router/entry"
and scripts align with Expo 54 + Router 6.apps/cli/templates/frontend/native/nativewind/components/container.tsx.hbs (1)
2-7
: Switching to SafeAreaView from safe-area-context requires SafeAreaProvider at the app root.Expo Router already injects SafeAreaProvider; if this template can be generated without Expo Router, ensure the root wraps with SafeAreaProvider to avoid runtime issues. Also confirm TS types for className on third‑party components are covered by NativeWind’s types; if not, consider a local .d.ts augmentation for SafeAreaViewProps. (nativewind.dev)
apps/cli/templates/frontend/native/nativewind/tailwind.config.js.hbs (1)
5-9
: Confirm Tailwind version for NativeWind.NativeWind v4 install docs still target Tailwind 3.x and a tailwind.config.js file. If this template moves to Tailwind v4 later, config handling changes. Verify the template pins Tailwind 3.x for NativeWind stacks. (nativewind.dev)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
apps/cli/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs (3)
5-24
: Prevent import name collisions across template combosWhen backend="convex" and api is "orpc"/"trpc", both blocks can render and collide on useQuery imports. Guard the ORPC/TRPC imports to be mutually exclusive with Convex.
-{{#if (eq api "orpc")}} -import { useQuery } from "@tanstack/react-query"; -import { orpc } from "@/utils/orpc"; -{{/if}} -{{#if (eq api "trpc")}} -import { useQuery } from "@tanstack/react-query"; -import { trpc } from "@/utils/trpc"; -{{/if}} -{{#if (eq backend "convex")}} +{{#if (eq backend "convex")}} {{#if (eq auth "clerk")}} import { Link } from "expo-router"; import { Authenticated, AuthLoading, Unauthenticated, useQuery } from "convex/react"; import { api } from "@{{ projectName }}/backend/convex/_generated/api"; import { useUser } from "@clerk/clerk-expo"; import { SignOutButton } from "@/components/sign-out-button"; {{else}} import { useQuery } from "convex/react"; import { api } from "@{{ projectName }}/backend/convex/_generated/api"; {{/if}} {{/if}} +{{#unless (eq backend "convex")}} + {{#if (eq api "orpc")}} + import { useQuery } from "@tanstack/react-query"; + import { orpc } from "@/utils/orpc"; + {{/if}} + {{#if (eq api "trpc")}} + import { useQuery } from "@tanstack/react-query"; + import { trpc } from "@/utils/trpc"; + {{/if}} +{{/unless}}
26-41
: Make healthCheck declarations mutually exclusiveSame collision risk as imports: duplicate const healthCheck when multiple blocks render. Mirror the import guarding around these declarations.
- {{#if (eq api "orpc")}} - const healthCheck = useQuery(orpc.healthCheck.queryOptions()); - {{/if}} - {{#if (eq api "trpc")}} - const healthCheck = useQuery(trpc.healthCheck.queryOptions()); - {{/if}} - {{#if (eq backend "convex")}} + {{#if (eq backend "convex")}} {{#if (eq auth "clerk")}} const { user } = useUser(); const healthCheck = useQuery(api.healthCheck.get); const privateData = useQuery(api.privateData.get); {{else}} const healthCheck = useQuery(api.healthCheck.get); {{/if}} {{/if}} + {{#unless (eq backend "convex")}} + {{#if (eq api "orpc")}} + const healthCheck = useQuery(orpc.healthCheck.queryOptions()); + {{/if}} + {{#if (eq api "trpc")}} + const healthCheck = useQuery(trpc.healthCheck.queryOptions()); + {{/if}} + {{/unless}}
121-137
: Harden optional chaining for Clerk email accessAvoid potential crash when emailAddresses is empty.
- <Text>Hello {user?.emailAddresses[0].emailAddress}</Text> + <Text>Hello {user?.emailAddresses?.[0]?.emailAddress ?? "user"}</Text>
♻️ Duplicate comments (1)
apps/cli/templates/frontend/native/unistyles/package.json.hbs (1)
5-5
: Expo Router entry point mismatch with dependency.
🧹 Nitpick comments (6)
apps/cli/src/utils/template-processor.ts (1)
25-29
: Remove redundant suffix check and simplify condition.If
isBinaryFile(srcPath)
is correct, an additional!srcPath.endsWith(".hbs")
is unnecessary and can hide issues.- if (isBinaryFile(srcPath) && !srcPath.endsWith(".hbs")) { + if (isBinaryFile(srcPath)) { await fs.copy(srcPath, destPath); return; }apps/cli/templates/frontend/native/unistyles/theme.ts.hbs (1)
74-81
: Consider DRY principle for repeated spacing values.The spacing values are duplicated between
lightTheme
anddarkTheme
. Since spacing typically doesn't change between themes, consider extracting to shared constants likesharedColors
.const sharedColors = { success: "#22C55E", destructive: "#EF4444", warning: "#F59E0B", info: "#3B82F6", } as const; +const sharedSpacing = { + xs: 4, + sm: 8, + md: 16, + lg: 24, + xl: 32, + xxl: 48, +} as const; +const sharedBorderRadius = { + sm: 6, + md: 8, + lg: 12, + xl: 16, +} as const; +const sharedFontSize = { + xs: 12, + sm: 14, + base: 16, + lg: 18, + xl: 20, + "2xl": 24, + "3xl": 30, + "4xl": 36, +} as const; export const lightTheme = { colors: { ...sharedColors, // ... color definitions }, - spacing: { - xs: 4, - sm: 8, - md: 16, - lg: 24, - xl: 32, - xxl: 48, - }, + spacing: sharedSpacing, - borderRadius: { - sm: 6, - md: 8, - lg: 12, - xl: 16, - }, + borderRadius: sharedBorderRadius, - fontSize: { - xs: 12, - sm: 14, - base: 16, - lg: 18, - xl: 20, - "2xl": 24, - "3xl": 30, - "4xl": 36, - }, + fontSize: sharedFontSize, } as const;apps/cli/templates/frontend/native/unistyles/metro.config.js.hbs (1)
1-5
: LGTM, with tiny simplification availableWorks for Expo 54. If you want to minimize the file, inline the export.
-const { getDefaultConfig } = require("expo/metro-config"); - -const config = getDefaultConfig(__dirname); - -module.exports = config; +const { getDefaultConfig } = require("expo/metro-config"); +module.exports = getDefaultConfig(__dirname);apps/cli/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs (3)
58-118
: Avoid generic else in Handlebars; prefer explicit conditionsCurrent {{else}} after the Convex branch conflicts with guidelines. Use explicit conditionals to render the ORPC/TRPC status only when backend is not Convex (and api ≠ "none").
- {{else}} - {{#unless (eq api "none")}} + {{/if}} + {{#unless (eq backend "convex")}} + {{#unless (eq api "none")}} <View style={styles.statusRow}> ... </View> - {{/unless}} - {{/if}} + {{/unless}} + {{/unless}}
206-211
: Use themed warning color for consistencyHard-coded hex breaks theme parity. Prefer a theme token (add one if missing).
statusDotWarning: { - backgroundColor: "#F59E0B", + backgroundColor: theme.colors.warning, },If theme lacks warning, add it in theme.ts.hbs to match light/dark.
147-160
: Remove or use unused stylesheroSection and heroSubtitle are defined but unused.
- heroSection: { - paddingVertical: theme.spacing.xl, - }, - heroTitle: { + heroTitle: { fontSize: theme.fontSize["4xl"], fontWeight: "bold", color: theme.colors.foreground, marginBottom: theme.spacing.sm, }, - heroSubtitle: { - fontSize: theme.fontSize.lg, - color: theme.colors.mutedForeground, - lineHeight: 28, - },Or render a subtitle Text using styles.heroSubtitle.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (13)
apps/cli/templates/frontend/native/native-base/assets/favicon.png
is excluded by!**/*.png
apps/cli/templates/frontend/native/native-base/assets/icon.png
is excluded by!**/*.png
apps/cli/templates/frontend/native/native-base/assets/images/android-icon-background.png
is excluded by!**/*.png
apps/cli/templates/frontend/native/native-base/assets/images/android-icon-foreground.png
is excluded by!**/*.png
apps/cli/templates/frontend/native/native-base/assets/images/android-icon-monochrome.png
is excluded by!**/*.png
apps/cli/templates/frontend/native/native-base/assets/images/favicon.png
is excluded by!**/*.png
apps/cli/templates/frontend/native/native-base/assets/images/icon.png
is excluded by!**/*.png
apps/cli/templates/frontend/native/native-base/assets/images/partial-react-logo.png
is excluded by!**/*.png
apps/cli/templates/frontend/native/native-base/assets/images/react-logo.png
is excluded by!**/*.png
apps/cli/templates/frontend/native/native-base/assets/images/[email protected]
is excluded by!**/*.png
apps/cli/templates/frontend/native/native-base/assets/images/[email protected]
is excluded by!**/*.png
apps/cli/templates/frontend/native/native-base/assets/images/splash-icon.png
is excluded by!**/*.png
apps/cli/templates/frontend/native/native-base/assets/splash.png
is excluded by!**/*.png
📒 Files selected for processing (11)
apps/cli/package.json
(1 hunks)apps/cli/src/helpers/core/template-manager.ts
(1 hunks)apps/cli/src/utils/template-processor.ts
(2 hunks)apps/cli/templates/frontend/native/unistyles/app.json.hbs
(1 hunks)apps/cli/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs
(1 hunks)apps/cli/templates/frontend/native/unistyles/app/+not-found.tsx.hbs
(1 hunks)apps/cli/templates/frontend/native/unistyles/metro.config.js
(0 hunks)apps/cli/templates/frontend/native/unistyles/metro.config.js.hbs
(1 hunks)apps/cli/templates/frontend/native/unistyles/package.json.hbs
(2 hunks)apps/cli/templates/frontend/native/unistyles/theme.ts
(0 hunks)apps/cli/templates/frontend/native/unistyles/theme.ts.hbs
(1 hunks)
💤 Files with no reviewable changes (2)
- apps/cli/templates/frontend/native/unistyles/metro.config.js
- apps/cli/templates/frontend/native/unistyles/theme.ts
✅ Files skipped from review due to trivial changes (1)
- apps/cli/package.json
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/cli/templates/frontend/native/unistyles/app/+not-found.tsx.hbs
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/convex_rules.mdc)
**/*.{ts,tsx}
: Use Id from './_generated/dataModel' to type document ids (e.g., Id<'users'>)
Ensure Record key/value types align with validators (e.g., v.record(v.id('users'), v.string()) => Record<Id<'users'>, string>)
Be strict with types for document ids; prefer Id<'table'> over string
Use 'as const' for string literals in discriminated unions
When using Array and Record types, declare with explicit generic types (e.g., const arr: Array = ...)
**/*.{ts,tsx}
: Use TypeScript type aliases instead of interface declarations.
Do not use explicit return types in TypeScript.
Files:
apps/cli/src/helpers/core/template-manager.ts
apps/cli/src/utils/template-processor.ts
**/*.{js,jsx,ts,tsx,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{js,jsx,ts,tsx,mjs,cjs}
: Do not use dotenv; Bun auto-loads .env
UseBun.serve()
for HTTP/WebSockets; do not useexpress
Usebun:sqlite
for SQLite; do not usebetter-sqlite3
UseBun.redis
for Redis; do not useioredis
UseBun.sql
for Postgres; do not usepg
orpostgres.js
Use built-inWebSocket
; do not usews
PreferBun.file
overnode:fs
readFile/writeFile
UseBun.$
instead ofexeca
for shelling out
Files:
apps/cli/src/helpers/core/template-manager.ts
apps/cli/src/utils/template-processor.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Define functions using the standard function declaration syntax, not arrow functions.
Files:
apps/cli/src/helpers/core/template-manager.ts
apps/cli/src/utils/template-processor.ts
**/*.{hbs,handlebars}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
In Handlebars templates, avoid generic if/else blocks; write explicit conditions (e.g., if (eq orm "prisma") and else if (eq orm "drizzle")).
Files:
apps/cli/templates/frontend/native/unistyles/theme.ts.hbs
apps/cli/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs
apps/cli/templates/frontend/native/unistyles/app.json.hbs
apps/cli/templates/frontend/native/unistyles/metro.config.js.hbs
apps/cli/templates/frontend/native/unistyles/package.json.hbs
🧬 Code graph analysis (1)
apps/cli/src/helpers/core/template-manager.ts (1)
apps/cli/src/utils/template-processor.ts (1)
processTemplate
(17-54)
🔇 Additional comments (7)
apps/cli/templates/frontend/native/unistyles/theme.ts.hbs (1)
1-98
: Well-structured theme system with comprehensive design tokens.The theme implementation provides a solid foundation with:
- Shared color constants for consistency
- Comprehensive design tokens (colors, spacing, borderRadius, fontSize)
- Proper TypeScript typing with
as const
- Good separation between light and dark themes
apps/cli/templates/frontend/native/unistyles/package.json.hbs (2)
12-44
: Major dependency upgrades look appropriate for Expo 54.The dependency updates align well with the Expo 54 upgrade:
- Expo packages updated to 54.x versions
- React/React Native updated to latest versions (19.1.0 and 0.81.4)
- React Native Reanimated upgraded to v4 (major version bump)
- Addition of react-native-worklets for new animation capabilities
21-21
: Confirm downgrade to @tanstack/react-form@^1.0.5 is intentional and safe.
npm confirms 1.0.5 exists, but this is a large downgrade from ^1.14.0 and may introduce breaking API/behavior changes.
Location: apps/cli/templates/frontend/native/unistyles/package.json.hbs (line 21).
- Action: either revert to a 1.14+ compatible range, update consumers/tests to support 1.0.x, or add a PR justification + compatibility tests.
apps/cli/templates/frontend/native/unistyles/app.json.hbs (4)
8-9
: Parameterize scheme and Android package — avoid hard-coded identifiersHard-coded values will collide across projects; replace with template vars and ensure Android package is lowercase, alphanumeric and dot-separated.
File: apps/cli/templates/frontend/native/unistyles/app.json.hbs (lines 8–9; also applies at 23)
- "scheme": "mybettertapp", + "scheme": "{{projectSlug}}", @@ - "package": "com.anonymous.mybettertapp6" + "package": "com.{{organizationId}}.{{projectSlug}}"If projectSlug/organizationId aren't available in the template context, add helpers to slugify projectName and inject an org scope.
21-22
: android.predictiveBackGestureEnabled is valid in Expo SDK 54 — no change requiredConfirmed: app.json's android.predictiveBackGestureEnabled is supported in Expo SDK 54 and not deprecated; for bare apps the equivalent native flag is android:enableOnBackInvokedCallback (Android 13+).
29-43
: Plugin configs are correct for Expo SDK 54expo-router can be listed as "expo-router" (optional origin option); expo-splash-screen accepts image, imageWidth and resizeMode ("contain" | "cover" | "native") and your backgroundColor/dark settings are valid — the snippet is correct.
10-10
: KeepnewArchEnabled
— correct for Expo SDK 54apps/cli/templates/frontend/native/unistyles/app.json.hbs (line 10) —
"newArchEnabled": true,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (3)
apps/cli/templates/frontend/native/nativewind/app.json.hbs (1)
21-22
: Remove edgeToEdgeEnabled; SDK 54 enables edge‑to‑edge by default.This key is redundant on SDK 54 (edge‑to‑edge is now always on), and keeping it can confuse future readers.
- "edgeToEdgeEnabled": true,
Reference: Expo SDK 54 notes: “Edge‑to‑edge will be enabled in all Android apps, and cannot be disabled.” (expo.dev)
apps/cli/templates/frontend/native/nativewind/package.json.hbs (2)
23-23
: Prefer ~ range for expo to stick to SDK‑approved patches.Expo templates typically use ~ to avoid accidental minor drifts within the same major. Optional, but safer for scaffolds.
- "expo": "^54.0.1", + "expo": "~54.0.1",
45-52
: Add engines.node >= 20 (RN 0.81 requirement).Helps prevent installs on unsupported Node versions in CI/user envs.
"devDependencies": { "@babel/core": "^7.26.10", "@types/react": "~19.1.10", "tailwindcss": "^3.4.17", "typescript": "~5.8.2" }, - "private": true + "engines": { + "node": ">=20" + }, + "private": trueReference: RN 0.81 raises minimum Node.js to 20. (reactnative.dev)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/cli/templates/frontend/native/nativewind/app.json.hbs
(1 hunks)apps/cli/templates/frontend/native/nativewind/package.json.hbs
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{hbs,handlebars}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
In Handlebars templates, avoid generic if/else blocks; write explicit conditions (e.g., if (eq orm "prisma") and else if (eq orm "drizzle")).
Files:
apps/cli/templates/frontend/native/nativewind/app.json.hbs
apps/cli/templates/frontend/native/nativewind/package.json.hbs
🔇 Additional comments (3)
apps/cli/templates/frontend/native/nativewind/app.json.hbs (1)
22-23
: Predictive back gesture setting is valid as written.android.predictiveBackGestureEnabled is a supported app.json key in v54; default is false, so keeping it explicit is fine.
Reference: v54 config schema shows android.predictiveBackGestureEnabled. (docs.expo.dev)
apps/cli/templates/frontend/native/nativewind/package.json.hbs (2)
23-44
: Deps look aligned with SDK 54 (RN 0.81, React 19.1, Router 6).These versions match SDK 54 expectations. Good.
References: SDK 54 beta includes RN 0.81 and React 19.1.0. (expo.dev)
39-40
: Reanimated v4 choice is compatible with RN 0.81.4.1.x supports RN 0.78–0.81 on the New Architecture, which SDK 54 uses.
Reference: Reanimated 4.x compatibility table. (docs.swmansion.com)
"name": "{{projectName}}", | ||
"slug": "{{projectName}}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Parameterize identifiers; add iOS bundle identifier; make slug URL‑safe.
Hardcoded scheme/package can collide across apps; slug may be invalid if projectName has spaces. Suggest deriving from a slug-safe helper and setting iOS bundle id.
"expo": {
- "name": "{{projectName}}",
- "slug": "{{projectName}}",
+ "name": "{{projectName}}",
+ "slug": "{{kebabCase projectName}}", // or your slug helper/var
...
- "scheme": "mybettertapp",
+ "scheme": "{{kebabCase projectName}}",
"ios": {
- "supportsTablet": true
+ "supportsTablet": true,
+ "bundleIdentifier": "com.anonymous.{{kebabCase projectName}}"
},
"android": {
"adaptiveIcon": {
...
},
"edgeToEdgeEnabled": true,
"predictiveBackGestureEnabled": false,
- "package": "com.anonymous.mybettertapp"
+ "package": "com.anonymous.{{kebabCase projectName}}"
},
Would you prefer a different org prefix than com.anonymous? I can wire this up to a CLI prompt.
Also applies to: 8-8, 12-13, 23-23
🤖 Prompt for AI Agents
In apps/cli/templates/frontend/native/nativewind/app.json.hbs around lines 3-4
(and also update occurrences at lines 8, 12-13, and 23), the template hardcodes
name/slug and iOS bundle/scheme which can collide or become invalid for project
names with spaces; replace these with parameterized, slug-safe helpers for the
slug and derive identifiers for android.package and ios.bundleIdentifier using a
configurable org prefix (e.g., com.<org>.<slug>) instead of com.anonymous,
ensure the slug is URL-safe (lowercase, hyphens, remove/replace invalid chars)
and use that slug when composing the bundle/package and scheme fields so all
identifiers are consistent and safe; wire the org prefix to a template parameter
(or CLI prompt) and update the template references accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/cli/templates/auth/better-auth/server/base/src/lib/auth.ts.hbs (1)
94-94
: Missing native trusted origins in workers runtime configuration.The Cloudflare Workers runtime configuration only includes
env.CORS_ORIGIN
but is missing the native app trusted origins ("mybettertapp://" and "exp://") that are present in other runtime configurations.Apply this diff to add the missing native trusted origins:
- trustedOrigins: [env.CORS_ORIGIN], + trustedOrigins: [ + env.CORS_ORIGIN, + {{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}} + "mybettertapp://", "exp://" + {{/if}} + ],
🧹 Nitpick comments (1)
apps/cli/templates/auth/better-auth/server/base/src/lib/auth.ts.hbs (1)
4-4
: Make Handlebars frontend checks explicit — avoid compoundor (includes ...)
checks.Replace instances of {{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}} with explicit branches: {{#if (includes frontend "native-nativewind")}}…{{else if (includes frontend "native-unistyles")}}…{{/if}} to match the template guideline.
apps/cli/templates/auth/better-auth/server/base/src/lib/auth.ts.hbs — lines 4, 18, 32, 42, 57, 71, 80, 107, 117, 126, 140, 148, 156, 170
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/cli/templates/auth/better-auth/native/native-base/lib/auth-client.ts.hbs
(1 hunks)apps/cli/templates/auth/better-auth/server/base/src/lib/auth.ts.hbs
(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/cli/templates/auth/better-auth/native/native-base/lib/auth-client.ts.hbs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{hbs,handlebars}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
In Handlebars templates, avoid generic if/else blocks; write explicit conditions (e.g., if (eq orm "prisma") and else if (eq orm "drizzle")).
Files:
apps/cli/templates/auth/better-auth/server/base/src/lib/auth.ts.hbs
🔇 Additional comments (4)
apps/cli/templates/auth/better-auth/server/base/src/lib/auth.ts.hbs (4)
19-19
: LGTM! Updated trusted origins for native mobile support.The change from "my-better-t-app://" to "mybettertapp://" and "exp://" correctly aligns with Expo's URL scheme conventions. The "exp://" origin supports Expo development builds while "mybettertapp://" matches the expected production app scheme.
58-58
: LGTM! Consistent trusted origins update.The drizzle ORM configuration correctly mirrors the same trusted origins update for native frontend support.
127-127
: LGTM! Consistent trusted origins update.The mongoose ORM configuration correctly includes the updated trusted origins for native frontend support.
157-157
: LGTM! Consistent trusted origins update.The "none" ORM configuration correctly includes the updated trusted origins for native frontend support.
Summary by CodeRabbit
New Features
Bug Fixes
Chores
Refactor