ノード上のCrojureScriptのWebフレームワーク。

ダジャンゴ、フラスコ、レールの伝統で。速く出荷するインディー開発者向けに設計されています。実際のサイトでテストされた戦闘。
哲学|クイックスタート|ドキュメント| 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 - ポートサイトFox Webサーバーの構成にバインドします。BIND_ADDRESS -IPアドレスSitefox Webサーバーを構成します。SMTP_SERVER -OUNGOVINGER SMTPサーバーなどの構成SMTP_SERVER=smtps://username:[email protected]/?pool=true 。DATABASE_URL接続するデータベースを構成します。デフォルトはsqlite://./database.sqliteです。 開始する最も簡単な方法は、1つのコマンドを使用して模範プロジェクトを設定するcreateスクリプトの1つを使用することです。フォームの提出を超えたフロントエンドのインタラクティブに多くのシンプルなWebサイトを構築している場合、NBB Createスクリプトは次の方法です。
npm init sitefox-nbb mywebsite
これにより、新しいプロジェクトを含むmywebsiteというフォルダーが作成されます。注意Scittleを使用してCLJSクライアント側を実行できます。
フルスタックのClojureScriptアプリケーションを構築している場合、Shadow-Cljs Create Scriptは次の方法です。
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何らかの形でClassPathに追加する必要があります。
npm i sitefox
注:M1 Macユーザーは、このようにNPMでPythonバージョンを設定する必要がある場合があります。
npm config set python python3
これは、 node-sqlite3ビルドが設定なしで故障することがあるためです。詳細については、この問題を参照してください。
2つのルートを備えたサンプルサーバー。そのうちの1つはキー値データベースに値を書き込みます。
( 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は、セッションとロギングに賢明なデフォルトを使用して、Express Webサーバーを使用します。詳細については、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ビルドで)。この例では、再構築が発生したときに関数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 Flowを管理するためにPromesaライブラリをお勧めします。この例は[promesa.core :as p]を要求すると仮定しています。
( p/let [[app host port] ( web/start )]
; now use express `app` to set up routes and middleware
)これらの例も参照してください。
Templatesの代わりに、SiteFoxはサーバー側の試薬レンダリングのショートカットを提供し、WTH 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&Reagentを扱うためのショートカットを提供します。
html/parse node-html-parser/parseの速記です。html/render試薬のrender-to-static-markup速記です。html/$は、パーサーのquerySelectorの速記です。html/$$パーサーのquerySelectorAllの速記です。テンプレートの例プロジェクトも参照してください。
SiteFoxを使用すると、構成なしでキー価値データの保存を簡単に開始できます。必要な場合は、後でより構造化されたデータに移行できます。 KeyVをバンドルします。これは、データベースバックされたキー値ストアです。 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モジュールは、データベースエラーが発生したときに、ライン番号などを備えたフルスタックトレースを提供しません。次のように、小さなパフォーマンスペナルティで冗長スタックトレースをオンにすることができます。
( 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は、パスポートライブラリをラップして認証を実装します。 3つの関数呼び出しを使用して、アプリに簡単な電子メールとパスワードベースの認証を追加できます。
( 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また、デフォルトのAUTH UI試薬フォームとリダイレクトURLをオーバーライドして、独自のバージョンでカスタマイズすることもできます。独自の試薬フォームをどのように提供するかについての詳細については、AUTHドキュメントを参照してください。また、独自に作成したい場合は、デフォルトの試薬AUTHフォームのソースコードも参照してください。
ユーザーがサインアップすると、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))新しいテーブルを作成したい場合は(aget user "id")で取得できるユーザーのuuidでキーをキーすると便利です。
詳細については、認証の例を参照してください。
ユーザー名ベースやサードパーティの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エンドポイント/_csrf-tokenで文字列として入手でき、 fetch-csrf-tokenを使用してフェッチし、次のようにフェッチリクエストのヘッダーに追加できます。
( 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はクライアントサイドCookie 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))デフォルトでは、Webサーバーは./logsフォルダーのログファイルに書き込みます。これらのファイルは、サーバーによって自動的に回転されます。ログには2つのタイプがあります。
logs/access.log 「combined」形式の標準のWebアクセスログ。logs/error.log tracebacks/install-traceback-handlerを使用してtracebacksが書かれている場所。エラーログに猛攻撃の例外を送信するには:
(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])によって作成されました。私は自分自身とクライアントのためにサイトを構築しながらそれを繰り返しました。