Как создать глобальные переменные, доступные во всех представлениях, используя 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, а затем немного ниже < 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.

EDIT: этот метод не позволит вам использовать эти локальные переменные в промежуточном программном обеспечении. Я действительно столкнулся с этим, как предлагает Пикелс в комментарии ниже. В этом случае вам нужно будет создать функцию промежуточного программного обеспечения как таковую в его альтернативном (и оцененном) ответе. Ваша промежуточная функция должна будет добавить их в res.locals для каждого ответа, а затем вызвать next. Эта функция промежуточного программного обеспечения должна быть размещена над любым другим промежуточным программным обеспечением, которое должно использовать эти локальные переменные.

EDIT: Еще одно различие между объявлением локальных переменных через 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 и просто использовать require() везде, где вам это нужно. Файл загружается только один раз во время работы приложения, и каждый модуль, которому он требуется, получает доступ к определенным в нем значениям. См. различные ответы на 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
Могу ли я таким образом запрашивать данные, предназначенные для глобального использования, например. данные навигационной панели, которые загружаются непосредственно из БД при каждом запросе страницы? Кажется, что эта идея может выходить за рамки использования местных жителей, например. зов мангуста. Я ищу прямую загрузку на каждом маршруте, поскольку навигационная панель является глобальной, позже рассмотрим кеширование. В качестве альтернативы, может быть, мне нужна функция, которая запускается один раз, а затем загружает их локальным жителям после сбора данных. - 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, где я хочу отправлять сообщения от обработчиков в других файлах. Я поместил свой объект ввода-вывода на global.myIO, и все отлично работает. - person Thom Porter; 05.11.2013
comment
На самом деле это не рекомендуется и не считается хорошей практикой при разработке Node. Node.JS включает в себя реализацию модульной системы, основанную на системе CommonJS, и полностью сосредоточен на идее модулей, которые не имеют общей области действия, вместо этого используя метод require. Это также устанавливает глобальную переменную js в Node вместо локальной для представления/шаблонов Express, как запрашивает вопрос. - person Cory Gross; 25.11.2013
comment
@CoryGross Рекомендуется ли устанавливать объект запроса как глобальную переменную, как это? - person Ali Sherafat; 28.07.2017
comment
Только это сработало. Спасибо, мистер Ф! @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="/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;

При этом будет создан новый экземпляр только один раз, и он будет использоваться везде, где есть файл. Я не уверен, связано ли это с тем, что переменная кэшируется, или из-за внутреннего механизма ссылок для приложения (который может включать кэширование). Любые комментарии о том, как node разрешает это, были бы замечательными.

Возможно, также прочитайте это, чтобы получить представление о том, как работает require: http://fredkschott.com/post/2014/06/require-and-the-module-system/

person dewwwald    schedule 26.07.2017