지금까지 이 시리즈의 샘플은 전부 화면 파일을 앱 옆에 뒀다. .mbd 폴더가 클라이언트와 같이 배포된다.
둘의 주인이 같으면 그게 맞다. 화면을 바꿀 사람과 앱을 배포할 사람이 같은 사람이니까.
문제는 화면의 주인이 앱의 주인이 아닐 때다.
- 로비에 걸린 디스플레이 — 건물 관리자가 화면을 바꾸고 싶다
- 프랜차이즈 매장 보드 — 본사가 바꾸고 점주는 안 건드린다
- 제조사가 출하하는 패널 — 화면은 제조사 것이고 앱은 통합업체 것이다
이런 경우에 화면을 앱에 넣어 두면 화면을 바꿀 때마다 앱을 다시 배포해야 한다. 그리고 그 배포는 화면을 바꾸고 싶은 사람이 못 한다.
클라이언트가 아무것도 안 갖는다
client ships: no library files at all, and no lib/ directory
server offers: ui://board, data://board
이 샘플의 클라이언트에는 lib/ 디렉터리 자체가 없다. .mbd 번들도 없다. 화면을 설명하는 파일이 클라이언트 쪽에 한 장도 없다.
검증이 그걸 지킨다.
STRAY=$(find bundle_host -name '*.json' -not -path '*/.dart_tool/*' -not -path '*/build/*' -not -name 'package_config.json' | wc -l | tr -d ' ')
[ "$STRAY" -eq 0 ] || { echo " $STRAY json file(s) on the client — it is not screenless"; exit 1; }
[ ! -d bundle_host/lib ] || { echo " the client has a lib/ — it should need none"; exit 1; }
MBD=$(find . -maxdepth 1 -name '*.mbd' | wc -l | tr -d ' ')
[ "$MBD" -eq 0 ] || { echo " there is a bundle here — this sample serves the screen instead"; exit 1; }
이 검사가 이 편의 전부다. 나중에 누가 "편의상" 화면 하나를 클라이언트에 두는 순간 실패한다.
서버가 화면을 리소스로 내놓는다
// The screen itself, as a resource. A client that can read this needs to
// ship nothing.
server.addResource(
uri: _screenUri,
name: 'Board screen',
description: 'The screen definition this board should draw',
mimeType: 'application/json',
handler: (uri, params) async => ReadResourceResult(
contents: [
ResourceContentInfo(
uri: _screenUri,
mimeType: 'application/json',
text: File(_live).readAsStringSync(),
),
],
),
);
화면과 데이터가 다른 리소스다. ui://board 와 data://board.
나눈 이유는 갱신 빈도가 다르기 때문이다. 가격은 하루에도 몇 번 바뀌고 레이아웃은 계절에 한 번 바뀐다. 같이 묶어 두면 가격 하나 바꿀 때마다 레이아웃 전체가 다시 온다.
첫 화면

drew "Board v1" (sha256:592cd36cd4d0, 59 lines) — generation 1
클라이언트는 이 화면을 처음 본다. 코드 어디에도 "Americano" 도 "가격은 오른쪽 정렬" 도 없다.