FOUNDRY
C8 Platform
← 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