web-dev-qa-db-ja.com

node.jsで必要となるライブラリを構造化するためのベストプラクティス

ヘルパー関数を含むユーティリティライブラリがいくつかあり、コントローラーから使用できるようにそれらをロードしたいのですが、ノードでユーティリティライブラリをコーディングするためのベストプラクティスは何でしょうか。

それを行うにはいくつかの方法があり、何が最良/より適切/より信頼できるのかわからないため、私は少し混乱しています。ここに2つのオプションがありますが、それらが最適かどうか疑問に思っています(たとえば、module.exports = exports = function(){}を使用するスニペットを見たことがあります)

//option1.js


"use strict";

module.exports =  function(){

     exports.test1 =  function(){ console.log('hi I'm test1')};
     exports.test2 =  function(){ console.log('hi I'm test2')};
     return exports;
};

//option2.js

"use strict";

module.exports =  {

     test1 : function(){ console.log('soy test1')},
     test2 :  function(){ console.log('soy test2')}

};

//test_controller.js

/* Requiring helpers in different ways */
var option1 = require('./option1.js')();
var option2 = require('./option2.js');
22
Endymion

私は自分のファイルを3つのセクションに分けて考えています。

セクション1:CommonJSの依存関係

var lib1 = require("lib1");
var lib2 = require("lib2");

追加のラッパー関数は必要ありません。すべてのノードモジュールは、関数内のnode.jsによって 自動的にラップされます これを行うことには利点がなく、混乱が生じるだけです。

セクション2:プレーンJavaScriptコード

これは、必要に応じて、サポート変数またはトップレベルのモジュールコードを散りばめた関数である必要があります。

var MY_CONST = 42;

function helper1() {
    //excellent code here
}

function helper2() {
    //excellent code here
}

セクション2を純粋なJSのままにします。この真ん中の「純粋な」セクションでは、commonJSイディオムを使用しないでください。 moduleexportsrequireなどは使用しないでください。JS自体は安定していますが、モジュールへのパッケージ化はまだ多くの変更が加えられているため、これは私の個人的なガイドラインです。また、無関係で変更される可能性のあるCommonJSビットは、コードの興味深いビットとは別にしておくことをお勧めします。 ECMAScript 6モジュールは数年以内にCommonJSに置き換わる可能性が高いため、セクション2の純粋なECMAScript 5を維持し、私が好きなように「CommonJSSandwich™」を作成することで、これを簡単に行えるようにします。

セクション3:CommonJSエクスポート

exports.helper1 = helper1;
exports.helper2 = helper2;
  • すべてのエクスポートを最後に配置すると、パブリックAPIが何であるかをすばやく理解し、不注意なコピー/貼り付けによるプロパティの誤ったエクスポートを防ぐことができます。
  • 新しいオブジェクトリテラルにexports.foo = foo;を割り当てるのではなく、上記のmodule.exports構文の方が好きです。これにより、オブジェクトリテラルの最後のプロパティでの末尾のコンマの問題が回避されることがわかりました。
  • requireまたはexportsステートメントで他のことを行うことは、ほぼ確実に不要であり、不必要に巧妙または魔法です。上級者になるまで、ここでは特別なことは何もしないでください。 (それでも、TJ Holowaychukでない場合は、おそらくばかげているだけです)

何をエクスポートすればよいですか

単一の関数(@substackスタイル)

function degreesToRadians(degrees) {}

module.exports = degreesToRadians;

小さくシンプルにしましょう。

関数のオブジェクト

モジュールがヘルパー関数のセットである場合、それらの関数をプロパティとして含むオブジェクトをエクスポートする必要があります

var foo = require("foo");

function doubleFoo(value) {
  return foo(value) * 2;
}

function tripleFoo(value) {
  return foo(value) * 3;
}

exports.doubleFoo = doubleFoo;
exports.tripleFoo = tripleFoo;

コンストラクター関数

モジュールがオブジェクト指向で使用するためのクラス設計である場合は、コンストラクター関数をエクスポートします

function GoCart() {
  this.wheels = 4;
}

GoCart.prototype.drive = function drive() {
  //vroom vroom
}

module.exports = GoCart;

工場/構成閉鎖機能

上記の2つのパターンをマスターし(本当に!)、オプションを取り、おそらく他の動的なことを行うファクトリ関数をエクスポートすることに自信を持ったら、それを選択してください。ただし、疑わしい場合は、最初の2つの単純な選択肢を使用してください。

//do-stuff.js
function doStuff(howFast, what) {
   return "I am doing " + what + " at speed " + howFast;
}

function setup(options) {
  //The object returned by this will have closure access to options
  //for its entire lifetime
  return {doStuff: doStuff.bind(null, options.howFast)};
}

module.exports = setup;

だからあなたはそれを次のように使うことができます

var doStuff = require("./do-stuff")({howFast: "blazing speed"});
console.log(doStuff.doStuff("jogging"));
//"I am doing jogging at speed blazing speed"
40
Peter Lyons

ステートレスユーティリティライブラリの場合、requireのたびに_module.exports_のコードを実行する必要がないため、option2.jsが最適です。 require('./option1.js')()を呼び出してoption1.jsを使用すると発生します。

一方、モジュールが状態を保持するオブジェクトを作成するコンストラクターを公開している場合は、option1.jsが必要になります。例えば、

person.js:

_module.exports = function(firstName,lastName){
    this.firstName = firstName;
    this.lastName = lastName;
};
_

そしてそれを使用するには:

_var Person = require("./person");

var person1 = new Person("Foo","Bar");
var person2 = new Person("Joe","Shmoe");
_

option1.js(上記で示したように)の他の利点は、パラメーターをモジュールに渡すことができることです。

2
go-oleg