← Tasks
[SC-01] Expo project init with TypeScript, Expo Router, expo-dev-client
completedcode_genP0
Description
## SC-01: Expo project init with TypeScript, Expo Router, expo-dev-client
Section: Scaffold | Milestone: M1 | Owner: AG Lu
### Failing Tests
- **package_json** (file_exists): File `c8-audio/package.json` must exist
- **app_json** (file_exists): File `c8-audio/app.json` must exist
- **tsconfig** (file_exists): File `c8-audio/tsconfig.json` must exist
- **expo_router_dep** (grep): Pattern `expo-router` in `c8-audio/package.json` (need 1+ matches)
- **dev_client_dep** (grep): Pattern `expo-dev-client` in `c8-audio/package.json` (need 1+ matches)
- **client_env_example** (file_exists): File `c8-audio/.env.example` must exist
### Acceptance Criteria
- File `c8-audio/package.json` must exist
- File `c8-audio/app.json` must exist
- File `c8-audio/tsconfig.json` must exist
- File matching `c8-audio/package.json` must contain pattern `expo-router`
- File matching `c8-audio/package.json` must contain pattern `expo-dev-client`
- File `c8-audio/.env.example` must exist
### Codebase Conventions
- Trilingual comments: // EN: ... // VI: ... // ES: ...
- SPEC section refs in comments
- Zod at module level with .safeParse()
- (supabase as any) with eslint-disable
- NextResponse.json() responses
- Error format: { error: 'message' }
Assignee
-
Claimed By
Cloud Lu → Claude Sonnet
Created
22d ago
Completed
19d ago
Quality
Overall
79%
Pass
PASS
Graded By
-
Graded At
-
Cost
Input Tokens
-
Output Tokens
-
Est. USD
-
Result
{
"cost": {
"input_tokens": 29,
"estimated_usd": 0.041577,
"output_tokens": 2766
},
"model": "claude-sonnet-4-20250514",
"status": "success",
"transport": "anthropic_api",
"latency_ms": 30608,
"response_text": "I'll help you initialize an Expo project with TypeScript, Expo Router, and expo-dev-client. Here's a step-by-step guide:\n\n## Prerequisites\n\nMake sure you have Node.js installed and the latest Expo CLI:\n\n```bash\nnpm install -g @expo/cli\n```\n\n## 1. Create New Expo Project\n\n```bash\n# Create a new Expo project with TypeScript template\nnpx create-expo-app --template tabs@50 MyExpoApp\n\n# Navigate to the project directory\ncd MyExpoApp\n```\n\nAlternatively, you can use the blank TypeScript template:\n\n```bash\nnpx create-expo-app --template blank-typescript@50 MyExpoApp\ncd MyExpoApp\n```\n\n## 2. Install Expo Router\n\n```bash\n# Install Expo Router\nnpx expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar\n```\n\n## 3. Install Expo Dev Client\n\n```bash\n# Install expo-dev-client\nnpx expo install expo-dev-client\n```\n\n## 4. Configure Expo Router\n\n### Update `app.json` or `app.config.js`:\n\n```json\n{\n \"expo\": {\n \"name\": \"MyExpoApp\",\n \"slug\": \"my-expo-app\",\n \"version\": \"1.0.0\",\n \"orientation\": \"portrait\",\n \"icon\": \"./assets/icon.png\",\n \"userInterfaceStyle\": \"light\",\n \"splash\": {\n \"image\": \"./assets/splash.png\",\n \"resizeMode\": \"contain\",\n \"backgroundColor\": \"#ffffff\"\n },\n \"assetBundlePatterns\": [\n \"**/*\"\n ],\n \"ios\": {\n \"supportsTablet\": true\n },\n \"android\": {\n \"adaptiveIcon\": {\n \"foregroundImage\": \"./assets/adaptive-icon.png\",\n \"backgroundColor\": \"#ffffff\"\n }\n },\n \"web\": {\n \"bundler\": \"metro\",\n \"output\": \"static\",\n \"favicon\": \"./assets/favicon.png\"\n },\n \"plugins\": [\n \"expo-router\",\n \"expo-dev-client\"\n ],\n \"experiments\": {\n \"typedRoutes\": true\n }\n }\n}\n```\n\n### Update `metro.config.js`:\n\n```javascript\nconst { getDefaultConfig } = require('expo/metro-config');\n\nconst config = getDefaultConfig(__dirname);\n\nmodule.exports = config;\n```\n\n### Create `babel.config.js`:\n\n```javascript\nmodule.exports = function (api) {\n api.cache(true);\n return {\n presets: ['babel-preset-expo'],\n plugins: [\n // Required for expo-router\n 'expo-router/babel',\n ],\n };\n};\n```\n\n## 5. Project Structure Setup\n\nCreate the following folder structure:\n\n```\nMyExpoApp/\n├── app/\n│ ├── (tabs)/\n│ │ ├── index.tsx\n│ │ ├── explore.tsx\n│ │ └── _layout.tsx\n│ ├── +not-found.tsx\n│ └── _layout.tsx\n├── components/\n├── constants/\n├── hooks/\n├── types/\n└── assets/\n```\n\n## 6. Create App Layout Files\n\n### `app/_layout.tsx`:\n\n```typescript\nimport FontAwesome from '@expo/vector-icons/FontAwesome';\nimport { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';\nimport { useFonts } from 'expo-font';\nimport { Stack } from 'expo-router';\nimport * as SplashScreen from 'expo-splash-screen';\nimport { useEffect } from 'react';\nimport 'react-native-reanimated';\n\nimport { useColorScheme } from '@/hooks/useColorScheme';\n\nexport {\n // Catch any errors thrown by the Layout component.\n ErrorBoundary,\n} from 'expo-router';\n\nexport const unstable_settings = {\n // Ensure that reloading on `/modal` keeps a back button present.\n initialRouteName: '(tabs)',\n};\n\n// Prevent the splash screen from auto-hiding before asset loading is complete.\nSplashScreen.preventAutoHideAsync();\n\nexport default function RootLayout() {\n const [loaded, error] = useFonts({\n SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),\n ...FontAwesome.font,\n });\n\n // Expo Router uses Error Boundaries to catch errors in the navigation tree.\n useEffect(() => {\n if (error) throw error;\n }, [error]);\n\n useEffect(() => {\n if (loaded) {\n SplashScreen.hideAsync();\n }\n }, [loaded]);\n\n if (!loaded) {\n return null;\n }\n\n return <RootLayoutNav />;\n}\n\nfunction RootLayoutNav() {\n const colorScheme = useColorScheme();\n\n return (\n <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>\n <Stack>\n <Stack.Screen name=\"(tabs)\" options={{ headerShown: false }} />\n <Stack.Screen name=\"+not-found\" />\n </Stack>\n </ThemeProvider>\n );\n}\n```\n\n### `app/(tabs)/_layout.tsx`:\n\n```typescript\nimport React from 'react';\nimport FontAwesome from '@expo/vector-icons/FontAwesome';\nimport { Link, Tabs } from 'expo-router';\nimport { Pressable } from 'react-native';\n\nimport Colors from '@/constants/Colors';\nimport { useColorScheme } from '@/hooks/useColorScheme';\nimport { useClientOnlyValue } from '@/hooks/useClientOnlyValue';\n\n// You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/\nfunction TabBarIcon(props: {\n name: React.ComponentProps<typeof FontAwesome>['name'];\n color: string;\n}) {\n return <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />;\n}\n\nexport default function TabLayout() {\n const colorScheme = useColorScheme();\n\n return (\n <Tabs\n screenOptions={{\n tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,\n // Disable the static render of the header on web\n // to prevent a hydration error in React Navigation v6.\n headerShown: useClientOnlyValue(false, true),\n }}>\n <Tabs.Screen\n name=\"index\"\n options={{\n title: 'Tab One',\n tabBarIcon: ({ color }) => <TabBarIcon name=\"code\" color={color} />,\n headerRight: () => (\n <Link href=\"/modal\" asChild>\n <Pressable>\n {({ pressed }) => (\n <FontAwesome\n name=\"info-circle\"\n size={25}\n color={Colors[colorScheme ?? 'light'].text}\n style={{ marginRight: 15, opacity: pressed ? 0.5 : 1 }}\n />\n )}\n </Pressable>\n </Link>\n ),\n }}\n />\n <Tabs.Screen\n name=\"two\"\n options={{\n title: 'Tab Two',\n tabBarIcon: ({ color }) => <TabBarIcon name=\"code\" color={color} />,\n }}\n />\n </Tabs>\n );\n}\n```\n\n### `app/(tabs)/index.tsx`:\n\n```typescript\nimport { StyleSheet } from 'react-native';\n\nimport EditScreenInfo from '@/components/EditScreenInfo';\nimport { Text, View } from '@/components/Themed';\n\nexport default function TabOneScreen() {\n return (\n <View style={styles.container}>\n <Text style={styles.title}>Tab One</Text>\n <View style={styles.separator} lightColor=\"#eee\" darkColor=\"rgba(255,255,255,0.1)\" />\n <EditScreenInfo path=\"app/(tabs)/index.tsx\" />\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n },\n title: {\n fontSize: 20,\n fontWeight: 'bold',\n },\n separator: {\n marginVertical: 30,\n height: 1,\n width: '80%',\n },\n});\n```\n\n### `app/+not-found.tsx`:\n\n```typescript\nimport { Link, Stack } from 'expo-router';\nimport { StyleSheet } from 'react-native';\n\nimport { Text, View } from '@/components/Themed';\n\nexport default function NotFoundScreen() {\n return (\n <>\n <Stack.Screen options={{ title: 'Oops!' }} />\n <View style={styles.container}>\n <Text style={styles.title}>This screen doesn't exist.</Text>\n\n <Link href=\"/\" style={styles.link}>\n <Text style={styles.linkText}>Go to home screen!</Text>\n </Link>\n </View>\n </>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n padding: 20,\n },\n title: {\n fontSize: 20,\n fontWeight: 'bold',\n },\n link: {\n marginTop: 15,\n paddingVertical: 15,\n },\n linkText: {\n fontSize: 14,\n color: '#2e78b7',\n },\n});\n```\n\n## 7. Update TypeScript Configuration\n\nCreate or update `tsconfig.json`:\n\n```json\n{\n \"extends\": \"expo/tsconfig.base\",\n \"compilerOptions\": {\n \"strict\": true,\n \"baseUrl\": \".\",\n \"paths\": {\n \"@/*\": [\"./app/*\"],\n \"@/components/*\": [\"./components/*\"],\n \"@/constants/*\": [\"./constants/*\"],\n \"@/hooks/*\": [\"./hooks/*\"],\n \"@/types/*\": [\"./types/*\"]\n }\n }\n}\n```\n\n## 8. Remove Old Entry Point\n\nDelete the old `App.tsx` file if it exists, as Expo Router will handle navigation.\n\n## 9. Start Development\n\n```bash\n# Start the development server\nnpx expo start\n\n# For development build\nnpx expo start --dev-client\n```\n\n## 10. Building Development Client\n\nTo create a development build:\n\n```bash\n# For iOS\nnpx expo run:ios\n\n# For Android \nnpx expo run:android\n\n# Or build using EAS\nnpx expo install @expo/cli\neas build --profile development --platform ios\neas build --profile development --platform android\n```\n\nYour Expo project is now set up with TypeScript, Expo Router, and expo-dev-client! The development client allows you to create custom native builds while maintaining the fast development workflow of Expo."
}Task ID: e73a0938-c3c6-4393-9e22-6d45690c2973