ExpressJS アプリケーションを構築するには? [closed] 質問する

ExpressJS アプリケーションを構築するには? [closed] 質問する

私は NodeJS 用の ExpressJS Web フレームワークを使用しています。

ExpressJS を使用する人は、環境 (開発、本番、テストなど)、ルートなどを に配置しますapp.js。これは、大規模なアプリケーションの場合、app.js が大きすぎるため、あまり良い方法ではないと思います。

次のようなディレクトリ構造にしたいと思います:

| my-application
| -- app.js
| -- config/
     | -- environment.js
     | -- routes.js

これが私のコードです:

アプリ

var express = require('express');
var app = module.exports = express.createServer();

require('./config/environment.js')(app, express);
require('./config/routes.js')(app);

app.listen(3000);

config/environment.js

module.exports = function(app, express){
    app.configure(function() {
    app.use(express.logger());
    });

    app.configure('development', function() {
    app.use(express.errorHandler({
        dumpExceptions: true,
        showStack: true
    }));
    });

    app.configure('production', function() {
    app.use(express.errorHandler());
    });
};

config/routes.js

module.exports = function(app) {
    app.get('/', function(req, res) {
    res.send('Hello world !');
    });
};

私のコードはうまく動作し、ディレクトリの構造も美しいと思います。ただし、コードを調整する必要があり、それが良い/美しいかどうかはわかりません。

ディレクトリ構造を使用してコードを適応させる方がよいのでしょうか、それとも 1 つのファイル (app.js) だけを使用する方がよいのでしょうか。

ベストアンサー1

さて、しばらく経ちましたし、これはよくある質問なので、JavaScript コードと、中規模の express.js アプリケーションをどのように構築したいかについての長い README を含むスキャフォールディング github リポジトリを作成しました。

focusaurus/エクスプレスコード構造は、この最新のコードを含むリポジトリです。プル リクエストを歓迎します。

StackOverflow はリンクだけの回答を好まないので、README のスナップショットを以下に示します。これは新しいプロジェクトであり、今後も更新を続けていく予定なので、いくつか更新を行いますが、最終的には github リポジトリがこの情報の最新の場所になります。


#Express コード構造

このプロジェクトは、中規模の express.js Web アプリケーションを編成する方法の例です。

少なくとも2016年12月のExpress v4.14まで

ビルドステータス

js 標準スタイル

アプリケーションの大きさはどれくらいですか?

Web アプリケーションはすべて同じというわけではなく、私の意見では、すべての express.js アプリケーションに適用すべき単一のコード構造は存在しません。

アプリケーションが小さい場合は、ここで例示したような深いディレクトリ構造は必要ありません。単純に、.jsリポジトリのルートにいくつかのファイルを配置するだけで完了です。

アプリケーションが巨大な場合は、ある時点でそれを個別の npm パッケージに分割する必要があります。一般的に、node.js のアプローチでは、少なくともライブラリについては、多数の小さなパッケージが好まれるようです。そのため、複数の npm パッケージを使用してアプリケーションを構築する必要があります。そうすれば、それが理にかなってオーバーヘッドを正当化できるようになります。したがって、アプリケーションが大きくなり、コードの一部がアプリケーション外で明らかに再利用可能になったり、サブシステムが明確になったりしたら、それを独自の git リポジトリに移動して、スタンドアロンの npm パッケージにします。

したがって、このプロジェクトの焦点は、中規模のアプリケーションに適した構造を示すことです。

全体的なアーキテクチャは何ですか

ウェブアプリケーションを構築するには、次のような多くのアプローチがあります。

  • Ruby on Rails 風のサーバーサイド MVC
  • MongoDB/Express/Angular/Node (MEAN) のようなシングル ページ アプリケーション スタイル
  • いくつかのフォームを備えた基本的な Web サイト
  • モデル/操作/ビュー/イベントスタイルMVCは死んだ。今こそ前進する時だ
  • その他、現在および過去の多くの

これらはそれぞれ、異なるディレクトリ構造にうまく適合します。この例では、これは単なるスキャフォールディングであり、完全に機能するアプリではありませんが、次の主要なアーキテクチャ ポイントを想定しています。

  • このサイトには従来の静的ページ/テンプレートがいくつかある
  • サイトの「アプリケーション」部分はシングルページアプリケーションスタイルで開発されています。
  • アプリケーションはブラウザにREST/JSONスタイルのAPIを公開します
  • このアプリはシンプルなビジネスドメインをモデル化しており、この場合は自動車販売店のアプリケーションです。

