Jaspr 웹 아키텍처 가이드 (v0.22.x)
목표
Jaspr는 Dart 기반 웹 프레임워크입니다 (현재 버전: 0.22.x).
Flutter Web이 Canvas를 통해 픽셀을 그리고 SEO에 취약한 반면, Jaspr는 Dart를 시맨틱 HTML 및 CSS DOM 요소로 컴파일합니다. 웹사이트, 블로그, 랜딩 페이지 또는 적절한 SEO가 필요한 모든 프로젝트에 Jaspr를 사용하세요.
지침
1. 핵심 개념: Flutter와 유사한 코딩 경험
Jaspr는 Flutter의 컴포넌트 모델을 미러링합니다. build 메서드는 단일 Component(Flutter의 Widget에 해당)를 반환합니다.
| Flutter 개념 | Jaspr 개념 | 참고 사항 |
|---|---|---|
Widget | Component | Jaspr의 모든 UI 요소는 Component입니다. |
StatelessWidget | StatelessComponent | 순수 선언형 UI; BuildContext context를 받습니다. |
StatefulWidget | StatefulComponent | setState, initState, createState()로 라이프사이클을 관리합니다. |
InheritedWidget | InheritedComponent | 컴포넌트 트리 아래로 상태를 전파합니다. |
1.1 DOM 요소
Jaspr는 DOM으로 렌더링되므로 jaspr/dom.dart에서 HTML 태그 헬퍼(div, p, img 등)를 사용합니다.
import 'package:jaspr/jaspr.dart';
class ProfileCard extends StatelessComponent {
final String name;
const ProfileCard({required this.name, super.key});
@override
Component build(BuildContext context) {
return div(
classes: 'profile-card',
styles: Styles.box(width: 300.px, backgroundColor: Colors.white),
[
h2([.text(name)]), // 🌟 Dart 3.10부터 사용 가능한 .text() 단축 문법 (Component.text)
p([
.text('Hello World!'),
]),
button(
onClick: () => print('버튼이 성공적으로 클릭되었습니다!'),
[.text('연락하기')]
)
]
);
}
}
2. Tailwind CSS 통합 (jaspr_tailwind)
Jaspr는 jaspr_tailwind를 통해 공식 Tailwind CSS 통합을 제공합니다.
2.1 설치 및 설정
dev_dependencies:
jaspr_tailwind: ^0.1.0
Tailwind v4 CSS 우선 문법으로 web/styles.tw.css를 생성합니다:
/* web/styles.tw.css */
@import "tailwindcss";
2.2 루트 컴포넌트에 컴파일된 CSS 로드
루트 컴포넌트에서 Document를 사용하여 컴파일된 스타일시트를 연결하고 classes 매개변수를 통해 Tailwind 클래스를 사용합니다:
import 'package:jaspr/jaspr.dart';
class App extends StatelessComponent {
@override
Component build(BuildContext context) {
return Document(
head: [
// 🌟 jaspr_tailwind가 styles.tw.css를 styles.css로 자동 컴파일
link(href: 'styles.css', rel: 'stylesheet'),
],
body: div(
// Tailwind 클래스를 직접 사용; 개발 중 jaspr_tailwind가 자동 새로고침
classes: 'bg-gray-100 min-h-screen flex items-center justify-center',
[
h1(classes: 'text-4xl font-bold text-blue-600', [.text('안녕 Tailwind!')]),
]
),
);
}
}
3. 라우팅 (jaspr_router)
Jaspr의 라우팅은 선언형 API를 가진 go_router를 미러링합니다.
3.1 설치 및 설정
dependencies:
jaspr_router: ^0.2.0
import 'package:jaspr/jaspr.dart';
import 'package:jaspr_router/jaspr_router.dart';
class MyApp extends StatelessComponent {
@override
Component build(BuildContext context) {
return Router(
routes: [
Route(
path: '/',
builder: (context, state) => const HomePage(),
),
Route(
path: '/about',
builder: (context, state) => const AboutPage(),
),
],
);
}
}
4. SSR: 비동기 백엔드 데이터 프리로딩
Jaspr가 Flutter Web보다 가지는 주요 이점은 서버 사이드 렌더링(SSR)입니다. Flutter Web에서는 initState에서 데이터를 가져와 클라이언트에서 로딩 상태가 발생하지만, Jaspr SSR에서는 HTML이 브라우저로 전송되기 전에 서버에서 데이터를 가져옵니다.
4.1 AsyncStatelessComponent (서버 전용)
jaspr/server.dart를 import하여 AsyncStatelessComponent를 사용하면 async build 메서드를 사용할 수 있습니다.
import 'package:jaspr/server.dart'; // 🌟 서버 전용 import
class ArticlePage extends AsyncStatelessComponent {
final String articleId;
const ArticlePage(this.articleId);
@override
Future<Component> build(BuildContext context) async {
// 서버 측에서 실행됨; 자유롭게 await를 사용하여 데이터베이스/API 호출
final articleData = await Database.fetchArticle(articleId);
// 브라우저는 완전히 렌더링된 HTML을 수신하여 즉각적이고 SEO 친화적인 콘텐츠를 제공
return div([
h1([.text(articleData.title)]),
p([.text(articleData.content)]),
]);
}
}
4.2 상태 저장 프리로딩 (PreloadStateMixin)
상태를 유지해야 하는 경우 PreloadStateMixin을 믹스인합니다:
class MyState extends State<MyStatefulComponent> with PreloadStateMixin {
@override
Future<void> preloadState() async {
// initState() 이전에 서버 측에서 실행됨; 클라이언트 측 하이드레이션을 위해 상태를 준비
await loadInitialData();
}
// ...
}
5. 테스팅 (jaspr_test)
jaspr_test는 컴포넌트 단위 테스트, SSR 결과 및 브라우저 상호작용을 다룹니다.
5.1 종속성 설정
dart pub add jaspr_test --dev
jaspr_test는 기본 package:test를 다시 내보내므로 별도로 import할 필요가 없습니다.
5.2 세 가지 주요 테스팅 함수
HTML/웹 환경의 복잡성으로 인해 Jaspr는 세 가지 시나리오별 테스팅 함수를 제공합니다:
testComponents (가상 환경 컴포넌트 테스팅)
헤드리스 순수 Dart 시뮬레이션 환경에서 컴포넌트 로직을 단위 테스트합니다. 가장 빠른 방법입니다. 사용법은 Flutter의 testWidgets와 매우 유사합니다.
import 'package:jaspr_test/jaspr_test.dart';
void main() {
testComponents('버튼 클릭 시 카운트가 증가하는지 테스트', (tester) async {
tester.pumpComponent(MyComponent());
expect(find.text('카운트: 0'), findsOneComponent);
await tester.click(find.tag('button'));
expect(find.text('카운트: 1'), findsOneComponent);
});
}
testServer (서버 사이드 렌더링 테스팅)
SSR 애플리케이션 테스팅을 대상으로 합니다. 시뮬레이션된 로컬 HTTP 서버를 직접 시작합니다. 요청을 보내고 서버가 반환하는 HTML 문자열이나 상태 속성을 확인할 수 있습니다.
import 'package:jaspr_test/jaspr_test.dart';
void main() {
testServer('서버 사이드 렌더링 HTML 확인', (tester) async {
final response = await tester.request('/');
expect(response.document.body?.text, contains('SSR에 오신 것을 환영합니다'));
});
}
testClient (브라우저 하이드레이션 및 상태 동기화 테스팅)
헤드리스 브라우저 환경에서 실행되며, 클라이언트가 서버로부터 initialStateData를 받은 후 하이드레이션을 통해 올바르게 인계받고 DOM 상호작용을 처리하는지 테스트합니다.
제약 사항
AsyncStatelessComponent는 서버 측(jaspr/server.dart)에서만 사용하세요. 클라이언트 UI 코드에서는 절대 사용하지 마십시오.- Flutter
Widget을 JasprComponent내부에 중첩하지 마십시오. - 렌더 모드에 맞는 테스터를 선택하세요: SSR →
testServer, CSR →testComponents, 브라우저 →testClient. 엄격한 타입 매칭보다 DOM 문자열 매칭을 선호합니다.