Awesome
<div align="center"><h1>React Native Typescript Starter</h1></div> <div align="center"><p1 align="center">This is a starter project along with boilerplate code which aims to create scalable, robust and enterprise level React Native Typescript applications 🚀</p1></div>Table of contents
- What is in it?
- Packages
- Running e2e tests 🤖
- Storybook usage 📙
- Path resolver
- Folder structure
- Usage
- Screenshots
- Contributing
- License
What is in it?
-
Pre configured react-native-storybook 📙. Launch the app and toggle the UI between storybook and react native!
Moreover, there will not be any manual effort needed for importing story entries thanks to react-native-storybook-loader library.
- Storybook scripts in package.json
"storybook": "start-storybook -p 6006", "prestorybook": "rnstl" // react-native-storybook-loader
- Storybook scripts in package.json
-
Detox 🤖 for gray box end-to-end testing.
- Detox scripts in package.json
"test:e2e": "detox test -c ios.sim.debug", "build:e2e": "detox build -c ios.sim.debug", "ci:test:e2e": "detox test -c ios.sim.release -l verbose --cleanup", "ci:build:e2e": "detox build -c ios.sim.release",
- Detox scripts in package.json
-
React native, typescript specific robust eslint configurations to enhance development experience.
- Some of eslint configurations are the followings:
-
Debugging 🛠 is one of the fundamental phase of development. Reactotron is ready for this purpose already!
-
Initializing navigation packages in react native applications can be overwhelming and time consuming. React navigation v6 is already installed and initialized along with required packages such as react-native-screens, using strongly typed typescript.
-
It is significant to write a good commit message, especially when you are collaborating with a team or a developer. Here comes Commitlint. It is initialized with the base config!
-
There might be specific scenarios that some actions might need to be executed before committing or pushing the code. Husky ⚓️ will take the responsibility for improving the commits along with commitlint. Husky with commitlint is 💣.
Packages 🎉
- React Navigation v6: Start quickly with built-in navigators that deliver a seamless out-of-the-box experience.
- React Navigation Bottom Tabs v6: A simple tab bar on the bottom of the screen that lets you switch between different routes.
- React Native Vector Icons: Customizable Icons for React Native with support for image source and full styling.
- React Native Date Time Picker: React Native date & time picker component for iOS, Android and Windows.
- React Native MMKV: The fastest key/value storage for React Native. ~30x faster than AsyncStorage!
- React Native Net Info: React Native Network Info API for Android & iOS.
- React Native Keychain: Keychain/Keystore Access for React Native
- React Native Dotenv: Load react native environment variables using import statements for multiple env files.
- React Native Modal: An enhanced, animated, customizable Modal for React Native.
- Detox: Gray box end-to-end testing and automation framework for mobile apps.
- React Native Clean Project: Automating the clean up of a React Native project.
- React Native Storybook: With Storybook for React Native you can design and develop individual React Native components without running your app.
- React Native Utils: Utility functions for react native projects.
Running e2e test 🤖
There is an already initial setup for e2e test in the project. Make sure you run the build script for detox beforehand, then simply executing detox test
will have the following result.
const { reloadApp } = require("./reload");
describe("Example", () => {
beforeEach(async () => {
await reloadApp();
});
it("should have welcome screen", async () => {
await expect(element(by.id("WelcomeScreen"))).toBeVisible();
});
it("should tap the button and counter should be increased by one", async () => {
await element(by.id("tap-me")).tap();
await expect(element(by.id("counter"))).toHaveText("1");
});
});
</details>
Storybook usage 📙
Toggle between storybook and app seamlessly!
<img src="./screenshots/storybook-usage.gif"/>Path resolver
Nested folders can be seen more frequently if the project gets larger by the time goes on.
And the path for importing any module from deeper component could be the following:
import AppButton from "../../../../../components/button/app-button"
Fortunately, Babel plugin module resolver with typescript resolves this issue with some quick configurations which is already covered in this project.
import AppButton "~components/button/app-button"
Folder structure
The project folder structure is the following.
src
|-- api
| |-- axios.instance.ts
|-- app.tsx
|-- assets
| |-- data-uris.ts
| |-- fonts
| |-- images
| |-- index.ts
|-- components
| |-- button
| | |-- button.stories.tsx
| | |-- button.test.tsx
| | |-- button.tsx
| | |-- index.ts
| |-- safe-area
| | |-- index.ts
| | |-- safe-area-provider.tsx
| | |-- safe-area-view.tsx
| |-- shared
| | |-- banner
| | | |-- banner.stories.tsx
| | | |-- banner.test.tsx
| | | |-- banner.tsx
| | | |-- index.ts
|-- config
| |-- reactotron.ts
|-- index.ts
|-- lib
| |-- async-storage
| | |-- index.ts
| |-- constants
| | |-- index.ts
| | |-- regex.ts
| | |-- validation.ts
| |-- user
| | |-- index.ts
| | |-- user.interface.ts
|-- localization
| |-- constants
| | |-- langauge.ts
| |-- helpers
| | |-- language-resources.ts
| | |-- language.ts
| |-- i18n.ts
| |-- locales
| | |-- de_DE.json
| | |-- en_US.json
|-- navigation
| |-- helpers
| | |-- tabbar-options.tsx
| | |-- tabbar-routes.ts
| |-- root-navigator.tsx
| |-- route-names.ts
| |-- stacks
| | |-- auth.tsx
| | |-- home.tsx
| | |-- profile.tsx
| |-- tabbar.tsx
| |-- types
| | |-- auth.ts
| | |-- home.ts
| | |-- index.ts
| | |-- profile.ts
| | |-- tabbar.ts
|-- screens
| |-- error
| | |-- fallback-screen.tsx
| | |-- index.ts
| | |-- main-error-boundary.tsx
| |-- home
| | |-- helpers
| | | |-- index.ts
| | |-- home-screen.tsx
| | |-- hooks
| | | |-- index.ts
| | |-- index.ts
| |-- launch
| | |-- index.ts
| | |-- launch-screen.tsx
| |-- login
| | |-- index.ts
| | |-- login-screen.tsx
| |-- profile
| | |-- index.ts
| | |-- profile-screen.tsx
| |-- sign-up
| | |-- index.ts
| | |-- sign-up-screen.tsx
|-- scripts
| |-- setup-debug.ts
|-- theme
| |-- common-styles.ts
|-- types
| |-- env.d.ts
|-- utils
| |-- ignore-logs.ts
| |-- index.ts
| |-- list.ts
| |-- network-activity.ts
| |-- storybook
| | |-- index.ts
| | |-- withStorybook.tsx
At first glance, some may think; "Hey, React suggests PascalCase for React components! Why you did not use PascalCase here ?"
First thing can be noticed easily is that all of the file names are named in kebab-case convention. There are several reasons behing this decision. One of them is related to CI system. This might not look reasonable for everyone though.
Personal thoughts regarding the naming convention
Having solely one naming convention throughout the project looks more solid and professional. Rather than using PascalCase (AppHeader.tsx) or kebap-case (header-utils.ts) depending on the situtation, having all file names with single naming convention is a way to go.
There is no BETTER naming convention or you MUST use this naming convention rule.
Therefore, feel free not to stick with kebap-case naming convention.
Usage
- Clone the project
git clone https://github.com/tarikpnr/react-native-typescript-starter.git
- react-native-rename for renaming project to the desired one.
Example apps
Screenshots
<table> <tr> </tr> <tr> <td><img src="./screenshots/app-home-screen.png"></td> <td><img src="screenshots/app-profile-screen.png"></td> <td><img src="screenshots/storybook-banner-knobs.png"></td> </tr> <tr> <td><img src="./screenshots/storybook-banner.png"></td> <td><img src="screenshots/storybook-button-knobs.png"></td> <td><img src="screenshots/storybook-button.png"></td> </tr> <tr> <td><img src="./screenshots/storybook-navigator.png"></td> <td><img src="screenshots/storybook-main-screen.png"></td> </tr> </table>Contributing
The main purpose of this library is to provide a highly scalable, robust and bug-free react native project. Contributors are always highly appreciated to keep this library maintained and enhance it more.
License
MIT