Ruby on Rails についてはどうでしょうか?

このプロジェクト全体のテーマは、Ruby on Rails に具体化されたアイデアや、そこで採用された「設定より規約」の決定の多くは、広く受け入れられ、使用されているものの、実際にはあまり役に立たず、このリポジトリが推奨するものとは逆の場合もあるということです。

ここで私が言いたいのは、コードを整理するための基本原則があり、その原則に基づいて、Ruby on Rails の規則は Ruby on Rails コミュニティにとって (ほぼ) 理にかなっているということです。ただし、その規則を無思慮に真似するだけでは、要点を見逃してしまいます。基本原則を理解すれば、シェル スクリプト、ゲーム、モバイル アプリ、エンタープライズ プロジェクト、さらにはホーム ディレクトリなど、すべてのプロジェクトが整理され、わかりやすくなります。

Rails コミュニティとしては、1 人の Rails 開発者がアプリからアプリへと切り替えても、毎回慣れ親しんで快適に使用できることを望んでいます。これは、37 Signals や Pivotal Labs にとっては非常に理にかなっており、メリットもあります。サーバーサイド JavaScript の世界では、全体的な精神は、何でもありのワイルド ウェストであり、私たちは特にそれについて問題視していません。それが私たちのやり方です。私たちはそれに慣れています。express.js 内でも、これは Rails ではなく Sinatra と近い関係にあり、Rails の規約を採用しても通常は何の役にも立ちません。私は、規約よりも原則、設定よりも原則のほうが重要だとさえ言っています。

