Как да създадете глобални променливи, достъпни във всички изгледи с помощта на Express / Node.JS?

Добре, създадох блог с помощта на Jekyll и можете да дефинирате променливи във файл _config.yml, които са достъпни във всички шаблони/оформления. В момента използвам Node.JS / Express с EJS шаблони и ejs-locals (за части/оформления . Търся да направя нещо подобно на глобалните променливи като site.title, които се намират в _config.yml, ако някой е запознат с Jekyll. Имам променливи като заглавие на сайта (вместо заглавие на страница), име на автор/компания, които остават същите на всички мои страници.

Ето пример за това, което правя в момента:

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

Бих искал да мога да дефинирам променливи като заглавието, описанието, автора и т.н. на моя сайт на едно място и да ги имам достъпни в моите оформления/шаблони чрез EJS, без да се налага да ги предавам като опции за всяко извикване на res.render. Има ли начин да направя това и пак да ми позволи да предам други променливи, специфични за всяка страница?


person Cory Gross    schedule 08.05.2013    source източник


Отговори (8)


След като имах възможност да проуча Справочника за API на Express 3, открих още малко това, което търсих. По-конкретно записите за app.locals и след това малко по-надолу < a href="http://expressjs.com/api.html#res.locals" rel="noreferrer">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.title, site.description, author.name, author.contact.

Бих могъл също да дефинирам локални променливи за всеки отговор на заявка с res.locals или просто да предам променливи като заглавието на страницата като optionsпараметър в извикването render.

РЕДАКТИРАНЕ: Този метод няма да ви позволи да използвате тези локални файлове във вашия междинен софтуер. Всъщност се натъкнах на това, както Пикълс предлага в коментара по-долу. В този случай ще трябва да създадете функция на мидълуер като такава в неговия алтернативен (и оценен) отговор. Вашата междинна функция ще трябва да ги добави към res.locals за всеки отговор и след това да извика next. Тази функция на междинния софтуер ще трябва да бъде поставена над всеки друг междинен софтуер, който трябва да използва тези локални.

РЕДАКТИРАНЕ: Друга разлика между декларирането на локални чрез app.locals и res.locals е, че с app.locals променливите се задават еднократно и се запазват през целия живот на приложението. Когато зададете локални с res.locals във вашия междинен софтуер, те се задават всеки път, когато получите заявка. По принцип трябва да предпочитате да задавате глобални стойности чрез app.locals, освен ако стойността не зависи от променливата req на заявката, подадена в междинния софтуер. Ако стойността не се промени, тогава ще бъде по-ефективно да бъде зададена само веднъж в app.locals.

person Cory Gross    schedule 11.05.2013
comment
app.locals има повече смисъл от това, което предложих. Има обаче една уловка, не можете да получите достъп до локалните във вашия междинен софтуер. В този случай вероятно няма значение, но това е една от онези проблеми, с които понякога се сблъсквате. - person Pickels; 12.05.2013
comment
Можете също да дефинирате конфигурация в js или json файл и просто да я изисквате() навсякъде, където имате нужда. Файлът ще се зарежда само веднъж по време на приложението и всеки модул, който го изисква, получава достъп до дефинираните от него стойности. Вижте различните отговори на stackoverflow.com/questions/5869216/ - person Joe Lapp; 18.07.2014
comment
В Express 4 locals не е функция, а обект. За да зададете свойство: app.locals.site.title = 'Example'; - person Martti Laine; 10.01.2015
comment
Еха! Сега цялото приложение може да се конфигурира чрез един файл. Чист удар. +1 - person Dipak; 07.05.2016
comment
@MarttiLaine Благодаря приятелю! - person Ali Emre Çakmakoğlu; 07.07.2016
comment
Локалните променливи са налични в междинния софтуер на обекта на заявката в 4x чрез req.app.locals - person danialk; 26.05.2019
comment
@MarttiLaine Изглежда мога да задам само едно ниво надолу... така че app.locals.title = 'Example' работи, но app.locals.site.title = 'Example' не. Защо така? - person volume one; 06.11.2019

Можете да направите това, като ги добавите към обекта 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 към всеки маршрут, което означава, че имате по-добро повторно използване на кода. След като тръгнете по пътя на междинния софтуер за многократна употреба, ще забележите, че ще имате много градивни елементи, които ще ускорят неимоверно разработката.

person Pickels    schedule 09.05.2013
comment
Знам, че това е стар отговор, но параметрите във вашата globalLocals функция за req и res са назад. - person brandon927; 09.03.2015
comment
Мога ли да направя заявка за данни, предназначени да бъдат глобални, по този начин, напр. navbar данни, които се зареждат директно от db всяка заявка за страница? Изглежда, че тази идея може да превишава използването на местните, напр. обаждане на мангуста. Търся директно зареждане, на всеки маршрут, тъй като навигационната лента е глобална, ще разгледам кеширането по-късно. Като алтернатива, може би имам нужда от функция, която се изпълнява веднъж, след което ги зарежда на местните след събиране на данните. - person blamb; 02.07.2017
comment
res.locals изглежда вече не е функция. - person killjoy; 14.05.2020
comment
Използвам вашия подход, за да покажа някои продукти в долния колонтитул. Благодаря ти! - person Carnaru Valentin; 15.09.2020

За Express 4.0 открих, че използването на променливи на ниво приложение работи малко по-различно и отговорът на Кори не работи за мен.

От документите: http://expressjs.com/en/api.html#app.locals

Открих, че можете да декларирате глобална променлива за приложението в

app.locals

e.g

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

И тогава във вашето приложение можете да получите достъп до тези променливи и във вашия експресен междинен софтуер можете да получите достъп до тях в обекта req като

req.app.locals.baseUrl

e.g.

console.log(req.app.locals.baseUrl)
//prints out http://www.google.com
person RamRovi    schedule 18.03.2016
comment
Също така експресният сървър трябва да се рестартира, когато в кода се добавят нови локални. - person Wtower; 05.07.2016

Във вашия app.js трябва да добавите нещо подобно

global.myvar = 100;

Сега, във всички ваши файлове, които искате да използвате тази променлива, можете просто да получите достъп до нея като myvar

person Fernando Bustos    schedule 20.09.2013
comment
Използвам модули за изискване и трябваше да го споменавам като global.myvar навсякъде и това проработи. Това беше хубаво лесно решение за socket.io, където искам да излъчвам съобщения от манипулатори в други файлове. Поставих своя io обект на global.myIO и всичко работи чудесно. - person Thom Porter; 05.11.2013
comment
Това всъщност не се препоръчва или счита за добра практика в разработката на Node. Node.JS включва внедряване на модулна система, базирана на системата CommonJS и е изцяло съсредоточена върху идеята за модули, които не споделят глобален обхват, вместо това използвайки метода на изискване. Това също задава глобална js променлива в Node вместо локална за експресен изглед/шаблони, както изисква въпросът. - person Cory Gross; 25.11.2013
comment
@CoryGross Добра практика ли е да зададете обект на заявка като глобална променлива като тази? - person Ali Sherafat; 28.07.2017
comment
Само това проработи. Благодаря г-н F! @CoryGross как да позволя на всички файлове в моето приложение да имат достъп до един обект? - person Divij Sehgal; 14.01.2019
comment
Това е най-добрият отговор. Това означава, че глобалният обект е достъпен за преминаване към изглед или където пожелаете. Като global.cdnURL = "https://cdn.domain.com, който можете да прехвърлите към изглед, за да заредите статично съдържание. - person volume one; 21.11.2019

можете също да използвате "глобален"

Пример:

декларирайте така:

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

person Shaik Matheen    schedule 21.10.2016

Един от начините да направите това, като актуализирате променливата 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 с леко подобрение.

въведете описание на изображението тук

person Gajen Sunthara    schedule 16.07.2016

С различните отговори внедрих този код, за да използвам външен файл JSON, зареден в „app.locals“

Параметри

{
    "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="/bg/css/<%= web.cssFile %>">
</head>

</body>
</html>

Надявайки се, че ще помогне

person Juan - 6510866    schedule 10.06.2020

Това, което правя, за да избегна замърсен глобален обхват, е да създам скрипт, който мога да включа навсякъде.

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

person dewwwald    schedule 26.07.2017