Shared와 자동 import
UI, API, job과 task가 함께 쓰는 코드와 타입을 한곳에 둡니다.
공통 함수
named export로 선언한 값은 Cake20 View 페이지, API, job과 task에서 import 없이 사용할 수 있습니다. 같은 이름을 두 파일에서 export하면 자동 import 생성이 중단됩니다.
// shared/utils/price.ts
export function formatPrice(value: number) {
return value.toLocaleString("ko-KR") + "원";
}공통 타입
// shared/types/user.d.ts
export interface UserSummary {
id: number;
name: string;
}화면·서버 전용 자동 import
app/types와 app/utils의 named export는 화면 코드에서만 자동 import합니다.
server/types와 server/utils의 named export는 API, route, hook, task와 seed를 포함한 서버 코드에서만 자동 import합니다.
shared/types와 shared/utils의 named export는 화면과 서버 양쪽에서 전역 자동 import합니다.
사용하지 않는 shared, server/types와 server/utils 폴더는 없어도 빌드하며, 빈 선택 폴더를 유지하기 위한 파일은 필요하지 않습니다.
반대 영역이나 shared에서 전용 폴더를 import할 수 없습니다. 양쪽에서 필요한 선언은 shared/types 또는 shared/utils에 둡니다.
// app/utils/money.ts: 화면에서만 사용
export const money = (value: number) => value.toLocaleString("ko-KR");
// server/types/session.d.ts: 서버에서만 사용
export interface SessionData { userId: number }~ 경로 별칭
화면 코드의 ~/는 해당 웹사이트의 app 폴더, 서버 코드의 ~/는 server 폴더를 최상위 경로로 사용합니다.
shared/types와 shared/utils는 전역 자동 import하므로 ~/ 또는 상대 경로로 다시 import하지 않습니다.
app과 server 밖으로 나가는 .. 구간은 현재 실행 영역의 ~ 최상위에서 무효화합니다. shared를 가리키는 정적 import는 저장할 때 제거하고 모듈 객체가 필요한 동적 import는 오류로 안내합니다.
// app/pages/about.tsx
import { browserLang } from "~/lib/browser";
// 화면 코드: ~/lib/browser → app/lib/browser
// 서버 코드: ~/경로 → server/경로Runtime 공통 기능
fetchGet, fetchPost, now, toDate, textDate와 startOfToday는 UI와 서버에서 import 없이 사용합니다. Date의 textFull, addDate 같은 확장 속성과 메서드도 Runtime이 함께 설치합니다.
db 연결과 웹사이트별 Prisma Client 인터페이스는 DB 모델에서 자동 생성됩니다. 이 기능들을 shared/utils에 다시 선언하지 않습니다.
shared는 웹사이트 고유 코드만 둡니다. Runtime 내장 기능을 복사하면 버전 충돌과 자동 import 이름 충돌이 발생할 수 있습니다.
로그인 상태 공유
- auth.login, auth.user, auth.require와 auth.logout만 사용하면 됩니다.
- 내부 세션 저장소와 쿠키 보안 설정은 Cake20이 처리합니다.
- 운영 도메인에서는 Secure 쿠키가 자동으로 적용됩니다.
// server/api/login.post.ts
export const config = {
filter: { userId: z.number() },
sample: { userId: 1 }
};
export default async (data: Input<typeof config.filter>) => {
const login = await auth.login({ id: data.userId });
return Response.json({ ok: true }, {
headers: { "set-cookie": login.cookie }
});
};
// server/api/me.get.ts
export default async (_input: unknown, context: ApiContext) => ({
user: await auth.user(context.request)
});