Nodejs MVCフレームワークまたは別の自転車

こんにちは、Habrahabr! なんらかの理由で、expressjsはnode.jsの2番目のフレームワークに隠れている人を最近驚かせていませんが、本当に必要なのでしょうか? expressjsが悪いという事実については言っていません、いいえ、それは仕事をしますが、このフレームワークが与えることができるより困難なルーティングが必要なとき、私はexpressjsにそれをプロジェクトに残すために他に何があると思いましたか? 残念ながら、ウェブサーバー以外には何もありません。テンプレートテンプレートとの統合はささいなことであり、ミドルウェアは単純な一連の関数、コールバック地獄ヒープに帰着します。



node.jsでドックを開いて、カーネル内にあるモジュールの数を簡単に見ると、多くの新しいものを自分で発見できます。 ご想像のとおり、別の自転車についてお話しします。



私は、多くのフェイントがphpフレームワークから借用されたことをすぐに言わなければなりません。



私がプロジェクトに残した依存関係:



async、hashids、mime-types、sequelize、validator、pug



1)プロジェクトの構造を決定しましょう:



フレームワーク構造
-ダッシュボード-プロジェクトのメインモジュール

-アプリケーションを開始するためのbinファイル

-アプリケーションの構成

-移行移行

-モジュールモジュール

-ビューのメインビュー



プロジェクト構造
-ベースベースクラス

-プロジェクトの90%で必要になる可能性のある主要な行動

-コンソールモードでアプリケーションを起動するために必要なコンソールクラス

-さまざまなヘルパーを含むhelpersフォルダー

-プロジェクトの90%で必要なモジュールモジュール(移行、静的レンダリング)

-Webアプリケーションモードで動作するために必要なWebクラス



2)Webアプリケーションの起動方法:



bin / server.jsファイルを作成します



Bin / server.jsファイル
import Application from "dok-js/dist/web/Application"; import path from "path"; const app = new Application({ basePath: path.join(__dirname, ".."), id: "server" }); app.run(); export default app;
      
      







その後、アプリケーションは./config/server.jsから設定をダウンロードしようとします



./config/server.js
 import path from "path"; export default function () { return { default: { basePath: path.join(__dirname, ".."), services: { Database: { options: { instances: { db: { database: "example", username: "example", password: "example", params: { host: "localhost", dialect: "postgres" } } } } }, Server: { options: { port: 1987 } }, Router: { options: { routes: { "/": { module: "dashboard", controller: "index", action: "index" }, "/login": { module: "identity", controller: "identity", action: "index" }, "/logout": { module: "identity", controller: "identity", action: "logout" }, "GET /assets/<filePath:.*>": { module: "static", controller: "static", action: "index", params: { viewPath: path.join(__dirname, "..", "views", "assets") } }, "/<module:\w+>/<controller:\w+>/<action:\w+>": {} } } } }, modules: { identity: { path: path.join(__dirname, "..", "modules", "identity", "IdentityModule") }, dashboard: { path: path.join(__dirname, "..", "modules", "dashboard", "DashboardModule") } } } }; }
      
      







そのため、私はexpressjsルートを使用できなかった瞬間に来ました。 ご覧のとおり、現在のバージョンのルートは非常に柔軟であり、アプリケーションを微調整することができます。ここではyii2からアイデアを取りました。



痛みは2番目です:expressjsとほとんどのnodejsフレームワークが私たちに課しているコントローラーとアクション。 これは通常、匿名関数であり(これはパフォーマンスに必要であると理解しています)、入力として要求と応答を受け取り、それらで何かを行います。 たとえば、すべての応答を記録するためにロガーをプロジェクトの途中に置く必要があり、アプリケーション全体をほぼリファクタリングするように親切にし、次の(要求、応答)が行う呼び出しの呼び出しを見逃すことを神が禁じている場合、これは私が決して知らないことですアクションが実行を完了した時点。



私が提案する解決策は次のとおりです。



ベース/ Request.js
 async run(ctx) { this.constructor.parse(ctx); try { ctx.route = App().getService("Router").getRoute(ctx.method, ctx.url); } catch (e) { return App().getService("ErrorHandler").handle(404, e.message); } try { return App().getModule(ctx.route.moduleName).runAction(ctx); } catch (e) { return App().getService("ErrorHandler").handle(500, e.message); } }
      
      







ベース/ Module.js
 async runAction(ctx) { const {controllerName, actionName} = ctx.route; const controller = this.createController(controllerName); if (!controller[actionName]) { throw new Error(`Action "${actionName}" in controller "${controllerName}" not found`); } const result = await this.runBehaviors(ctx, controller); if (result) { return result; } return controller[actionName](ctx); }
      
      







つまり すべてのコントローラーに単一の起動ポイントがあります。



さて、コントローラー自体:



モジュール/ダッシュボード/コントローラー/ IndexController.js
 import Controller from "dok-js/dist/web/Controller"; import AccessControl from "dok-js/dist/behaviors/AccessControl"; export default class IndexController extends Controller { getBehaviors() { return [{ behavior: AccessControl, options: [{ actions: ["index"], roles: ["user"] }] }]; } indexAction() { return this.render("index"); } }
      
      







モジュール/アイデンティティ/コントローラー/ IdentityController.js
 import Controller from "dok-js/dist/web/Controller"; import SignInForm from "../data-models/SignInForm"; export default class IdentityController extends Controller { async indexAction(ctx) { const data = {}; data.meta = { title: "" }; if (ctx.method === "POST") { const signInForm = new SignInForm(); signInForm.load(ctx.body); const $user = await signInForm.login(ctx); if ($user) { return this.redirectTo("/", 301); } data.signInForm = signInForm; } return this.render("sign-in", data); } logoutAction(ctx) { ctx.session.clearSession(); return this.redirectTo("/", 302); } }
      
      







また、コントローラーのコンストラクターが一度呼び出されてからキャッシュに追加されることもすぐに言います。



フレームワーク自体はまだ湿っていますが、githubで確認できます。



github.com/kalyuk/dok-js



また、小さな例をスケッチしました。移行を開始するコンソールアプリケーションもあります。



github.com/kalyuk/dok-js-example



All Articles