Wie erstelle ich globale Variablen, auf die in allen Ansichten mit Express / Node.JS zugegriffen werden kann?

80

Ok, ich habe ein Blog mit Jekyll erstellt und Sie können Variablen in einer Datei definieren, auf _config.ymldie in allen Vorlagen / Layouts zugegriffen werden kann. Ich verwende derzeit Node.JS / Express mit EJS- Vorlagen und EJS-Locals (für Partials / Layouts. Ich möchte etwas Ähnliches tun wie die globalen Variablen site.title, die in enthalten sind, _config.ymlwenn jemand mit Jekyll vertraut ist. Ich habe Variablen wie die Titel der Site (anstelle des Seitentitels), Autor / Firmenname, die auf allen meinen Seiten gleich bleiben.

Hier ist ein Beispiel dafür, was ich gerade mache:

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

Ich möchte in der Lage sein, Variablen wie Titel, Beschreibung, Autor usw. meiner Site an einem Ort zu definieren und sie über EJS in meinen Layouts / Vorlagen zugänglich zu machen, ohne sie als Optionen an jeden Aufruf von übergeben zu müssen res.render. Gibt es eine Möglichkeit, dies zu tun und mir trotzdem zu erlauben, andere für jede Seite spezifische Variablen zu übergeben?

Cory Gross
quelle

Antworten:

108

Nachdem ich die Express 3 API-Referenz etwas genauer studiert hatte, entdeckte ich, wonach ich suchte. Insbesondere die Einträge für app.localsund dann etwas weiter unten res.localsenthielten die Antworten, die ich brauchte.

Ich habe selbst festgestellt, dass die Funktion app.localsein Objekt verwendet und alle seine Eigenschaften als globale Variablen für die Anwendung speichert. Diese Globals werden als lokale Variablen an jede Ansicht übergeben. Die Funktion res.localsist jedoch auf die Anforderung beschränkt, und daher sind lokale Antwortvariablen nur für die Ansichten zugänglich, die während dieser bestimmten Anforderung / Antwort gerendert wurden.

Also für meinen Fall in meinem, app.jswas ich getan habe, war hinzuzufügen:

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]'
    }
});

Dann alle diese Variablen sind zugänglich in meinen Ansichten wie site.title, site.description, author.name, author.contact.

Ich könnte auch lokale Variablen für jede Antwort auf eine Anfrage mit definieren res.localsoder einfach Variablen wie den Seitentitel als optionsParameter im renderAufruf übergeben.

EDIT: Diese Methode wird nicht ermöglichen es Ihnen , diese Einheimischen in Ihrer Middleware zu verwenden. Ich bin tatsächlich darauf gestoßen, wie Pickels im Kommentar unten vorschlägt. In diesem Fall müssen Sie in seiner alternativen (und geschätzten) Antwort eine Middleware-Funktion als solche erstellen. Ihre Middleware-Funktion muss sie res.localsfür jede Antwort hinzufügen und dann aufrufen next. Diese Middleware-Funktion muss über jeder anderen Middleware platziert werden, die diese Einheimischen verwenden muss.

BEARBEITEN: Ein weiterer Unterschied zwischen der Deklaration von Einheimischen über app.localsund res.localsbesteht darin, dass app.localsdie Variablen ein einziges Mal festgelegt werden und während der gesamten Lebensdauer der Anwendung bestehen bleiben. Wenn Sie Einheimische mit res.localsin Ihrer Middleware festlegen, werden diese jedes Mal festgelegt, wenn Sie eine Anfrage erhalten. Grundsätzlich sollten Sie das Setzen von Globals über bevorzugen, es sei app.localsdenn, der Wert hängt von der Anforderungsvariablen ab req, die an die Middleware übergeben wird. Wenn sich der Wert nicht ändert, ist es effizienter, ihn nur einmal einzustellen app.locals.

Cory Gross
quelle
1
app.locals macht mehr Sinn als ich vorgeschlagen habe. Es gibt jedoch einen Haken: Sie können nicht auf die Einheimischen in Ihrer Middleware zugreifen. In diesem Fall spielt es wahrscheinlich keine Rolle, aber es ist eine dieser Fallstricke, auf die Sie manchmal stoßen.
Pickels
Sie können die Konfiguration auch in einer js- oder json-Datei definieren und sie einfach überall dort benötigen, wo Sie sie benötigen. Die Datei wird während der Anwendung nur einmal geladen, und jedes Modul, das dies erfordert, erhält Zugriff auf die von ihm definierten Werte. Siehe die verschiedenen Antworten unter stackoverflow.com/questions/5869216/…
Joe Lapp
51
In Express 4 locals ist keine Funktion, sondern ein Objekt. So legen Sie eine Eigenschaft fest:app.locals.site.title = 'Example';
Martti Laine
Beeindruckend! Jetzt kann die gesamte App über eine einzige Datei konfiguriert werden. Ein sauberer Schuss. +1
Dipak
@ Martintaine Danke Kumpel!
Ali Emre Çakmakoğlu
54

Sie können dies tun, indem Sie sie dem lokalen Objekt in einer allgemeinen Middleware hinzufügen.

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 ist auch eine Funktion, die das lokale Objekt erweitert, anstatt es zu überschreiben. Das Folgende funktioniert also auch

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

Vollständiges Beispiel

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

Ich habe auch eine generische Render-Middleware hinzugefügt. Auf diese Weise müssen Sie nicht jeder Route res.render hinzufügen, was bedeutet, dass Sie den Code besser wiederverwenden können. Sobald Sie die wiederverwendbare Middleware-Route eingeschlagen haben, werden Sie feststellen, dass Sie viele Bausteine ​​haben, die die Entwicklung enorm beschleunigen.

