web-dev-qa-db-ja.com

Express / Node.JSを使用してすべてのビューでアクセス可能なグローバル変数を作成するにはどうすればよいですか?

それでは、 Jekyll を使用してブログを作成しました。すべてのテンプレート/レイアウトでアクセス可能なファイル_config.ymlで変数を定義できます。現在、 Node.JS / ExpressEJS テンプレートと ejs-locals (パーシャル/レイアウト。Jekyllに慣れている人なら、site.titleにある_config.ymlのようなグローバル変数に似たものを探しています。サイトタイトル(ページタイトルではなく)などの変数があります。著者/会社名。すべてのページで同じです。

以下は、私が現在行っていることの例です。

exports.index = function(req, res){
    res.render('index', { 
        siteTitle: 'My Website Title',
        pageTitle: 'The Root Splash Page',
        author: 'Cory Gross',
        description: 'My app description',
        indexSpecificData: someData
    });
};

exports.home = function (req, res) {
    res.render('home', {
        siteTitle: 'My Website Title',
        pageTitle: 'The Home Page',
        author: 'Cory Gross',
        description: 'My app description',
        homeSpecificData: someOtherData
    });
};

サイトのタイトル、説明、著者などの変数を1か所で定義し、res.renderへの各呼び出しのオプションとして渡すことなく、レイアウト/テンプレートでEJSを介してアクセスできるようにしたいと思います。これを行う方法はありますが、それでも各ページに固有の他の変数を渡すことができますか?

73
Cory Gross

Express 3 APIリファレンス を勉強する機会を得た後、私は探しているものを発見しました。具体的には、 app.locals のエントリと、さらに少し下の res.locals 必要な答えを保持しました。

関数app.localsがオブジェクトを受け取り、そのすべてのプロパティをアプリケーションにスコープされたグローバル変数として保存することを自分で発見しました。これらのグローバルは、ローカル変数として各ビューに渡されます。ただし、関数res.localsはスコープが要求に限定されているため、応答ローカル変数は、その特定の要求/応答中にレンダリングされたビューにのみアクセスできます。

したがって、私の場合はapp.jsで追加したことは次のとおりです。

app.locals({
    site: {
        title: 'ExpressBootstrapEJS',
        description: 'A boilerplate for a simple web application with a Node.JS and Express backend, with an EJS template with using Twitter Bootstrap.'
    },
    author: {
        name: 'Cory Gross',
        contact: '[email protected]'
    }
});

その後、これらの変数はすべて、site.titlesite.descriptionauthor.nameauthor.contactとしてビューでアクセスできます。

また、res.localsを使用してリクエストへの応答ごとにローカル変数を定義することも、ページのタイトルなどの変数をoptions呼び出しのrenderparameterとして渡すこともできます。

EDIT:このメソッドは、notこれらのローカルをミドルウェアで使用できるようにします。 Pickelsが以下のコメントで示唆しているように、実際にこれに遭遇しました。この場合、あなたは彼の代わりの(そして高く評価された)回答でミドルウェア関数を作成する必要があります。ミドルウェア関数は、応答ごとにそれらをres.localsに追加し、nextを呼び出す必要があります。このミドルウェア機能は、これらのローカルを使用する必要がある他のミドルウェアの上に配置する必要があります。

EDIT:app.localsres.localsを介してローカルを宣言することのもう1つの違いは、app.localsを使用すると、変数が1回設定され、アプリケーションの存続期間中持続することです。ミドルウェアでres.localsを使用してローカルを設定すると、これらはリクエストを取得するたびに設定されます。値がミドルウェアに渡されるリクエストreq変数に依存しない限り、基本的にapp.localsを介してグローバルを設定することを好むはずです。値が変わらない場合は、app.localsで一度だけ設定する方が効率的です。

100
Cory Gross

これを行うには、一般的なミドルウェアのローカルオブジェクトにそれらを追加します。

app.use(function (req, res, next) {
   res.locals = {
     siteTitle: "My Website's Title",
     pageTitle: "The Home Page",
     author: "Cory Gross",
     description: "My app's description",
   };
   next();
});

Localsは、localsオブジェクトを上書きするのではなく拡張する関数でもあります。したがって、次のようにも動作します

res.locals({
  siteTitle: "My Website's Title",
  pageTitle: "The Home Page",
  author: "Cory Gross",
  description: "My app's description",
});

完全な例

var app = express();

var middleware = {

    render: function (view) {
        return function (req, res, next) {
            res.render(view);
        }
    },

    globalLocals: function (req, res, next) {
        res.locals({ 
            siteTitle: "My Website's Title",
            pageTitle: "The Root Splash Page",
            author: "Cory Gross",
            description: "My app's description",
        });
        next();
    },

    index: function (req, res, next) {
        res.locals({
            indexSpecificData: someData
        });
        next();
    }

};


app.use(middleware.globalLocals);
app.get('/', middleware.index, middleware.render('home'));
app.get('/products', middleware.products, middleware.render('products'));

また、汎用レンダーミドルウェアも追加しました。この方法では、res.renderを各ルートに追加する必要がないため、コードの再利用が向上します。再利用可能なミドルウェアのルートをたどると、開発を大幅にスピードアップする多くのビルディングブロックがあることに気付くでしょう。

49
Pickels

Express 4.0の場合、アプリケーションレベルの変数を使用すると動作が少し異なり、Coryの答えは機能しませんでした。

ドキュメントから: http://expressjs.com/en/api.html#app.locals

アプリのグローバル変数を宣言できることがわかりました

app.locals

例えば

app.locals.baseUrl = "http://www.google.com"

そして、アプリケーションでこれらの変数にアクセスできます。エクスプレスミドルウェアでは、reqオブジェクトで次のようにアクセスできます。

req.app.locals.baseUrl

例えば.

console.log(req.app.locals.baseUrl)
//prints out http://www.google.com
16
RamRovi

App.jsに次のようなものを追加する必要があります

global.myvar = 100;

これで、この変数を使用するすべてのファイルで、myvarとしてアクセスできます。

11
Fernando Bustos

「グローバル」を使用することもできます

例:

このように宣言します:

  app.use(function(req,res,next){
      global.site_url = req.headers.Host;   // hostname = 'localhost:8080'
      next();
   });

次のように使用します。任意のビューまたはejsファイルで<%console.log(site_url); %>

jsファイルにconsole.log(site_url);

1
Shaik Matheen

これを行う1つの方法は、app.localsでそのアプリのapp.js変数を更新することです

以下で設定

var app = express();
app.locals.appName = "DRC on FHIR";

アクセスを取得

app.listen(3000, function () {
    console.log('[' + app.locals.appName + '] => app listening on port 3001!');
});

@RamRoviの例のスクリーンショットを少し改良して詳しく説明します。

enter image description here

1
Gajen Sunthara

汚染されたグローバルスコープを持たないようにするために、どこにでも含めることができるスクリプトを作成します。

// my-script.js
const ActionsOverTime = require('@bigteam/node-aot').ActionsOverTime;
const config = require('../../config/config').actionsOverTime;
let aotInstance;

(function () {
  if (!aotInstance) {
    console.log('Create new aot instance');
    aotInstance = ActionsOverTime.createActionOverTimeEmitter(config);
  }
})();

exports = aotInstance;

これを行うと、新しいインスタンスが一度だけ作成され、ファイルが含まれるすべての場所で共有されます。変数がキャッシュされているのか、アプリケーションの内部参照メカニズム(キャッシュを含む可能性がある)が原因であるのかはわかりません。ノードがこれを解決する方法に関するコメントは素晴らしいでしょう。

たぶん、これを読んでrequireがどのように機能するかについての要点を入手してください: http://fredkschott.com/post/2014/06/require-and-the-module-system/

0
dewwwald