앱 만들기를 빠르게 시작하려면 Obelisk를 쓰든가, reflex-platform을 씁니다.
obsidiansystems/obelisk
고퀄의 웹, 모바일 앱을 Reflex를 써서 매우 빠르게 만들 수 있다고 합니다. 아직은 제대로 안 써봐서 얼마나 빠르게 만들 수 있을까 싶습니다. 같은 하스켈 코드로 Web, iOS, Android, MacOS, Linux에서 돌아가게 만들 수 있다고 하니, 일단 눈이 갑니다.
명령행에서 쓰는 CLI툴입니다.
reflex
를 써서 프론트 엔드 뼈대를 만듭니다.snap
을 써서 백엔드 뼈대를 만듭니다.ob run
파일에 저장하면 자동으로 앱을 리빌드 합니다. jsaddle-warp를 쓰는 프론트엔드를 제공합니다.ob repl
ghci 쉘ob deploy
EC2에 배포하는 걸 도와줍니다. 최적화하고 짧게 만든 js를 생성합니다.obelisk-route
Reflex를 쓰는 하스켈 패키지를 다양한 플래폼에서 돌아가게 빌드할 수 있는 엄선된curated 패키지 세트 및 도구 입니다. 닉스 패키지 매니저로 돌릴 닉스 표현식 모음과 ghc, ghcjs를 쓰기 위한 스크립트 모음이라 보면 됩니다.
GHCJS로 컴파일하면, 메모리를 엄청 잡아 먹습니다. 최소 8GB, 권장 16GB라 합니다.
TMPDIR
디렉토리도,/nix/store
도 꽤 잡아 먹습니다.
공부용이나, 작은 프로젝트는 try-reflex
스크립트를 돌려서 환경을 잡으면 되는데, 큰 프로젝트는 cabal을 쓰는 게 좋다 합니다. cabal로 환경 잡기
※ try-reflex
를 실행하는데, 세 시간이 넘게 걸리고, 디스크 용량은 거의 30GB를 먹었습니다. 환경마다 다르겠지만, 엔간한 장비에선 긴 시간이 필요한 작업 같습니다.
실행 후 한참을 기다렸는데, 믿었던 닉스가
No space left on device
오류를 뱉습니다. 설치할 곳의 공간은 여유가 있는데도 계속 오류가 나서, 찾아 보니 닉스가 쓰는 임시 폴더 용량이 문제였습니다.
export TEMP=/other/sufficientDir
혹은
export TMPDIR=/other/sufficientDir
을 했는데도
임시 디렉토리를 사용하는 곳이 바뀌지 않았습니다. 닉스가 딱히 시스템 수준의 환경 변수를 읽어가지 않나 봅니다. 시스템 수준의 환경 변수가 아닌 데몬을 위한 환경 변수를 잡아주어 성공했습니다. 데비안6.1.66-1 (2023-12-09) 환경.
sudo vim /etc/systemd/system/nix-daemon.service
[Service] ... Environment=TMPDIR=/other/sufficientDir
위와 같이 추가하고
sudo systemctl daemon-reload
sudo service nix-daemon restart
※ NTFS 파티션에 잡으니 cp: perserving times for …: Operation not permitted 오류가 납니다.
reflex
콜백 스타일을 쓰지 않고, side effect도 없이 인터랙티브 프로그램을 만듭니다. 조합compositable 가능한 이벤트와 시간에 따라 변하는 값을 써서 인터랙티브 시스템을 순수 함수로 표현합니다.
DOM 생성 코드와는 무관합니다. reflex는 reflex-dom의 기반이긴 하지만, 꼭 웹 관련 앱이 아니더라도 FRP 아키텍처로 구현할 때 쓸 수 있습니다.
reflex-dom-core와 reflex-dom
DOM 위젯, 웹 소켓, XHR 요청을 만들기 위한 API를 제공합니다.
이론에 대한 설명은 딱히 같이 하지 않아, Reflex만 보는 분들은 다른 쪽(FRAN, Yampa, reactive-banana, …) 문서들을 참고해야겠습니다.
Behavior
시간에 따라 변하는 값을 위한 컨테이너. 샘플링할 수는 있지만, 자신이 변한다고 외부에 알릴 방법은 없습니다.
Behavior t a
모든 시간에 값이 존재해야 하는데, 만일 그렇지 않은 값을 Behavior
로 모델링 한다면 Behavior t (Maybe a)
를 써야 합니다. Behavior 값들은 tag
나 attach
함수를 써서 Event로 태깅할 수 있습니다. 처음 생성할 때 sample
함수를 쓰면 위젯 안에서 샘플링될 수 있습니다.
Event
Event t a
버튼 클릭 Event t ()
키 누름 Event t Char
다른 프레임워크에서 이벤트 네트워크라 부르는 걸, 여기선 이벤트-전파-그래프라 부르는 것 같습니다. 외부 값(외부 이벤트)을 이벤트-전파-그래프에 넣을 때는 newTriggerEvent
IO 액션을 씁니다.
newTriggerEvent :: TriggerEvent t m => m (Event t a, a -> IO ())
Dynamic
Event와 Behavior를 튜플에 담아 둔 것
DOM API는 기본적으로 push-기반입니다. 그래서 Behavior를 쓸 곳에 Dynamic을 쓰는 경우가 많습니다.
Dynamic
값에 updated
를 적용해서, 값이 변했을 때 이벤트를 얻을 수 있습니다.
updated :: (Reflex t) => Dynamic t a -> Event t a
타임라인 t
는 FRP 컨텍스트와 별 개입니다. 단일 프로그램이 Reflex를 여러 컨텍스트에서 돌릴 경우 꼬이지 않게 해줍니다.?
위젯과 위젯들을 연결하는 접착glue 코드로 구성됩니다. 위젯은 Event나 Dynamic value에 따라 컨텐츠를 수정할 수 있는 능력을 가진 DOM 구조의 무언가로 볼 수 있습니다. 이벤트를 발생시키는 input field 같은 구조들도 있습니다. 위젯들은 마우스 클릭같은 사용자 인터랙션에 반응할 수 있습니다. (이 걸 위젯이 마우스 클릭을 캡처한다고 말하기도 합니다.)
“오브젝트” 트리
모나드 DomBuilder
로 DOM 생성 작업을 합니다.
ghcjs
ghc같은 컴파일러
ghcjs-dom
DOM과 웹API와 쓰일 인터페이스 API를 제공하는 라이브러리
KDE의 KHTML과 KJS에 파생된 웹 컨텐트 엔진. Apple 사파리 브라우저에 쓰입니다. HTML, SVG, XML 등을 디스플레이할 때 쓰입니다. DOM, XMLHttpRequest, XSLT, CSS, Javascript/ECMAscript 등을 지원합니다.