create-ern-boilerplate 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -0
- package/create.js +162 -0
- package/package.json +36 -0
- package/templates/default/README.md +278 -0
- package/templates/default/app.json +58 -0
- package/templates/default/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# š create-ern-boilerplate
|
|
2
|
+
|
|
3
|
+
CLI untuk membuat proyek **React Native Expo** dengan cepat menggunakan berbagai template yang sudah disiapkan.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## š¦ Instalasi
|
|
8
|
+
|
|
9
|
+
Kamu tidak perlu menginstall package ini secara global.
|
|
10
|
+
Cukup jalankan menggunakan **npx**:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npx create-ern-boilerplate
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
š§ Contoh Penggunaan
|
|
18
|
+
š¢ 1. Mode Interaktif (Default)
|
|
19
|
+
npx create-ern-boilerplate
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
Kamu akan ditanya:
|
|
23
|
+
|
|
24
|
+
Nama project
|
|
25
|
+
|
|
26
|
+
Deskripsi
|
|
27
|
+
|
|
28
|
+
Template yang ingin digunakan
|
|
29
|
+
|
|
30
|
+
Apakah ingin langsung install dependencies
|
|
31
|
+
|
|
32
|
+
Contoh:
|
|
33
|
+
|
|
34
|
+
? Nama project kamu: my-expo-app
|
|
35
|
+
? Deskripsi singkat: Aplikasi keren dengan Expo
|
|
36
|
+
? Pilih template: redux
|
|
37
|
+
? Langsung install dependencies setelah membuat project? Yes
|
|
38
|
+
|
|
39
|
+
š” 2. Mode Cepat (Tanpa Prompt)
|
|
40
|
+
|
|
41
|
+
Langsung buat project baru tanpa pertanyaan:
|
|
42
|
+
|
|
43
|
+
npx create-ern-boilerplate my-app -y
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
š¹ Otomatis pakai template default minimal
|
|
47
|
+
š¹ Langsung install dependencies
|
|
48
|
+
|
|
49
|
+
šµ 3. Mode Cepat + Custom Deskripsi + Template
|
|
50
|
+
|
|
51
|
+
Kamu bisa langsung menentukan deskripsi dan template:
|
|
52
|
+
|
|
53
|
+
npx create-ern-boilerplate my-app -y --desc "Boilerplate lengkap" --template default
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
Hasilnya langsung generate project my-app pakai template redux, isi deskripsi, dan auto install dependencies.
|
package/create.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import inquirer from "inquirer";
|
|
8
|
+
import ora from "ora";
|
|
9
|
+
import { execSync } from "child_process";
|
|
10
|
+
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = path.dirname(__filename);
|
|
13
|
+
|
|
14
|
+
async function main() {
|
|
15
|
+
console.log(chalk.bold.cyan("\nš Create Expo React Native Boilerplate\n"));
|
|
16
|
+
|
|
17
|
+
// Ambil argumen CLI
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
const hasY = args.includes("-y") || args.includes("--yes");
|
|
20
|
+
|
|
21
|
+
// Ambil nilai argumen manual
|
|
22
|
+
const nameArg = args.find((a) => !a.startsWith("-"));
|
|
23
|
+
const descIndex = args.findIndex((a) => a === "--desc");
|
|
24
|
+
const templateIndex = args.findIndex((a) => a === "--template");
|
|
25
|
+
|
|
26
|
+
const descArg = descIndex !== -1 ? args[descIndex + 1] : "";
|
|
27
|
+
const templateArg = templateIndex !== -1 ? args[templateIndex + 1] : "";
|
|
28
|
+
|
|
29
|
+
let projectName = nameArg || "";
|
|
30
|
+
let description = descArg || "Proyek React Native dengan Expo";
|
|
31
|
+
let templateName = templateArg || "minimal"; // default template
|
|
32
|
+
let autoInstall = false;
|
|
33
|
+
|
|
34
|
+
// === Mode interaktif ===
|
|
35
|
+
if (!hasY) {
|
|
36
|
+
const answers = await inquirer.prompt([
|
|
37
|
+
{
|
|
38
|
+
name: "projectName",
|
|
39
|
+
message: "Nama project kamu:",
|
|
40
|
+
default: projectName || "my-expo-app",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "description",
|
|
44
|
+
message: "Deskripsi singkat:",
|
|
45
|
+
default: description,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: "list",
|
|
49
|
+
name: "template",
|
|
50
|
+
message: "Pilih template:",
|
|
51
|
+
choices: await getTemplateChoices(),
|
|
52
|
+
default: templateName,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: "confirm",
|
|
56
|
+
name: "autoInstall",
|
|
57
|
+
message: "Langsung install dependencies setelah membuat project?",
|
|
58
|
+
default: false,
|
|
59
|
+
},
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
projectName = answers.projectName;
|
|
63
|
+
description = answers.description;
|
|
64
|
+
templateName = answers.template;
|
|
65
|
+
autoInstall = answers.autoInstall;
|
|
66
|
+
} else {
|
|
67
|
+
// === Mode cepat (-y) ===
|
|
68
|
+
if (!projectName) {
|
|
69
|
+
console.log(chalk.red("ā Kamu harus kasih nama project di mode -y"));
|
|
70
|
+
console.log(chalk.yellow("Contoh: npx create-ern-boilerplate my-app -y --desc 'My App' --template redux"));
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
autoInstall = true; // kalau -y, langsung install
|
|
74
|
+
console.log(chalk.green(`š¦ Membuat proyek ${projectName}... (mode cepat)`));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const targetDir = path.resolve(process.cwd(), projectName);
|
|
78
|
+
const templateDir = path.resolve(__dirname, "templates", templateName);
|
|
79
|
+
|
|
80
|
+
if (!(await fs.pathExists(templateDir))) {
|
|
81
|
+
console.log(chalk.red(`ā Template "${templateName}" tidak ditemukan.`));
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (fs.existsSync(targetDir)) {
|
|
86
|
+
console.log(chalk.red(`ā Folder "${projectName}" sudah ada.`));
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// === Copy template ===
|
|
91
|
+
const spinner = ora(`š Menyalin template "${templateName}"...`).start();
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
await fs.copy(templateDir, targetDir);
|
|
95
|
+
|
|
96
|
+
// === Update package.json ===
|
|
97
|
+
const pkgPath = path.join(targetDir, "package.json");
|
|
98
|
+
if (fs.existsSync(pkgPath)) {
|
|
99
|
+
const pkg = await fs.readJson(pkgPath);
|
|
100
|
+
pkg.name = projectName;
|
|
101
|
+
pkg.description = description;
|
|
102
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// === Update app.json ===
|
|
106
|
+
// === Update app.json ===
|
|
107
|
+
const appJsonPath = path.join(targetDir, "app.json");
|
|
108
|
+
if (fs.existsSync(appJsonPath)) {
|
|
109
|
+
const appJson = await fs.readJson(appJsonPath);
|
|
110
|
+
appJson.expo = appJson.expo || {};
|
|
111
|
+
appJson.expo.name = projectName;
|
|
112
|
+
appJson.expo.slug = projectName.toLowerCase().replace(/\s+/g, "-");
|
|
113
|
+
appJson.expo.ios.bundleIdentifier = `com.${projectName.toLowerCase()}.app`;
|
|
114
|
+
appJson.expo.android.package = `com.${projectName.toLowerCase()}.app`;
|
|
115
|
+
appJson.expo.scheme = projectName.toLowerCase();
|
|
116
|
+
appJson.expo.extra.eas.projectId = ""; // reset biar gak nabrak project kamu
|
|
117
|
+
await fs.writeJson(appJsonPath, appJson, { spaces: 2 });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
spinner.succeed(`ā
Template "${templateName}" berhasil dibuat!`);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
spinner.fail("ā Terjadi kesalahan saat membuat project.");
|
|
123
|
+
console.error(err);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// === Auto install kalau dipilih ===
|
|
128
|
+
if (autoInstall) {
|
|
129
|
+
const installSpinner = ora("š¦ Menginstall dependencies...").start();
|
|
130
|
+
try {
|
|
131
|
+
execSync("npm install", { cwd: targetDir, stdio: "inherit" });
|
|
132
|
+
installSpinner.succeed("ā
Dependencies berhasil diinstall!");
|
|
133
|
+
} catch (err) {
|
|
134
|
+
installSpinner.fail("ā Gagal menginstall dependencies.");
|
|
135
|
+
console.error(err);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
console.log(`
|
|
140
|
+
${chalk.green("š Selesai!")}
|
|
141
|
+
Langkah selanjutnya:
|
|
142
|
+
${chalk.cyan(`cd ${projectName}`)}
|
|
143
|
+
${autoInstall ? chalk.dim("(dependencies sudah terinstall ā
)") : chalk.cyan("npm install")}
|
|
144
|
+
${chalk.cyan("npm run start")}
|
|
145
|
+
|
|
146
|
+
Happy coding! š»
|
|
147
|
+
`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// === Helper untuk menampilkan daftar template ===
|
|
151
|
+
async function getTemplateChoices() {
|
|
152
|
+
const templatesDir = path.join(__dirname, "templates");
|
|
153
|
+
const folders = await fs.readdir(templatesDir);
|
|
154
|
+
return folders.filter((f) =>
|
|
155
|
+
fs.statSync(path.join(templatesDir, f)).isDirectory()
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
main().catch((err) => {
|
|
160
|
+
console.error(chalk.red("Terjadi kesalahan:"), err);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-ern-boilerplate",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Expo React Native boilerplate generator",
|
|
5
|
+
"bin": {
|
|
6
|
+
"create-ern-boilerplate": "./create.js",
|
|
7
|
+
"ern-boilerplate": "./create.js"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"author": {
|
|
12
|
+
"name": "defazr",
|
|
13
|
+
"email": "ulfar.far@gmail.com"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/",
|
|
23
|
+
"keywords": [
|
|
24
|
+
"expo",
|
|
25
|
+
"react-native",
|
|
26
|
+
"boilerplate",
|
|
27
|
+
"template",
|
|
28
|
+
"create"
|
|
29
|
+
],
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"chalk": "^5.3.0",
|
|
32
|
+
"fs-extra": "^11.2.0",
|
|
33
|
+
"inquirer": "^9.2.12",
|
|
34
|
+
"ora": "^8.0.1"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# Expo React Native Boilerplate
|
|
2
|
+
|
|
3
|
+
A comprehensive boilerplate for building React Native applications with Expo, featuring authentication, theming, and a clean architecture.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ā
**Expo Router** - File-based routing
|
|
8
|
+
- ā
**TypeScript** - Type-safe development
|
|
9
|
+
- ā
**NativeWind (Tailwind CSS)** - Utility-first styling
|
|
10
|
+
- ā
**Authentication Context** - Global auth state management
|
|
11
|
+
- ā
**Theme Support** - Light/Dark mode with system preference
|
|
12
|
+
- ā
**Mock API Server** - JSON Server for development
|
|
13
|
+
- ā
**Secure Storage** - Expo SecureStore for sensitive data
|
|
14
|
+
- ā
**Path Aliases** - Clean imports with `@` prefix
|
|
15
|
+
- ā
**Form Validation** - Built-in validation utilities
|
|
16
|
+
- ā
**Reusable Components** - Button, Input, Card, Loading, etc.
|
|
17
|
+
|
|
18
|
+
## Project Structure
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
.
|
|
22
|
+
āāā app
|
|
23
|
+
ā āāā (admin) # Halaman & route khusus admin
|
|
24
|
+
ā āāā (auth) # Halaman auth (login, register, dsb)
|
|
25
|
+
ā āāā (protected) # Halaman yang membutuhkan autentikasi
|
|
26
|
+
ā āāā _layout.tsx # Root layout untuk Expo Router
|
|
27
|
+
ā
|
|
28
|
+
āāā server
|
|
29
|
+
ā āāā db.json # Mock data untuk JSON Server
|
|
30
|
+
ā āāā middleware.js # Custom middleware untuk API
|
|
31
|
+
ā āāā routes.json # Routing konfigurasi JSON Server
|
|
32
|
+
ā
|
|
33
|
+
āāā src
|
|
34
|
+
ā āāā assets # Gambar, font, dan aset statis
|
|
35
|
+
ā āāā components # Komponen UI reusable
|
|
36
|
+
ā āāā contexts # Context API (Auth, Theme, dsb)
|
|
37
|
+
ā āāā hooks # Custom React hooks
|
|
38
|
+
ā āāā services # API service (Axios, interceptors, dll)
|
|
39
|
+
ā āāā theme # Konfigurasi tema (warna, dark mode)
|
|
40
|
+
ā āāā types # TypeScript type definitions
|
|
41
|
+
ā āāā utils # Helper functions & constants
|
|
42
|
+
ā
|
|
43
|
+
āāā app.json # Konfigurasi Expo project
|
|
44
|
+
āāā babel.config.js # Konfigurasi Babel
|
|
45
|
+
āāā expo-env.d.ts # Type definitions untuk Expo environment
|
|
46
|
+
āāā global.css # Global style untuk Tailwind / NativeWind
|
|
47
|
+
āāā index.ts # Entry point utama aplikasi
|
|
48
|
+
āāā LICENSE # Lisensi project
|
|
49
|
+
āāā metro.config.js # Konfigurasi Metro bundler
|
|
50
|
+
āāā nativewind-env.d.ts # Type support untuk NativeWind
|
|
51
|
+
āāā package.json # Dependency & script project
|
|
52
|
+
āāā package-lock.json # Lock file npm
|
|
53
|
+
āāā README.md # Dokumentasi project
|
|
54
|
+
āāā structure.txt # Struktur folder (auto-generated)
|
|
55
|
+
āāā tailwind.config.js # Konfigurasi TailwindCSS
|
|
56
|
+
āāā tsconfig.json # Konfigurasi TypeScript
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Getting Started
|
|
61
|
+
|
|
62
|
+
### Prerequisites
|
|
63
|
+
|
|
64
|
+
- Node.js 18+
|
|
65
|
+
- npm or yarn
|
|
66
|
+
- Expo CLI
|
|
67
|
+
|
|
68
|
+
### Installation
|
|
69
|
+
|
|
70
|
+
1. Clone the repository:
|
|
71
|
+
```bash
|
|
72
|
+
git clone <your-repo-url>
|
|
73
|
+
cd expo-boilerplate
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
2. Install dependencies:
|
|
77
|
+
```bash
|
|
78
|
+
npm install
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
3. Start the development server:
|
|
82
|
+
```bash
|
|
83
|
+
npm run dev
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
This will start both the Expo development server and the mock API server.
|
|
87
|
+
|
|
88
|
+
### Available Scripts
|
|
89
|
+
|
|
90
|
+
- `npm start` - Start Expo development server
|
|
91
|
+
- `npm run android` - Run on Android
|
|
92
|
+
- `npm run ios` - Run on iOS
|
|
93
|
+
- `npm run web` - Run on web
|
|
94
|
+
- `npm run server` - Start mock API server
|
|
95
|
+
- `npm run dev` - Start both Expo and API server
|
|
96
|
+
- `npm run lint` - Run ESLint
|
|
97
|
+
- `npm run type-check` - Run TypeScript type checking
|
|
98
|
+
|
|
99
|
+
## Configuration
|
|
100
|
+
|
|
101
|
+
### API Configuration
|
|
102
|
+
|
|
103
|
+
Edit `src/utils/constants.ts` to configure your API endpoints:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
export const API_CONFIG = {
|
|
107
|
+
BASE_URL: __DEV__ ? 'http://localhost:3001' : 'https://api.yourapp.com',
|
|
108
|
+
TIMEOUT: 10000,
|
|
109
|
+
};
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Theme Configuration
|
|
113
|
+
|
|
114
|
+
Customize colors in `src/theme/colors.ts`:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
export const colors = {
|
|
118
|
+
light: {
|
|
119
|
+
primary: '#3b82f6',
|
|
120
|
+
// ... other colors
|
|
121
|
+
},
|
|
122
|
+
dark: {
|
|
123
|
+
primary: '#3b82f6',
|
|
124
|
+
// ... other colors
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Authentication
|
|
130
|
+
|
|
131
|
+
The boilerplate includes a complete authentication flow:
|
|
132
|
+
|
|
133
|
+
### Default Credentials
|
|
134
|
+
|
|
135
|
+
- **Admin**: admin@example.com / admin123
|
|
136
|
+
- **User**: user@example.com / user123
|
|
137
|
+
|
|
138
|
+
### Using Authentication
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { useAuth } from '@hooks/useAuth';
|
|
142
|
+
|
|
143
|
+
function MyComponent() {
|
|
144
|
+
const { user, login, logout, isAuthenticated } = useAuth();
|
|
145
|
+
|
|
146
|
+
// Use authentication methods
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Theming
|
|
151
|
+
|
|
152
|
+
Switch between light and dark themes:
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { useTheme } from '@hooks/useTheme';
|
|
156
|
+
|
|
157
|
+
function MyComponent() {
|
|
158
|
+
const { theme, colors, setThemeMode } = useTheme();
|
|
159
|
+
|
|
160
|
+
// theme: 'light' | 'dark'
|
|
161
|
+
// colors: current theme colors
|
|
162
|
+
// setThemeMode: 'light' | 'dark' | 'auto'
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## API Services
|
|
167
|
+
|
|
168
|
+
### Making API Calls
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { newsService } from '@services/newsService';
|
|
172
|
+
|
|
173
|
+
// Get all news
|
|
174
|
+
const news = await newsService.getNews({ limit: 10 });
|
|
175
|
+
|
|
176
|
+
// Get single news item
|
|
177
|
+
const newsItem = await newsService.getNewsById('1');
|
|
178
|
+
|
|
179
|
+
// Create news
|
|
180
|
+
const newNews = await newsService.createNews({
|
|
181
|
+
title: 'New Article',
|
|
182
|
+
content: 'Content here',
|
|
183
|
+
// ...
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Custom Hooks
|
|
188
|
+
|
|
189
|
+
### useAuth
|
|
190
|
+
|
|
191
|
+
Access authentication state and methods.
|
|
192
|
+
|
|
193
|
+
### useTheme
|
|
194
|
+
|
|
195
|
+
Access theme configuration and toggle themes.
|
|
196
|
+
|
|
197
|
+
## Components
|
|
198
|
+
|
|
199
|
+
### Button
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
<Button
|
|
203
|
+
title="Click Me"
|
|
204
|
+
variant="primary"
|
|
205
|
+
size="md"
|
|
206
|
+
onPress={() => {}}
|
|
207
|
+
loading={false}
|
|
208
|
+
fullWidth
|
|
209
|
+
/>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Input
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
<Input
|
|
216
|
+
label="Email"
|
|
217
|
+
placeholder="Enter email"
|
|
218
|
+
value={email}
|
|
219
|
+
onChangeText={setEmail}
|
|
220
|
+
error={emailError}
|
|
221
|
+
secureTextEntry
|
|
222
|
+
/>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Card
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
<Card className="mb-4">
|
|
229
|
+
<Text>Card content</Text>
|
|
230
|
+
</Card>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Loading
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
<Loading text="Loading..." fullScreen />
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Path Aliases
|
|
240
|
+
|
|
241
|
+
Use clean imports with configured path aliases:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
import { Button } from '@components/common/Button';
|
|
245
|
+
import { useAuth } from '@hooks/useAuth';
|
|
246
|
+
import { newsService } from '@services/newsService';
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Deployment
|
|
250
|
+
|
|
251
|
+
### Building for Production
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# For Android
|
|
255
|
+
eas build --platform android
|
|
256
|
+
|
|
257
|
+
# For iOS
|
|
258
|
+
eas build --platform ios
|
|
259
|
+
|
|
260
|
+
# For both
|
|
261
|
+
eas build --platform all
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Contributing
|
|
265
|
+
|
|
266
|
+
1. Fork the repository
|
|
267
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
268
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
269
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
270
|
+
5. Open a Pull Request
|
|
271
|
+
|
|
272
|
+
## License
|
|
273
|
+
|
|
274
|
+
MIT License - feel free to use this boilerplate for your projects!
|
|
275
|
+
|
|
276
|
+
## Support
|
|
277
|
+
|
|
278
|
+
For issues and questions, please open an issue on GitHub.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"expo": {
|
|
3
|
+
"name": "APP_NAME",
|
|
4
|
+
"slug": "APP_SLUG",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"orientation": "portrait",
|
|
7
|
+
"icon": "./src/assets/images/icon.png",
|
|
8
|
+
"scheme": "myapp",
|
|
9
|
+
"userInterfaceStyle": "automatic",
|
|
10
|
+
"splash": {
|
|
11
|
+
"image": "./src/assets/images/splash-icon.png",
|
|
12
|
+
"resizeMode": "contain",
|
|
13
|
+
"backgroundColor": "#ffffff"
|
|
14
|
+
},
|
|
15
|
+
"assetBundlePatterns": ["**/*"],
|
|
16
|
+
"ios": {
|
|
17
|
+
"supportsTablet": true,
|
|
18
|
+
"bundleIdentifier": "com.yourname.APP_SLUG"
|
|
19
|
+
},
|
|
20
|
+
"android": {
|
|
21
|
+
"adaptiveIcon": {
|
|
22
|
+
"foregroundImage": "./src/assets/images/adaptive-icon.png",
|
|
23
|
+
"backgroundColor": "#ffffff"
|
|
24
|
+
},
|
|
25
|
+
"package": "com.yourname.APP_SLUG",
|
|
26
|
+
"versionCode": 1
|
|
27
|
+
},
|
|
28
|
+
"web": {
|
|
29
|
+
"bundler": "metro",
|
|
30
|
+
"output": "static",
|
|
31
|
+
"favicon": "./src/assets/images/favicon.png"
|
|
32
|
+
},
|
|
33
|
+
"plugins": [
|
|
34
|
+
"expo-router",
|
|
35
|
+
[
|
|
36
|
+
"expo-secure-store",
|
|
37
|
+
{
|
|
38
|
+
"requireFullDiskAccess": false
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
],
|
|
42
|
+
"experiments": {
|
|
43
|
+
"typedRoutes": true
|
|
44
|
+
},
|
|
45
|
+
"extra": {
|
|
46
|
+
"eas": {
|
|
47
|
+
"projectId": ""
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"updates": {
|
|
51
|
+
"enabled": true,
|
|
52
|
+
"checkAutomatically": "ON_LOAD"
|
|
53
|
+
},
|
|
54
|
+
"runtimeVersion": {
|
|
55
|
+
"policy": "sdkVersion"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "expo-boilerplate",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "expo-router/entry",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"start": "expo start --clear",
|
|
7
|
+
"android": "expo start --android",
|
|
8
|
+
"ios": "expo start --ios",
|
|
9
|
+
"web": "expo start --web",
|
|
10
|
+
"server": "json-server --watch server/db.json --host 10.1.59.172 --port 3001 --middlewares server/middleware.js --routes server/routes.json",
|
|
11
|
+
"dev": "concurrently -n expo,server -c blue,green \"expo start --no-interactive --clear\" \"npm run server\"",
|
|
12
|
+
"lint": "eslint .",
|
|
13
|
+
"type-check": "tsc --noEmit"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"axios": "^1.7.2",
|
|
17
|
+
"babel-preset-expo": "^54.0.5",
|
|
18
|
+
"expo": "~54.0.0",
|
|
19
|
+
"expo-constants": "~18.0.9",
|
|
20
|
+
"expo-linking": "~8.0.8",
|
|
21
|
+
"expo-router": "^6.0.12",
|
|
22
|
+
"expo-secure-store": "~15.0.7",
|
|
23
|
+
"expo-status-bar": "~3.0.8",
|
|
24
|
+
"lucide-react-native": "^0.546.0",
|
|
25
|
+
"nativewind": "^4.0.1",
|
|
26
|
+
"react": "19.1.0",
|
|
27
|
+
"react-native": "^0.81.4",
|
|
28
|
+
"react-native-gesture-handler": "~2.28.0",
|
|
29
|
+
"react-native-reanimated": "~4.1.1",
|
|
30
|
+
"react-native-safe-area-context": "~5.6.0",
|
|
31
|
+
"react-native-screens": "~4.16.0",
|
|
32
|
+
"react-native-worklets": "0.5.1",
|
|
33
|
+
"react-native-svg": "15.12.1",
|
|
34
|
+
"expo-linear-gradient": "~15.0.7"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@babel/core": "^7.26.0",
|
|
38
|
+
"@types/react": "~19.1.10",
|
|
39
|
+
"babel-plugin-module-resolver": "^5.0.2",
|
|
40
|
+
"concurrently": "^8.2.0",
|
|
41
|
+
"eslint": "^9.12.0",
|
|
42
|
+
"eslint-config-prettier": "^9.1.0",
|
|
43
|
+
"json-server": "^0.17.4",
|
|
44
|
+
"prettier": "^3.3.3",
|
|
45
|
+
"tailwindcss": "^3.4.13",
|
|
46
|
+
"typescript": "~5.9.2"
|
|
47
|
+
},
|
|
48
|
+
"private": true,
|
|
49
|
+
"expo": {
|
|
50
|
+
"install": {
|
|
51
|
+
"exclude": ["react", "expo", "expo-constants", "react-native"]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|