根底にある原則と動機

  • 精神的に管理しやすい
    • 脳は、一度に少数の関連した事柄しか処理したり考えたりできません。そのため、ディレクトリを使用します。ディレクトリは、小さな部分に焦点を当てることで、複雑な事柄を処理するのに役立ちます。
  • サイズが適切であること
    • 3つのディレクトリの下に1つのファイルだけがある「マンションディレクトリ」を作成しないでください。これは、Ansible のベストプラクティス小さなプロジェクトでは、1 つのディレクトリに 3 つのファイルを格納する方がはるかに適切なのに、10 個以上のファイルを格納するために 10 個以上のディレクトリを作成するという恥ずかしい状況になります。バスを運転して仕事に行くことはありません (バスの運転手でない限り、しかしその場合でも、仕事に行くためにバスを運転するのではなく、仕事でバスを運転します)。したがって、実際のファイルによって正当化されないファイルシステム構造を作成しないでください。
  • モジュール式でありながら実用的であること
    • Node コミュニティは全体的に、小さなモジュールを好みます。アプリから完全にきれいに分離できるものは、内部使用または npm で公開するためにモジュールに抽出する必要があります。ただし、ここで対象とする中規模のアプリケーションの場合、このオーバーヘッドによってワークフローに手間がかかるだけで、それに見合った価値はありません。そのため、分離されているコードがあるものの、完全に独立した npm モジュールを正当化するほどではない場合、そのコードを「プロトモジュール」と見なし、サイズのしきい値を超えたら抽出されるものと見なしてください。
    • 次のような人たち翻訳者移行を容易にし、リマインダーとして機能するように、app/node_modulesディレクトリを含め、プロトモジュールpackage.jsonディレクトリにファイルを配置することもできます。
  • コードを簡単に見つけられるようにする
    • 構築する機能や修正するバグがある場合、開発者が関連するソース ファイルを簡単に見つけられるようにすることが私たちの目標です。
      • 名前は意味があり正確である
      • 不要なコードは完全に削除され、孤立したファイルに残されたり、単にコメントアウトされたりすることはありません。
  • 検索しやすい
    • すべてのファーストパーティのソースコードはappディレクトリ内にあるため、cdfind/grep/xargs/ag/ackなどを実行しても、サードパーティの一致に惑わされることはありません。
  • シンプルでわかりやすい名前を使用する
    • npm では、パッケージ名はすべて小文字にする必要があるようです。これはひどいことだと思いますが、大勢の意見に従わざるを得ません。したがって、JavaScript では はマイナス記号であるため、JavaScript の変数名が であるにもかかわらず、ファイル名には を使用する必要がありkebab-caseます。camelCase-
    • 変数名はモジュールパスのベース名と一致しますがkebab-casecamelCase
  • 機能ではなく結合度でグループ化する
    • app/viewsこれは、、、app/controllersなどapp/modelsのRuby on Railsの慣例からの大きな逸脱です。
    • 機能はフルスタックに追加されるので、機能に関連するファイルのフルスタックに焦点を当てたいと思います。ユーザーモデルに電話番号フィールドを追加する場合、ユーザーコントローラー以外のコントローラーは気にしませんし、ユーザーモデル以外のモデルも気にしません。
    • そのため、それぞれ独自のディレクトリにある6つのファイルを編集し、それらのディレクトリ内の他の大量のファイルを無視する代わりに、このリポジトリは、機能を構築するために必要なすべてのファイルが共存するように構成されています。
    • MVC の性質上、ユーザー ビューはユーザー コントローラーに結合され、ユーザー コントローラーはユーザー モデルに結合されます。そのため、ユーザー モデルを変更すると、これらの 3 つのファイルは一緒に変更されることがよくありますが、取引コントローラーまたは顧客コントローラーは分離されているため、関係しません。通常、非 MVC 設計にも同じことが当てはまります。
    • どのコードをどのモジュールに配置するかという点での MVC または MOVE スタイルの分離は依然として推奨されますが、MVC ファイルを兄弟ディレクトリに分散させるのは面倒です。
    • したがって、各ルート ファイルには、そのルートが所有するルートの部分があります。routes.rbアプリ内のすべてのルートの概要が必要な場合は Rails スタイルのファイルが便利ですが、実際に機能を構築してバグを修正する場合は、変更する部分に関連するルートのみを気にします。
  • テストをコードの隣に保存する
    • これは「結合によるグループ化」の一例にすぎませんが、特に言及したいと思いました。私はこれまで、テストが「tests」と呼ばれる並列ファイルシステムの下に置かれるプロジェクトを数多く書いてきましたが、テストを対応するコードと同じディレクトリに置くようになってからは、もう元には戻りません。この方法はモジュール化が進み、テキストエディタで作業するのがはるかに簡単になり、「../../..」パスのナンセンスが大幅に軽減されます。疑問がある場合は、いくつかのプロジェクトで試してみて、自分で判断してください。これが優れていることを納得させるためにこれ以上のことはしません。
  • イベントとの横断的結合を減らす
    • 「OK、新しい取引が作成されるたびに、すべての営業担当者にメールを送信したい」と考えるのは簡単です。その後、取引を作成するルートにそれらのメールを送信するためのコードを配置するだけです。
    • ただし、この結合により、最終的にアプリは巨大な泥の塊になってしまいます。
    • 代わりに、DealModel は単に「作成」イベントを発生させ、システムがそれに応じて他に何を行うかについてはまったく認識しないようにする必要があります。
    • このようにコーディングすると、ユーザー コード ベースの純粋さを汚すような、結合されたビジネス ロジックの巣窟があちこちに存在しなくなるため、ユーザーに関連するすべてのコードを配置することがはるかに可能app/usersになります。
  • コードフローが追跡可能
    • 魔法のようなことはしないでください。ファイルシステム内の魔法のディレクトリからファイルを自動ロードしないでください。Rails にならないでください。アプリは から始まりapp/server.js:1、コードをたどることで、アプリがロードして実行するすべての内容を確認できます。
    • ルートに DSL を作成しないでください。必要のないときに、愚かなメタプログラミングを行わないでください。
    • アプリが非常に大きく、3 つの基本的な、、の呼び出しmagicRESTRouter.route(somecontroller, {except: 'POST'})よりも を実行する方が大きなメリットになる場合は、効果的に作業するには大きすぎるモノリシック アプリを構築している可能性があります。3 つの単純な行を 1 つの複雑な行に変換するためではなく、大きなメリットを得るために工夫してください。app.getapp.putapp.del
  • 小文字ケバブ文字のファイル名を使用する
    • このフォーマットは、プラットフォーム間でのファイルシステムの大文字と小文字の区別の問題を回避します。
    • npmは新しいパッケージ名に大文字の使用を禁止しており、これはそれとうまく機能します。

