Jak stworzyć zmienne globalne dostępne we wszystkich widokach za pomocą Express / Node.JS?


81

Ok, więc zbudowałem bloga używając Jekyll i możesz zdefiniować zmienne w pliku, _config.ymlktóre są dostępne we wszystkich szablonach / układach. Obecnie używam Node.JS / Express z szablonami EJS i lokalnymi ejs (dla częściowych / układów. Chcę zrobić coś podobnego do zmiennych globalnych, takich jak site.titlete, które można znaleźć w, _config.ymljeśli ktoś zna Jekyll. Mam zmienne takie jak tytuł witryny (zamiast tytułu strony), nazwa autora / firmy, które pozostają takie same na wszystkich moich stronach.

Oto przykład tego, co obecnie robię .:

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

Chciałbym móc zdefiniować zmienne, takie jak tytuł, opis, autor itp. Mojej witryny, w jednym miejscu i mieć je dostępne w moich układach / szablonach za pośrednictwem EJS bez konieczności przekazywania ich jako opcji do każdego wywołania res.render. Czy istnieje sposób, aby to zrobić i nadal pozwolić mi przekazywać inne zmienne specyficzne dla każdej strony?

Odpowiedzi:


109

Po dokładniejszym przestudiowaniu dokumentacji API Express 3 odkryłem, czego szukałem. W szczególności wpisy dotyczące, app.localsa następnie nieco dalej, res.localszawierały odpowiedzi, których potrzebowałem.

Sam odkryłem, że funkcja app.localspobiera obiekt i zapisuje wszystkie jego właściwości jako zmienne globalne w zakresie aplikacji. Te wartości globalne są przekazywane jako zmienne lokalne do każdego widoku. res.localsJednak zakres funkcji obejmuje żądanie, a zatem lokalne zmienne odpowiedzi są dostępne tylko dla widoków renderowanych podczas tego konkretnego żądania / odpowiedzi.

Więc dla mojego przypadku w moim app.jstym, co zrobiłem, było dodanie:

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

Następnie wszystkie te zmienne są dostępne w moich poglądów jak site.title, site.description, author.name, author.contact.

Mógłbym również zdefiniować zmienne lokalne dla każdej odpowiedzi na żądanie z res.localslub po prostu przekazać zmienne, takie jak tytuł strony, jako optionsparametr w renderwywołaniu.

EDYCJA: Ta metoda nie pozwoli ci na użycie tych lokalnych w twoim oprogramowaniu pośrednim. Właściwie natknąłem się na to, jak sugeruje Pickels w komentarzu poniżej. W takim przypadku będziesz musiał utworzyć funkcję oprogramowania pośredniego jako taką w jego alternatywnej (i docenianej) odpowiedzi. Twoja funkcja oprogramowania pośredniego będzie musiała dodać je do res.localskażdej odpowiedzi, a następnie wywołać next. Ta funkcja oprogramowania pośredniego będzie musiała zostać umieszczona nad jakimkolwiek innym oprogramowaniem pośrednim, które musi korzystać z tych lokalnych.

EDYCJA: Inną różnicą między deklarowaniem lokalizacji lokalnych za pośrednictwem app.localsi res.localsjest to, że app.localszmienne są ustawiane jednorazowo i trwają przez cały okres użytkowania aplikacji. Gdy ustawiasz lokalne res.localsw oprogramowaniu pośrednim, są one ustawiane za każdym razem, gdy otrzymasz żądanie. Zasadniczo powinieneś preferować ustawianie wartości globalnych via, app.localschyba że wartość zależy od reqzmiennej żądania przekazanej do oprogramowania pośredniego. Jeśli wartość się nie zmieni, bardziej wydajne będzie ustawienie jej tylko raz app.locals.


1
app.locals ma więcej sensu niż sugerowałem. Ma jednak jeden haczyk, nie możesz uzyskać dostępu do lokalnych w swoim oprogramowaniu pośrednim. W tym przypadku prawdopodobnie nie ma to znaczenia, ale jest to jedna z tych pułapek, na które czasami napotykasz.
Pickels

Możesz także zdefiniować konfigurację w pliku js lub json i po prostu wymagać () jej wszędzie tam, gdzie jej potrzebujesz. Plik zostanie załadowany tylko raz podczas aplikacji, a każdy moduł, który go wymaga, uzyska dostęp do zdefiniowanych przez siebie wartości. Zobacz różne odpowiedzi na stackoverflow.com/questions/5869216/ ...
Joe Lapp

51
W Express 4 locals nie jest funkcją, ale obiektem. Aby ustawić nieruchomość:app.locals.site.title = 'Example';
Martti Laine

Łał! Teraz całą aplikację można konfigurować za pomocą jednego pliku. Czysty strzał. +1
Dipak

@MarttiLaine Dzięki kolego!
Ali Emre Çakmakoğlu

55

Możesz to zrobić, dodając je do obiektu lokalnego w ogólnym oprogramowaniu pośredniczącym.

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

Lokalne to także funkcja, która rozszerza obiekt lokalny zamiast go nadpisywać. Więc poniższe działa również

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

Pełny przykład

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

Dodałem również ogólne oprogramowanie pośredniczące renderowania. W ten sposób nie musisz dodawać res.render do każdej trasy, co oznacza, że ​​masz lepsze możliwości ponownego wykorzystania kodu. Gdy przejdziesz ścieżką oprogramowania pośredniego wielokrotnego użytku, zauważysz, że masz wiele bloków konstrukcyjnych, które ogromnie przyspieszą rozwój.


Wiem, że to stary odpowiedź, ale params twojej globalLocalsfunkcją reqi ressą do tyłu.
brandon927

Czy mogę w ten sposób wyszukiwać dane, które mają być globalne, np. Dane paska nawigacyjnego, które ładują się bezpośrednio z bazy danych przy każdym żądaniu strony? Wydaje się, że ten pomysł może przekroczyć użycie miejscowych, np. Mangusty. Szukam bezpośredniego obciążenia na każdej trasie, ponieważ pasek nawigacyjny jest globalny, zajrzę do buforowania później. Alternatywnie, może potrzebuję funkcji, która działa raz, a następnie ładuje je do lokalnych po zebraniu danych.
blamb

1
res.localsnie wydaje się już być funkcją.
killjoy

Używam Twojego podejścia, aby pokazać niektóre produkty w stopce. Dziękuję Ci!
Carnaru Valentin,

18

W przypadku Express 4.0 stwierdziłem, że używanie zmiennych poziomu aplikacji działa trochę inaczej, a odpowiedź Cory'ego nie działa dla mnie.

Z dokumentów: http://expressjs.com/en/api.html#app.locals

Odkryłem, że możesz zadeklarować zmienną globalną dla aplikacji w

app.locals

na przykład

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

Następnie w swojej aplikacji możesz uzyskać dostęp do tych zmiennych, aw swoim ekspresowym oprogramowaniu pośrednim możesz uzyskać do nich dostęp w obiekcie req jako

req.app.locals.baseUrl

na przykład

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

1
Ponadto serwer ekspresowy musi zostać ponownie uruchomiony, gdy w kodzie zostaną dodane nowe lokalizacje.
Wtower,

14

W swoim app.js musisz dodać coś takiego

global.myvar = 100;

Teraz we wszystkich plikach, które chcesz użyć tej zmiennej, możesz uzyskać do niej dostęp jako myvar


Używam modułów wymagających i musiałem odwoływać się do nich jak global.myvarwszędzie, i to zadziałało. To było przyjemne i łatwe rozwiązanie dla socket.io, gdzie chcę wysyłać wiadomości od programów obsługi w innych plikach. Włączam obiekt „io” global.myIOi wszystko działa świetnie.
Thom Porter,

6
W rzeczywistości nie jest to zalecane ani uważane za dobrą praktykę w programowaniu Node. Node.JS zawiera implementację systemu modułowego opartego na systemie CommonJS i jest całkowicie skoncentrowany na idei modułów, które nie mają wspólnego zakresu globalnego, zamiast tego wykorzystują metodę require. To również ustawia globalną zmienną js w Node zamiast lokalnego dla widoku / szablonów Express, jak to zadaje pytanie.
Cory Gross,

@CoryGross Czy dobrym zwyczajem jest ustawienie obiektu żądania jako zmiennej globalnej w ten sposób?
Ali Sherafat

Tylko to działało. Dzięki, panie F! @CoryGross Jak umożliwić wszystkim plikom w mojej aplikacji dostęp do pojedynczego obiektu?
Divij Sehgal

To najlepsza odpowiedź. Oznacza to, że obiekt globalny jest dostępny do przekazania do widoku lub w dowolnym miejscu. W global.cdnURL = "https://cdn.domain.comten sposób możesz przejść do widoku, aby załadować statyczną zawartość.
tom pierwszy

1

Można to zrobić, aktualizując app.localszmienną dla tej aplikacji wapp.js

Ustaw za pomocą następujących

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

Uzyskać dostęp

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

Opracowanie ze zrzutem ekranu z przykładu @RamRovi z niewielkimi poprawkami.

wprowadź opis obrazu tutaj


1

możesz też użyć „globalnego”

Przykład:

zadeklaruj tak:

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

Użyj w ten sposób: w dowolnym widoku lub pliku ejs <% console.log (site_url); %>

w plikach js console.log (site_url);


0

Z różnymi odpowiedziami zaimplementowałem ten kod, aby użyć zewnętrznego pliku JSON załadowanego w „app.locals”

Parametry

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

Podanie

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;

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

Mam nadzieję, że to pomoże


-1

Aby uniknąć zanieczyszczonego zasięgu globalnego, tworzę skrypt, który mogę umieścić w dowolnym miejscu.

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

W ten sposób utworzysz nową instancję tylko raz i udostępnisz ją wszędzie tam, gdzie znajduje się plik. Nie jestem pewien, czy dzieje się tak, ponieważ zmienna jest buforowana, czy też z powodu wewnętrznego mechanizmu referencyjnego dla aplikacji (który może obejmować buforowanie). Wszelkie komentarze na temat tego, jak węzeł rozwiązuje ten problem, byłyby świetne.

Może również przeczytaj to, aby dowiedzieć się, jak działa Wymaganie: http://fredkschott.com/post/2014/06/require-and-the-module-system/

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.