Project Structure
If you open the new project in VSCode you will see the following structure:
.├── api ## any thing related to api calls and data fetching│ ├── common ##common api files such as axios client and react query provider│ │ ├── api-provider.tsx│ │ ├── client.tsx│ │ ├── index.tsx│ │ └── utils.tsx│ ├── index.tsx│ ├── posts ## query and mutation related to post│ │ ├── index.ts│ │ ├── types.ts│ │ ├── use-add-post.ts│ │ ├── use-post.ts│ │ └── use-posts.ts│ └── types.ts├── core # core files such as auth, localization, storage and more│ ├── auth│ │ ├── index.tsx│ │ └── utils.tsx│ ├── env.js│ ├── hooks│ │ ├── index.tsx│ │ ├── use-is-first-time.tsx│ │ └── use-selected-theme.tsx│ ├── i18n│ │ ├── index.tsx│ │ ├── react-i18next.d.ts│ │ ├── resources.ts│ │ ├── types.ts│ │ └── utils.tsx│ ├── index.tsx│ ├── keyboard.ts│ ├── storage.tsx│ ├── test-utils.tsx│ └── utils.ts├── index.tsx├── navigation│ ├── auth-navigator.tsx│ ├── feed-navigator.tsx│ ├── index.tsx│ ├── navigation-container.tsx│ ├── root-navigator.tsx│ ├── tab-navigator.tsx│ ├── types.tsx│ └── use-theme-config.tsx├── screens│ ├── feed│ │ ├── add-post.tsx│ │ ├── card.tsx│ │ ├── index.tsx│ │ ├── list.tsx│ │ └── post.tsx│ ├── index.tsx│ ├── login│ │ ├── index.tsx│ │ ├── login-form.test.tsx│ │ └── login-form.tsx│ ├── onboarding│ │ ├── cover.tsx│ │ ├── index.tsx│ │ └── onboarding.tsx│ ├── settings│ │ ├── index.tsx│ │ ├── item.tsx│ │ ├── items-container.tsx│ │ ├── language-item.tsx│ │ └── theme-item.tsx│ └── style│ ├── button-variants.tsx│ ├── color-variants.tsx│ ├── index.tsx│ ├── input-variants.tsx│ ├── text-variants.tsx│ └── title.tsx├── translations # translation resources files│ ├── ar.json│ └── en.json├── types│ └── index.ts└── ui # ui components and theme configuration ├── core │ ├── activity-indicator.tsx │ ├── bottom-sheet │ ├── button.tsx │ ├── image.tsx │ ├── index.tsx │ ├── input │ ├── list │ ├── modal │ ├── pressable.tsx │ ├── scroll-view.tsx │ ├── select │ ├── text.tsx │ ├── touchable-opacity.tsx │ └── view.tsx ├── error-handler │ ├── error-fallback.tsx │ └── index.tsx ├── focus-aware-status-bar.tsx ├── icons ├── index.tsx ├── screen.tsx ├── theme │ ├── colors.js │ ├── constants.tsx │ └── index.ts └── utils.tsx
-
ui
: This folder contains all the UI components and the theme configuration. We provide minimal components with a basicobytes
theme. You can add your own components and theme configuration here. -
core
: This folder contains the core files, such as authentication, localization, storage, and more. It can be shared with other projects. That’s why we are only including modules that have nothing to do with project logic. This approach helps us share code between projects and also update the starter with new features. -
navigation
: This folder contains the navigation files such as stack, tab and drawer navigators. We provide a basic navigation structure for the demo app that you can modify to fit your needs. -
screens
: This folder contains the screens files. We provide a basic screens structure for the demo app that you can remove and add your screens. If you need to create a specific component for a screen you can create acomponents
folder inside the screen folder. -
api
: This folder contains the API files. We provide a basic api client and provider and you just need to create query and mutation for your modules. Checkposts
folder for inspiration on how to create a query and mutation. -
translations
: This folder contains the translation resources files. We recommend using translation files even if you are not supporting multiple languages as it will help you to support multiple languages in the future and also help you to find all the strings in one place. -
types
: This folder contains the global types.
Importing files
We use absolute imports to import files using the Babel module resolver plugin and TypeScript path mapping. This approach helps us avoid long relative paths and makes the code cleaner and more readable.
Here is a simple example of how the Feed screen looks with absolute imports.
import { FlashList } from '@shopify/flash-list';import React from 'react';
import type { Post } from '@/api';import { usePosts } from '@/api';import { EmptyList, SafeAreaView, Text, View } from '@/ui';
import { Card } from './card';
export const Feed = () => { const { data, isLoading } = usePosts();
const renderItem = React.useCallback( ({ item }: { item: Post }) => <Card {...item} />, [] ); return ( <View className="flex-1 bg-white"> <FlashList data={data} renderItem={renderItem} keyExtractor={(_, index) => `item-${index}`} ListHeaderComponent={ListHeader} ListEmptyComponent={<EmptyList isLoading={isLoading} />} estimatedItemSize={300} /> </View> );};
const ListHeader = () => ( <SafeAreaView className="ml-4"> <Text variant="lg" className="font-bold"> Feed </Text> </SafeAreaView>);
This approach is very useful when you are working on a large project with a lot of files and folders and it can be done by updating the babel.config.js
file and tsconfig.json
file to the following:
⚙️ Babel configuration
module.exports = function (api) { api.cache(true); return { presets: ['babel-preset-expo'], plugins: [ [ 'module-resolver', { root: ['./'], alias: { '@': './src', '@env': './src/core/env.js', }, extensions: [ '.ios.ts', '.android.ts', '.ts', '.ios.tsx', '.android.tsx', '.tsx', '.jsx', '.js', '.json', ], }, ], ['nativewind/babel', { mode: 'compileOnly' }], 'react-native-reanimated/plugin', ], };};
⚙️ Typescript Config
{ "extends": "expo/tsconfig.base", "compilerOptions": { "strict": true, "baseUrl": ".", "paths": { "@/*": ["./src/*"], "@env": ["./src/core/env.js"] }, "esModuleInterop": true, "checkJs": true }, "exclude": [ "node_modules", "babel.config.js", "metro.config.js", "docs", "cli", "android", "ios", "lint-staged.config.js" ]}