express.js の詳細

  • は使用しないでくださいapp.configure。ほとんど役に立たず、必要ありません。無分別なコピーペーストにより、多くの定型文に含まれています。
  • Express におけるミドルウェアとルートの順序は重要です!!!
    • 私がstackoverflowで目にするルーティングの問題のほとんどすべては、順序がずれたExpressミドルウェアによるものです。
    • 一般的に、ルートは分離し、順序にあまり依存しないようにしたい。
    • app.use本当に 2 つのルートにのみミドルウェアが必要な場合は、アプリケーション全体に使用しないでください(私はあなたを見ていますbody-parser)
    • すべてが終わったら、次の順序が正確であることを確認してください。
      1. アプリケーション全体にわたる極めて重要なミドルウェア
      2. すべてのルートと各種ルートミドルウェア
      3. THENエラーハンドラ
  • 残念なことに、Sinatraにインスパイアされたexpress.jsは、すべてのルートが含まれserver.js、それらの順序が明確であると想定しています。中規模のアプリケーションの場合、ルートを個別のモジュールに分割するのは良いことですが、順序が乱れるミドルウェアの危険性が生じます。

アプリのシンボリックリンクトリック

コミュニティによって概要が示され、長々と議論されている多くのアプローチが、gistに掲載されています。Node.js のローカル require() パスの改善. 私はすぐに「たくさんの../../../..」を処理するか、要求元モジュール。ただし、現時点では、以下に詳述するシンボリックリンク トリックを使用しています。

したがって、次のような煩わしい相対パスを含むプロジェクト内要求を回避する 1 つの方法は、require("../../../config")次のトリックを使用することです。

  • アプリのnode_modulesの下にシンボリックリンクを作成します
    • cd node_modules && ln -nsf ../app
  • node_modulesフォルダ全体ではなく、 node_modules/appシンボリックリンク自体のみをgitに追加します。
    • git add -f node_modules/app
    • .gitignoreはい、ファイルにはまだ「node_modules」が残っているはずです
    • いいえ、「node_modules」を Git リポジトリに配置しないでください。これを推奨する人もいますが、それは間違いです。
  • このプレフィックスを使用してプロジェクト内モジュールを要求できるようになりました
    • var config = require("app/config");
    • var DealModel = require("app/deals/deal-model");
  • 基本的に、これにより、プロジェクト内の requires は外部 npm モジュールの requires と非常によく似た動作をするようになります。
  • 申し訳ありませんが、Windows ユーザーの場合は、親ディレクトリの相対パスを使用する必要があります。

構成

一般的に、モジュールとクラスは、options渡される基本的な JavaScript オブジェクトのみを想定してコーディングします。モジュールのみapp/server.jsをロードする必要がありますapp/config.js。そこから、options必要に応じてサブシステムを構成するための小さなオブジェクトを合成できますが、すべてのサブシステムを、追加情報が満載の大きなグローバル構成モジュールに結合するのは不適切な結合です。

接続パラメータを渡してサブシステム自体に送信接続を行わせるのではなく、DB 接続の作成を集中化し、それらをサブシステムに渡すようにしてください。

ノードENV

app/config.jsこれは、Rails から引き継がれた、魅力的だがひどいアイデアです。アプリには、環境変数を確認する場所が 1 か所だけある必要がありますNODE_ENV。他のすべては、クラス コンストラクター引数またはモジュール構成パラメーターとして明示的なオプションを取る必要があります。

電子メール モジュールに電子メールの配信方法 (SMTP、標準出力へのログ、キューへの配置など) に関するオプションがある場合は、 のようなオプションを取る必要があります{deliver: 'stdout'}が、絶対に をチェックしないでくださいNODE_ENV

テスト

現在、テスト ファイルを対応するコードと同じディレクトリに保存し、ファイル名拡張子の命名規則を使用してテストと本番コードを区別しています。

  • foo.jsモジュール「foo」のコードを持つ
  • foo.tape.jsfooのノードベースのテストがあり、同じディレクトリにあります
  • foo.btape.jsブラウザ環境で実行する必要があるテストに使用できます

必要に応じて、ファイルシステム glob とfind . -name '*.tape.js'コマンドを使用してすべてのテストにアクセスします。

.js各モジュールファイル内でコードを整理する方法

このプロジェクトの範囲は主にファイルとディレクトリの配置場所に関するものであり、他の範囲をあまり追加したくありませんが、コードを 3 つの異なるセクションに整理していることだけ述べておきます。

  1. CommonJS の開始ブロックは状態依存関係の呼び出しを必要とします
  2. 純粋な JavaScript のメイン コード ブロック。ここには CommonJS の汚染はありません。エクスポート、モジュール、または require を参照しないでください。
  3. エクスポートを設定するためのCommonJSの終了ブロック

おすすめ記事