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


81

さて、私はJekyllを使用してブログを_config.yml作成しました。すべてのテンプレート/レイアウトでアクセスできる、ファイル内の変数を定義できます。私は現在、EJSテンプレートとejs-localsでNode.JS / Expressを使用しています(パーシャル/レイアウト用。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か所で定義し、への各呼び出しのオプションとして渡すことなく、EJSを介してレイアウト/テンプレートでアクセスできるようにしたいと思いますres.render。これを実行しても、各ページに固有の他の変数を渡すことができる方法はありますか?

回答:


109

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: 'CoryG89@gmail.com'
    }
});

そして、これらの変数のすべてがとしての私の見解でアクセス可能なsite.titlesite.descriptionauthor.nameauthor.contact

また、リクエストへの各応答のローカル変数を、で定義しres.localsたり、ページのタイトルなどの変数を呼び出しのoptionsパラメーターとして渡すこともできrenderます。

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

編集:地元の人々を宣言経由してのもう一つの違いapp.localsres.localsしていることであるapp.locals変数単一の時間に設定され、アプリケーションの生涯にわたって持続します。res.localsミドルウェアでローカルを設定すると、リクエストを受け取るたびに設定されます。app.localsreqがミドルウェアに渡される要求変数に依存しない限り、基本的にはを介してグローバルを設定することをお勧めします。値が変わらない場合は、に1回だけ設定する方が効率的ですapp.locals


1
app.localsは、私が提案したものよりも理にかなっています。ただし、1つの問題がありますが、ミドルウェアでローカルにアクセスすることはできません。この場合、それはおそらく問題ではありませんが、それはあなたが時々遭遇するそれらの落とし穴の1つです。
Pickels 2013年

jsまたはjsonファイルで構成を定義し、必要な場所で単純にrequire()することもできます。ファイルはアプリケーション中に1回だけロードされ、ファイルを必要とするすべてのモジュールは、定義された値にアクセスできます。stackoverflow.com/questions/5869216/で
Joe Lapp 2014

51
ではエクスプレス4 localsの機能が、オブジェクトではありません。プロパティを設定するには:app.locals.site.title = 'Example';
Martti Laine

うわー!これで、アプリ全体を1つのファイルで構成できるようになりました。きれいなショット。+1
Dipak 2016年

@MarttiLaineありがとうバディ!
アリ・エムレÇakmakoğlu

55

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

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を追加する必要がないため、コードの再利用が向上します。再利用可能なミドルウェアルートをたどると、開発を大幅にスピードアップするビルディングブロックがたくさんあることに気付くでしょう。


私は、これは古い答えですけど、自分の中のparamsglobalLocalsのための機能reqとはres逆方向にあります。
brandon927 2015年

この方法で、グローバルにすることを目的としたデータをクエリできますか?たとえば、各ページリクエストのdbから直接ロードされるナビゲーションバーデータなどです。これは、マングースの鳴き声など、地元の人々の利用を超えている可能性があるという考えのようです。navbarはグローバルであるため、すべてのルートで直接ロードを探しています。後でキャッシュを調べます。あるいは、一度実行する関数が必要な場合もあります。データを収集した後、これらをローカルにロードします。
blamb 2017

1
res.localsもう関数ではないようです。
killjoy

私はあなたのアプローチを使用して、いくつかの製品をフッターに表示します。ありがとうございました!
カルナルバレンティン

18

Express 4.0の場合、アプリケーションレベルの変数の使用は少し異なって機能し、Coryの答えは私には機能しませんでした。

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

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

app.locals

例えば

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

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

req.app.locals.baseUrl

例えば

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

1
また、コードに新しいローカルが追加された場合は、エクスプレスサーバーを再起動する必要があります。
Wtower 2016

14

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

global.myvar = 100;

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


私はrequireモジュールを使用していて、global.myvarどこでもそれを参照する必要があり、それはうまくいきました。これは、他のファイルのハンドラーからメッセージを出力したいsocket.ioにとって非常に簡単なソリューションでした。「io」オブジェクトを配置しましたがglobal.myIO、すべてうまく機能しています。
トムポーター

6
これは実際には推奨されておらず、ノード開発のグッドプラクティスとは見なされていません。Node.JSには、CommonJSシステムに基づくモジュールシステムの実装が含まれており、requireメソッドを使用する代わりに、グローバルスコープを共有しないモジュールのアイデアに完全に集中しています。これはまた、質問が求めるようなExpressビュー/テンプレートのローカルではなく、ノードにグローバルjs変数を設定します。
コーリー・グロス

@CoryGrossリクエストオブジェクトをこのようなグローバル変数として設定するのは良い習慣ですか?
Ali Sherafat

これだけが機能しました。Fさん、ありがとう!@CoryGrossアプリケーション内のすべてのファイルが単一のオブジェクトにアクセスできるようにするにはどうすればよいですか?
DivijSehgal19年

これが最良の答えです。これは、グローバルオブジェクトをビューまたは任意の場所に渡すことができることを意味します。このようglobal.cdnURL = "https://cdn.domain.comに、ビューに渡して静的コンテンツをロードできます。
第1巻

1

これを行う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の例のスクリーンショットを少し強化して詳しく説明します。

ここに画像の説明を入力してください


1

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

例:

このように宣言します:

  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);


0

さまざまな答えで、「app.locals」にロードされた外部ファイルJSONを使用するようにこのコードを実装しました

パラメーター

{
    "web": {
        "title" : "Le titre de ma Page",
        "cssFile" : "20200608_1018.css"
    }
}

応用

var express     = require('express');
var appli       = express();
var serveur     = require('http').Server(appli);

var myParams    = require('./include/my_params.json');
var myFonctions = require('./include/my_fonctions.js');

appli.locals = myParams;

EJSページ

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <title><%= web.title %></title>
    <link rel="stylesheet" type="text/css" href="/css/<%= web.cssFile %>">
</head>

</body>
</html>

それが役立つことを願っています


-1

汚染されたグローバルスコープを回避するために私が行うことは、どこにでも含めることができるスクリプトを作成することです。

// 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;

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.