feat: bootstrap lunch picker miniapp with backend, docs, and branding assets
This commit is contained in:
312
APPS_IN_TOSS_STARTER.md
Normal file
312
APPS_IN_TOSS_STARTER.md
Normal file
@@ -0,0 +1,312 @@
|
||||
# Apps in Toss Starter
|
||||
|
||||
새 프로젝트를 시작할 때 기준으로 쓰는 최소 설정이다.
|
||||
|
||||
## 목표
|
||||
|
||||
- RN `0.84.0` 타깃 번들이 포함된 `.ait` 생성
|
||||
- 불필요한 Granite 플러그인 없이 Apps in Toss 기준으로 안정적으로 시작
|
||||
|
||||
## 기본 원칙
|
||||
|
||||
- `build`는 반드시 `ait build`
|
||||
- `granite.config.ts`에는 `target: '0.84.0'` 명시
|
||||
- `appsInToss({...})` 중심의 최소 구성 유지
|
||||
- `router()`, `hermes()` 같은 추가 Granite 플러그인은 꼭 필요한 경우에만 사용
|
||||
|
||||
## 시작 순서
|
||||
|
||||
### 1. 프로젝트 생성 후 의존성 설치
|
||||
|
||||
프로젝트 루트에서:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### 2. `package.json` 설정
|
||||
|
||||
아래 형태로 맞춘다.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-app",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "granite dev",
|
||||
"build": "ait build",
|
||||
"deploy": "ait deploy",
|
||||
"check:build": "./check-apps-in-toss-build.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apps-in-toss/framework": "^2.4.1",
|
||||
"@granite-js/native": "1.0.10",
|
||||
"@granite-js/react-native": "1.0.10",
|
||||
"brick-module": "0.5.1",
|
||||
"react": "19.2.3",
|
||||
"react-native": "0.84.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "19.2.0",
|
||||
"babel-preset-granite": "1.0.10",
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. `babel.config.js` 추가
|
||||
|
||||
루트에 아래 파일을 반드시 둔다.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
presets: ['babel-preset-granite'],
|
||||
};
|
||||
```
|
||||
|
||||
이 파일이 없으면 `react-native` 패키지 내부 구문을 Metro가 잘못 파싱해서
|
||||
`Missing semicolon` 에러가 날 수 있다.
|
||||
|
||||
### 4. `index.js` 엔트리 설정
|
||||
|
||||
루트 `index.js`는 아래처럼 시작한다.
|
||||
|
||||
```js
|
||||
const { register } = require('@granite-js/react-native');
|
||||
|
||||
register(require('./src/_app').default);
|
||||
```
|
||||
|
||||
그냥 `require('./src/_app')`만 하면 Granite 개발 엔트리포인트인 `shared`가 등록되지 않아
|
||||
`"shared" has not been registered` 에러가 날 수 있다.
|
||||
|
||||
### 5. `granite.config.ts` 설정
|
||||
|
||||
아래처럼 시작한다.
|
||||
|
||||
```ts
|
||||
import { appsInToss } from '@apps-in-toss/framework/plugins';
|
||||
import { defineConfig } from '@granite-js/react-native/config';
|
||||
|
||||
export default defineConfig({
|
||||
appName: 'my-app',
|
||||
scheme: 'intoss',
|
||||
plugins: [
|
||||
appsInToss({
|
||||
target: '0.84.0',
|
||||
brand: {
|
||||
displayName: '내 앱 이름',
|
||||
primaryColor: '#0064FF',
|
||||
icon: 'https://static.toss.im/appsintoss/your-icon.png',
|
||||
},
|
||||
navigationBar: {
|
||||
withBackButton: true,
|
||||
withHomeButton: true,
|
||||
},
|
||||
permissions: [],
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
### 6. `src/pages/_404.tsx` 추가
|
||||
|
||||
파일 기반 라우터가 fallback 페이지를 요구하므로 아래 파일을 기본으로 넣는다.
|
||||
|
||||
```tsx
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { SafeAreaView } from '@granite-js/native/react-native-safe-area-context';
|
||||
|
||||
export default function NotFoundPage() {
|
||||
return (
|
||||
<SafeAreaView style={styles.safeArea}>
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.title}>Page not found</Text>
|
||||
<Text style={styles.description}>
|
||||
요청한 화면을 찾을 수 없습니다.
|
||||
</Text>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
safeArea: {
|
||||
flex: 1,
|
||||
backgroundColor: '#F4F7FB',
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
title: {
|
||||
color: '#111827',
|
||||
fontSize: 24,
|
||||
fontWeight: '700',
|
||||
marginBottom: 8,
|
||||
},
|
||||
description: {
|
||||
color: '#4B5563',
|
||||
fontSize: 15,
|
||||
textAlign: 'center',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 권장하지 않는 시작 방식
|
||||
|
||||
아래는 이유 없으면 넣지 않는다.
|
||||
|
||||
```ts
|
||||
router()
|
||||
hermes()
|
||||
```
|
||||
|
||||
이 조합은 프로젝트에 따라 Apps in Toss 패키징 결과를 꼬이게 만들 수 있다.
|
||||
|
||||
## 개발 명령어
|
||||
|
||||
개발 서버:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
빌드:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
배포:
|
||||
|
||||
```bash
|
||||
npm run deploy
|
||||
```
|
||||
|
||||
검증:
|
||||
|
||||
```bash
|
||||
npm run check:build
|
||||
```
|
||||
|
||||
## 빌드 후 반드시 확인할 것
|
||||
|
||||
### 1. 빌드 로그 확인
|
||||
|
||||
아래 같은 로그가 보여야 한다.
|
||||
|
||||
```text
|
||||
[1/2] Built for RN 0.84.0
|
||||
[2/2] Built for RN 0.72.6
|
||||
```
|
||||
|
||||
### 2. `.ait` 안 번들 확인
|
||||
|
||||
아래 명령으로 확인:
|
||||
|
||||
```bash
|
||||
python3 - <<'PY'
|
||||
import zipfile
|
||||
path='my-app.ait'
|
||||
with zipfile.ZipFile(path) as z:
|
||||
for name in z.namelist():
|
||||
if name.startswith('bundle.') and name.endswith('.js'):
|
||||
print(name)
|
||||
PY
|
||||
```
|
||||
|
||||
정상 예시:
|
||||
|
||||
```text
|
||||
bundle.ios.0_84_0.js
|
||||
bundle.android.0_84_0.js
|
||||
bundle.ios.0_72_6.js
|
||||
bundle.android.0_72_6.js
|
||||
```
|
||||
|
||||
중요한 건 최소한 아래 두 파일이 포함되는 것이다.
|
||||
|
||||
- `bundle.ios.0_84_0.js`
|
||||
- `bundle.android.0_84_0.js`
|
||||
|
||||
## 문제 생겼을 때 체크리스트
|
||||
|
||||
### `지원하지 않는 번들이에요. 최신 SDK를 사용해주세요`가 뜨면
|
||||
|
||||
순서대로 확인:
|
||||
|
||||
1. `granite.config.ts`에 `target: '0.84.0'`가 있는지
|
||||
2. `package.json`의 `build`가 `ait build`인지
|
||||
3. `.ait` 내부에 `bundle.*.0_84_0.js`가 실제로 들어 있는지
|
||||
4. 예전 `.ait` 파일을 업로드한 건 아닌지
|
||||
5. 불필요한 Granite 플러그인을 추가하지 않았는지
|
||||
|
||||
## 새 프로젝트 시작용 빠른 체크
|
||||
|
||||
프로젝트 준비 후 아래만 실행하면 된다.
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
개발 실행 전에는 아래 파일들이 있는지 먼저 확인한다.
|
||||
|
||||
- `babel.config.js`
|
||||
- `index.js`
|
||||
- `src/pages/_404.tsx`
|
||||
|
||||
그 다음 `.ait` 확인:
|
||||
|
||||
```bash
|
||||
python3 - <<'PY'
|
||||
import zipfile
|
||||
import pathlib
|
||||
|
||||
ait_files = sorted(pathlib.Path('.').glob('*.ait'))
|
||||
if not ait_files:
|
||||
raise SystemExit('No .ait file found')
|
||||
|
||||
path = str(ait_files[0])
|
||||
print(path)
|
||||
|
||||
with zipfile.ZipFile(path) as z:
|
||||
for name in z.namelist():
|
||||
if name.startswith('bundle.') and name.endswith('.js'):
|
||||
print(name)
|
||||
PY
|
||||
```
|
||||
|
||||
## 실전 기준 요약
|
||||
|
||||
- 새 프로젝트는 Apps in Toss 최소 설정으로 시작
|
||||
- `build`는 `ait build`
|
||||
- `target: '0.84.0'` 필수
|
||||
- `.ait`에 `0_84_0` 번들이 있는지 꼭 확인
|
||||
|
||||
## 템플릿 폴더
|
||||
|
||||
`starter/template` 폴더에는 새 프로젝트 시작용 기본 파일 세트를 넣어뒀다.
|
||||
|
||||
- `package.json`
|
||||
- `granite.config.ts`
|
||||
- `babel.config.js`
|
||||
- `index.js`
|
||||
- `tsconfig.json`
|
||||
- `require.context.ts`
|
||||
- `.watchmanconfig`
|
||||
- `src/_app.tsx`
|
||||
- `src/pages/index.tsx`
|
||||
- `src/pages/_404.tsx`
|
||||
- `check-apps-in-toss-build.sh`
|
||||
|
||||
새 프로젝트를 만들 때는 이 폴더 내용을 복사한 다음 아래 값만 먼저 바꾸면 된다.
|
||||
|
||||
- `package.json`의 `name`
|
||||
- `granite.config.ts`의 `appName`
|
||||
- `granite.config.ts`의 `brand.displayName`
|
||||
- `granite.config.ts`의 `brand.icon`
|
||||
- `src/pages/index.tsx`의 화면 문구
|
||||
Reference in New Issue
Block a user