노드에서 clojurescript 용 웹 프레임 워크.

장고, 플라스크 및 레일의 전통에서. 빨리 배송되는 인디 개발자를 위해 설계되었습니다. 실제 사이트에서 전투 테스트.
철학 | 빠른 시작 | 문서 | API | 예 | 지역 사회
( ns webserver
( :require
[promesa.core :as p]
[sitefox.html :refer [render]]
[sitefox.web :as web]))
( defn root [_req res]
( ->> ( render [ :h1 " Hello world! " ])
( .send res)))
( p/let [[app host port] ( web/start )]
( .get app " / " root)
( print " Serving on " ( str " http:// " host " : " port)))PORT -PORT SiteFox 웹 서버 바인딩 구성.BIND_ADDRESS IP 주소 사이트 Fox 웹 서버를 구성합니다.SMTP_SERVER 발신 SMTP 서버 구성 예를 들어 SMTP_SERVER=smtps://username:[email protected]/?pool=true .DATABASE_URL 연결할 데이터베이스를 구성합니다. 기본값으로 sqlite://./database.sqlite . 시작하는 가장 빠른 방법은 하나의 명령으로 예제 프로젝트를 설정하는 create Scripts 중 하나를 사용하는 것입니다. 양식 제출 이상의 프론트 엔드 상호 작용이없는 간단한 웹 사이트를 구축하는 경우 NBB 제작 스크립트가 다음과 같습니다.
npm init sitefox-nbb mywebsite
이렇게하면 새 프로젝트가 포함 된 mywebsite 라는 폴더가 생성됩니다. 참고 Scittle을 사용하여 CLJS 클라이언트면을 실행할 수 있습니다.
풀 스택 Clojurescript 응용 프로그램을 작성하는 경우 Shadow-Cljs 작성 스크립트는 다음과 같습니다.
npm init sitefox-shadow-fullstack myapp
새 프로젝트가 포함 된 myapp 라는 폴더가 생성됩니다.
종속성으로 프로젝트에 SiteFox를 추가하십시오.
{:deps
{io.github.chr15m/sitefox {:git/tag "v0.0.26" :git/sha "e6ea2027b5d4277917732d43d550083c8e105da9"}}}
npm 사용하는 경우 SiteFox를 종속성으로 설치할 수 있습니다. 그렇게하면 어떻게 든 클래스 경로에 node_modules/sitefox/src 추가해야합니다.
npm i sitefox
참고 : M1 Mac 사용자는 다음과 같은 NPM에서 Python 버전을 설정해야 할 수도 있습니다.
npm config set python python3
node-sqlite3 빌드는 때때로 설정없이 실패하기 때문입니다. 자세한 내용은이 문제를 참조하십시오.
두 개의 경로가있는 예제 서버 (그 중 하나는 값을 키 값 데이터베이스에 기록합니다.
( ns my.server
( :require
[promesa.core :as p]
[sitefox.web :as web]
[sitefox.db :refer [kv]]))
( defn home-page [req res]
; send a basic hello world response
( .send res " Hello world! " ))
( defn hello [req res]
; write a value to the key-value database
( p/let [table ( kv " sometable " )
r ( .write table " key " 42 )]
( .json res true )))
( defn setup-routes [app]
; flush all routes from express
( web/reset-routes app)
; set up an express route for "/"
( .get app " / " home-page)
; set up an express route for "/hello"
( .post app " /hello " hello)
; statically serve files from the "public" dir on "/"
; (or from "build" dir in PROD mode)
( web/static-folder app " / " " public " ))
( defn main! []
; create an express server and start serving
; BIND_ADDRESS & PORT env vars set host & port.
( p/let [[app _host _port] ( web/start )]
; set up the routes for the first time
( setup-routes app)))더 많은 SiteFox 예제.
SiteFox에 대한 지원이 필요한 경우 다음을 수행 할 수 있습니다.
SiteFox는 세션 및 로깅에 대해 현명한 기본값으로 Express 웹 서버를 사용합니다. 자세한 내용은 Express 라우팅 문서를 참조하십시오.
web/start 으로 새 서버를 만들고 "Hello World!"로 응답하는 경로를 설정하십시오. 다음과 같이 :
( -> ( web/start )
( .then ( fn [app host port]
( .get app " /myroute "
( fn [req res]
( .send res " Hello world! " )))) SiteFox에는 서버가 변경 될 때 경로를 다시로드 할 수있는 옵션 시스템이 제공됩니다. 서버 코드가 새로 고침 될 때마다 (예 : Shadow-Cljs 빌드에 의해) Express 경로가 다시로드됩니다. 이 예에서는 재 구축이 발생할 때 기능 setup-routes 호출됩니다.
( defn setup-routes [app]
; flush all routes from express
( web/reset-routes app)
; ask express to handle the route "/"
( .get app " / " ( fn [req res] ( .send res " Hello world! " ))))
; during the server setup hook up the reloader
( reloader ( partial #'setup-routes app)) Promise Control 흐름을 관리하기위한 Promesa 라이브러리를 권장합니다. 이 예제는 [promesa.core :as p] 요구한다고 가정합니다.
( p/let [[app host port] ( web/start )]
; now use express `app` to set up routes and middleware
)또한 다음을 참조하십시오.
SiteFox는 템플릿 대신 서버 사이드 시약 렌더링을위한 바로 가기를 제공하고 병합 된 HTML 문서를 제공합니다.
[sitefox.html :refer [render-into]]HTML 문서를로드하고 시약 양식을 선택한 요소로 렌더링 할 수 있습니다.
( def index-html ( fs/readFileSync " index.html " ))
( defn component-main []
[ :div
[ :h1 " Hello world! " ]
[ :p " This is my content. " ]])
; this returns a new HTML string that can be returned
; e.g. with (.send res)
( render-into index-html " main " [component-main])SiteFox는 Node-HTML-Parser를 사용하며 HTML 및 시약 작업을위한 바로 가기를 제공합니다.
html/parse node-html-parser/parse 의 경우 속기입니다.html/render 시약의 render-to-static-markup 대한 속기입니다.html/$ Parser의 querySelector 의 속기입니다.html/$$ Parser의 querySelectorAll 의 속기입니다.또한 템플릿 예제 프로젝트를 참조하십시오.
SiteFox를 사용하면 구성없이 키 값 데이터를 쉽게 저장할 수 있습니다. 필요한 경우 나중에보다 구조화 된 데이터로 전환 할 수 있습니다. Keyv는 Keyvalue 스토어를 뒷받침하는 데이터베이스입니다. db/kv 와 db/client 통해 기본 데이터베이스를 통해 키 값 스토어에 액세스 할 수 있습니다.
DB 모듈의 전체 문서를 참조하십시오.
기본적으로 로컬 SQLITE 데이터베이스가 사용되며 구성없이 즉시 서버에서 데이터를 지속 할 수 있습니다. 생산으로 이동하면 환경 변수 DATABASE_URL 사용하여 다른 데이터베이스를 구성 할 수 있습니다. 예를 들어, "dbname"이라는 Postgres 데이터베이스를 사용하려면 다음과 같이 액세스 할 수 있습니다 (네트워크/로컬 설정에 따라 다름).
DATABASE_URL="postgres://%2Fvar%2Frun%2Fpostgresql/DBNAME"
DATABASE_URL=postgres://someuser:somepassword@somehost:5432/DBNAME
DATABASE_URL=postgres:///somedatabase
Postgres 백엔드를 사용하려면 npm install @keyv/postgres 도 필요합니다.
데이터베이스 및 키 값 인터페이스를 사용하려면 먼저 데이터베이스 모듈이 필요합니다.
[sitefox.db :as db] 이제 db/kv 사용하여 네임 스펙이있는 "테이블"에 키 값을 작성할 수 있습니다.
( let [table ( db/kv " sometable " )]
( .set table " key " " 42 " ))값을 다시 검색하십시오.
( -> ( .get table " key " )
( .then ( fn [val] ( print val)))) db/client 사용하여 기본 데이터베이스 클라이언트에 액세스 할 수 있습니다. 예를 들어 구성된 데이터베이스에 대해 쿼리를 만들려면 다음과 같습니다.
( let [c ( db/client )]
( -> ( .query c " select * from sometable WHERE x = 1 " )
( .then ( fn [rows] ( print rows)))))다시 한 번, 데이터베이스 작업 중에 제어 흐름을 관리하는 데 Promesa가 권장됩니다.
명령 줄에서 키 값 데이터를 탐색하려면 SQLITE 및 JQ를 사용하여 다음과 같은 데이터를 필터링하십시오.
sqlite3 database.sqlite "select * from keyv where key like 'SOMEPREFIX%';" | cut -f 2 -d "|" | jq '.'
기본적으로 node-sqlite3 모듈은 데이터베이스 오류가 발생할 때 라인 번호 등이있는 전체 스택 추적을 제공하지 않습니다. 다음과 같이 작은 성능 페널티로 Verbose 스택 추적을 켜는 것이 가능합니다.
( ns yourapp
( :require
[ " sqlite3 " :as sqlite3]))
( .verbose sqlite3) 프로덕션에서 SQLITE3을 실행하려면 오류 SQLITE_BUSY: database is locked . 다음과 같이 SQLITE3에서 쓰기 로깅 모드를 활성화하여 이러한 동시성 및 잠금 문제를 해결할 수 있습니다.
(ns yourapp
(:require
[sitefox.db :refer [client]]))
(p/let [c (client)
wal-mode-enabled (.query c "PRAGMA journal_mode=WAL;")]
(js/console.log wal-mode-enabled))
이 코드는 서버 코드의 주요 기능에 안전하게 배치 할 수 있습니다.
세션은 기본적으로 활성화되며 서버의 각 방문자는 자체 세션을 갖습니다. 세션 데이터는 페이지로드를 가로 질러 서버 측면으로 유지되므로 예를 들어 인증 상태를 저장할 수 있습니다. 세션은 네임 스패닝 된 kv 테이블로 뒷받침됩니다 (위의 데이터베이스 섹션 참조). req.session 사용하여 세션에 임의의 JS 데이터 구조를 읽고 쓸 수 있습니다.
세션 스토어에 값을 작성하려면 (경로 처리기 기능 내부) :
( let [session ( aget req " session " )]
( aset session " myvalue " 42 ))세션 스토어에서 값을 읽으려면 :
( aget req " session " " myvalue " )SiteFox는 여권 라이브러리를 감싸서 인증을 구현합니다. 세 가지 기능 호출로 간단한 이메일 및 비밀번호 기반 인증을 앱에 추가 할 수 있습니다.
( defn setup-routes [app]
( let [template ( fs/readFileSync " index.html " )]
( web/reset-routes app)
; three calls to set up email based authentication
( auth/setup-auth app)
( auth/setup-email-based-auth app template " main " )
( auth/setup-reset-password app template " main " )
; ... add your additional routes here ... ;
)) 전달 된 template 문자열은 HTML 문서이고 "main" 은 Auth UI를 장착 할 위치를 지정하는 선택기입니다. 이렇게하면 기본적으로 다음 경로가 설정되어 사용자를 보낼 수 있습니다.
/auth/sign-in/auth/sign-up/auth/reset-password기본 인증 UI 시약 양식과 리디렉션 URL을 재정의하여 자신의 버전으로 사용자 정의 할 수도 있습니다. 자신의 시약 양식을 제공하는 방법에 대한 자세한 내용은 인증 문서를 참조하십시오. 또한 직접 만들고 싶다면 기본 시약 인증 양식의 소스 코드를 참조하십시오.
사용자가 가입하면 데이터가 SiteFox에서 사용하는 기본 keyV 데이터베이스에 유지됩니다. 요청 객체에서 현재 인증 된 사용자의 데이터 구조를 검색 할 수 있습니다.
( let [user ( aget req " user " )] ...) 그런 다음 사용자의 데이터를 업데이트하고 데이터를 데이터베이스에 다시 저장할 수 있습니다. applied-science.js-interop 라이브러리는 이것에 편리합니다 (여기서는 j 로 필요) :
( p/let [user ( aget req " user " )]
( j/assoc! user :somekey 42 )
( auth/save-user user)) 새 테이블을 만들려면 사용자의 UUID (aget user "id") 로 얻을 수있는 사용자의 UUID에 키를 키우는 것이 유용합니다.
자세한 내용은 인증 예제를 참조하십시오.
사용자 이름 기반 또는 제 3 자 OAUTH와 같은 새로운 인증 체계를 추가하려면 여권 문서 및 Auth.Cljs를 참조하십시오. 가장 좋은 환영 요청을 당기십시오!
Sitefox는 이메일을 보내기 위해 NodeMailer를 번들로 묶습니다. 나가는 SMTP 서버 구성 :
SMTP_SERVER=smtps://username:[email protected]/?pool=true
그런 다음 다음과 같이 send-email 기능을 사용할 수 있습니다.
( -> ( mail/send-email
" [email protected] "
" [email protected] "
" This is my test email. "
:text " Hello, This is my first email from **Sitefox**. Thank you. " )
( .then js/console.log)) 기본적으로 전송 된 이메일은 JSON-LINES 형식의 ./logs/mail.log 에 로그인됩니다.
SMTP 서버를 지정하지 않으면 이메일 모듈이 디버그 모드에 있습니다. 전자 메일이 전송되지 않으며, 나가는 이메일은 검사를 위해 /tmp 에 기록되며, send-email 결과는 콘솔에 로그인됩니다.
SMTP_SERVER=ethereal 설정하면 Ethereal.email 서비스가 사용됩니다. send-email 실행하면 결과의 url 속성을 인쇄 할 수 있습니다. DEV 모드에서 이메일을 테스트하기 위해 인쇄 된 링크를 사용할 수 있습니다.
Send-Email 예제 프로젝트도 참조하십시오.
노드 입력 밸리 디터를 사용하고 CSRF 문제를 확인하는 양식 유효성 검사 예제를 참조하십시오.
CSRF 경고없이 POST 할 수 있도록 이와 같은 숨겨진 요소 (시약 구문)를 만들어야합니다.
[ :input { :name " _csrf " :type " hidden " :default-value ( .csrfToken req)}] 클라이언트 측에서 AJAX POST 요청을하는 경우 CSRF 토큰을 헤더로 전달해야합니다. 유효한 토큰은 JSON Endpoint /_csrf-token 에서 문자열로 사용할 수 있으며 fetch-csrf-token 사용하여 가져와 다음과 같이 Fetch 요청의 헤더에 추가 할 수 있습니다.
( ns n ( :require [sitefox.ui :refer [fetch-csrf-token]]))
( -> ( fetch-csrf-token )
( .then ( fn [token]
( js/fetch " /api/endpoint "
#js { :method " POST "
:headers #js { :Content-Type " application/json "
:X-XSRF-TOKEN token} ; <- use token here
:body ( js/JSON.stringify ( clj->js some-data))})))) 참고 : 환경 변수 SEND_CSRF_TOKEN 설정하면 클라이언트 측 쿠키에서 CSRF 토큰을 가져올 수 있습니다. 이것은 이전 SiteFox 버전의 기본값이었습니다. 설정하면 SiteFox는 클라이언트 측 쿠키 XSRF-TOKEN 의 모든 GET 요청에서 토큰을 보내며 ui/csrf-token 기능으로 검색 할 수 있습니다. 이것은 유효하지만 덜 안전한 형태의 CSRF 보호입니다.
드문 상황에서는 CSRF 검사를 끄는 것을 원할 수 있습니다 (예 : 비 브라우저 장치에서 API에 게시). 당신이 무엇을하고 있는지 알고 있다면 pre-csrf-router 사용하여 CSRF 점검을 우회하는 경로를 추가 할 수 있습니다.
( defn setup-routes [app]
; flush all routes from express
( web/reset-routes app)
; set up an API route bypassing CSRF checks
( .post ( j/get app " pre-csrf-router " ) " /api/endpoint " endpoint-unprotected-by-csrf)
; set up an express route for "/hello" which is protected as normal
( .post app " /hello " hello)) 기본적으로 웹 서버는 ./logs 폴더의 로그 파일에 기록됩니다. 이 파일은 서버에 의해 자동으로 회전됩니다. 로그에는 두 가지 유형이 있습니다.
logs/access.log .tracebacks/install-traceback-handler 사용하여 TraceBacks가 작성되는 logs/error.log .오류 로그에 가입하지 않은 예외를 보내려면 :
(def admin-email (env-required "ADMIN_EMAIL"))
(def build-id (try (fs/readFileSync "build-id.txt") (catch :default _e "dev")))
(install-traceback-handler admin-email build-id)
다음과 같이 현재 git 커밋을 기반으로 build-id.txt 작성하십시오.
git rev-parse HEAD | cut -b -8 > build-id.txt
Tracebacks에서 올바른 clojurescript 줄 번호를 얻으려면 ["source-maps-support" :as sourcemaps] 다음 :
(.install sourcemaps)
web/setup-error-handler 기능을 사용하여 정의하는 시약 구성 요소를 기반으로 해당 오류의 페이지를 제공 할 수 있습니다.
( defn component-error-page [_req error-code error]
[ :section.error
[ :h2 error-code " Error " ]
( case error-code
404 [ :p " We couldn't find the page you're looking for. " ]
500 [ :<> [ :p " An error occurred: " ] [ :p ( .toString error)]]
[ :div " An unknown error occurred. " ])])
( web/setup-error-handler app my-html-template " main " component-error-page)이를 결합하여 500 개의 내부 서버 오류와 다음과 같은 예외를 모두 포착 할 수 있습니다.
(let [traceback-handler (install-traceback-handler admin-email build-id)]
(web/setup-error-handler app template-app "main" component-error-page traceback-handler))
라이브 재 장전은 nbb 및 shadow-cljs 사용하여 지원됩니다. NPM 작성 스크립트를 사용할 때는 기본적으로 활성화됩니다. 예에 더 자세한 내용이 있습니다.
SiteFox는 Chris McCormick (Twitter의 @MCCRMX 및 Mastodon의 [email protected])에 의해 만들어졌습니다. 나 자신과 고객을 위해 사이트를 구축하는 동안 반복했습니다.