Pickels
quelle
Ich weiß, dass dies eine alte Antwort ist, aber die Parameter in Ihrer globalLocalsFunktion für reqund ressind rückwärts.
brandon927
Kann ich auf diese Weise Daten abfragen, die global sein sollen, z. B. Navigationsdaten, die bei jeder Seitenanforderung direkt aus der Datenbank geladen werden? Das scheint zu sein, dass diese Idee die Verwendung von Einheimischen überschreiten könnte, z. B. ein Mungo-Anruf. Ich suche nach direkter Last auf jeder Route, da die Navigationsleiste global ist, werde ich mich später mit dem Caching befassen. Alternativ brauche ich vielleicht eine Funktion, die einmal ausgeführt wird und diese dann nach dem Sammeln der Daten an die Einheimischen lädt.
Blamb
1
res.localsscheint keine Funktion mehr zu sein.
Killjoy
Ich verwende Ihren Ansatz, um einige Produkte in der Fußzeile anzuzeigen. Vielen Dank!
Carnaru Valentin
18

Für Express 4.0 stellte ich fest, dass die Verwendung von Variablen auf Anwendungsebene etwas anders funktioniert und Corys Antwort bei mir nicht funktioniert hat.

Aus den Dokumenten: http://expressjs.com/en/api.html#app.locals

Ich habe festgestellt, dass Sie eine globale Variable für die App in deklarieren können

app.locals

z.B

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

Und dann können Sie in Ihrer Anwendung auf diese Variablen zugreifen und in Ihrer Express-Middleware können Sie im req-Objekt als auf sie zugreifen

req.app.locals.baseUrl

z.B

console.log(req.app.locals.baseUrl)
//prints out http://www.google.com
RamRovi
quelle
1
Außerdem muss der Express-Server neu gestartet werden, wenn neue Einheimische in den Code eingefügt werden.
Wtower
14

In Ihrer app.js müssen Sie so etwas hinzufügen

global.myvar = 100;

Jetzt können Sie in all Ihren Dateien, in denen Sie diese Variable verwenden möchten, einfach als darauf zugreifen myvar

Fernando Bustos
quelle
Ich benutze Require-Module und musste wie global.myvarüberall darauf verweisen , und das hat funktioniert. Dies war eine schöne einfache Lösung für socket.io, wo ich Nachrichten von Handlern in anderen Dateien ausgeben möchte. Ich lege mein "io" Objekt an global.myIOund alles funktioniert super.
Thom Porter
6
Dies wird in der Knotenentwicklung nicht empfohlen oder als bewährte Methode angesehen. Node.JS enthält eine Modulsystemimplementierung, die auf dem CommonJS-System basiert, und konzentriert sich vollständig auf die Idee von Modulen, die keinen globalen Bereich gemeinsam nutzen, sondern die Methode require verwenden. Dadurch wird auch eine globale js-Variable in Node anstelle einer lokalen für Express-Ansicht / Vorlagen festgelegt, wie in der Frage angegeben.
Cory Gross
@CoryGross Ist es eine gute Praxis, das Anforderungsobjekt als globale Variable wie diese festzulegen?
Ali Sherafat
Nur das hat funktioniert. Danke Herr F! @CoryGross Wie lasse ich alle Dateien in meiner Anwendung auf ein einzelnes Objekt zugreifen?
Divij Sehgal
Dies ist die beste Antwort. Dies bedeutet, dass das globale Objekt an eine Ansicht oder an einen beliebigen Ort übergeben werden kann. Auf global.cdnURL = "https://cdn.domain.comdiese Weise können Sie zu einer Ansicht übergehen, um statische Inhalte zu laden.
Band eins
1

Eine Möglichkeit, dies zu tun, besteht darin, die app.localsVariable für diese App in zu aktualisierenapp.js

Stellen Sie Folgendes ein

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

Zugang erhalten

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

Ausarbeitung eines Screenshots aus dem @ RamRovi-Beispiel mit geringfügiger Verbesserung.

Geben Sie hier die Bildbeschreibung ein

Gajen Sunthara
quelle
1

Sie können auch "global" verwenden

Beispiel:

deklarieren Sie wie folgt:

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

Verwendung wie folgt: in beliebigen Ansichten oder EJS-Dateien <% console.log (site_url); %>

in js-Dateien console.log (site_url);

Shaik Matheen
quelle
0

Mit den unterschiedlichen Antworten habe ich diesen Code implementiert, um eine externe Datei JSON zu verwenden, die in "app.locals" geladen ist.

Parameter

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

Anwendung

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 Seite

<!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>

Ich hoffe, es wird helfen

Juan - 6510866
quelle
-1

Um einen verschmutzten globalen Bereich zu vermeiden, erstelle ich ein Skript, das ich überall einfügen kann.

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

Dadurch wird nur einmal eine neue Instanz erstellt und diese überall dort freigegeben, wo die Datei enthalten ist. Ich bin nicht sicher, ob dies daran liegt, dass die Variable zwischengespeichert ist oder an einem internen Referenzmechanismus für die Anwendung (der möglicherweise das Zwischenspeichern umfasst). Alle Kommentare dazu, wie der Knoten dies löst, wären großartig.

Vielleicht lesen Sie auch dies, um zu erfahren, wie die Anforderungen funktionieren: http://fredkschott.com/post/2014/06/require-and-the-module-system/

Dewwwald
quelle