Как с помощью Express / Node.JS создать глобальные переменные, доступные во всех представлениях?

81

Итак, я создал блог, используя 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. Есть ли способ сделать это и при этом позволить мне передавать другие переменные, специфичные для каждой страницы?

Кори Гросс
источник

Ответы:

109

После того, как я получил возможность еще немного изучить Справочник по API Express 3, я обнаружил то, что искал. В частности, в записях, 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.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.

Кори Гросс
источник
1
app.locals имеет больше смысла, чем то, что я предлагал. Однако у него есть одна загвоздка: вы не можете получить доступ к локальным элементам в вашем промежуточном программном обеспечении. В этом случае это, вероятно, не имеет значения, но это одна из тех ошибок, с которыми вы иногда сталкиваетесь.
Пикелс
Вы также можете определить конфигурацию в файле js или json и просто require () везде, где вам это нужно. Файл загружается только один раз во время приложения, и каждый модуль, которому он требуется, получает доступ к определенным им значениям. См. Различные ответы на stackoverflow.com/questions/5869216/…
Джо Лапп
51
В Express 4 locals это не функция, а объект. Чтобы установить свойство:app.locals.site.title = 'Example';
Martti Laine
Вот Это Да! Теперь все приложение настраивается с помощью одного файла. Чистый выстрел. +1
Дипак
@MarttiLaine Спасибо, дружище!
Али Эмре Чакмакоглу 07
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 к каждому маршруту, что означает более удобное повторное использование кода. Пройдя по пути многоразового промежуточного программного обеспечения, вы заметите, что у вас будет много строительных блоков, которые значительно ускорят разработку.

Пикели
источник
Я знаю, что это старый ответ, но параметры в вашей globalLocalsфункции для reqи resявляются обратными.
brandon927
Могу ли я таким образом запрашивать данные, которые должны быть глобальными, например данные навигационной панели, которые загружаются непосредственно из базы данных при каждом запросе страницы? Кажется, эта идея может выходить за рамки использования местных жителей, например, зов мангуста. Я ищу прямую загрузку на каждом маршруте, поскольку панель навигации глобальная, позже рассмотрим кеширование. В качестве альтернативы, может быть, мне нужна функция, которая запускается один раз, а затем загружает их местным жителям после сбора данных.
blamb 02
1
res.localsбольше не похоже на функцию.
killjoy
Я использую ваш подход, чтобы показывать некоторые товары в футере. Спасибо!
Карнару Валентин
18

Для Express 4.0 я обнаружил, что использование переменных уровня приложения работает немного иначе, и ответ Кори не сработал для меня.

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

Я обнаружил, что вы можете объявить глобальную переменную для приложения в

app.locals

например

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

А затем в своем приложении вы можете получить доступ к этим переменным, а в своем промежуточном программном обеспечении вы можете получить к ним доступ в объекте req как

req.app.locals.baseUrl

например

console.log(req.app.locals.baseUrl)
//prints out http://www.google.com
RamRovi
источник
1
Также экспресс-сервер необходимо перезапускать, когда в код добавляются новые локальные переменные.
Wtower 05
14

В вашем app.js вам нужно добавить что-то вроде этого

global.myvar = 100;

Теперь во всех ваших файлах, которые вы хотите использовать эту переменную, вы можете просто получить к ней доступ как myvar

Фернандо Бустос
источник
Я использую требуемые модули, и мне приходилось ссылаться на них как на global.myvarвезде, и это сработало. Это было хорошее простое решение для socket.io, где я хочу отправлять сообщения от обработчиков в других файлах. Я включил свой объект "io", global.myIOи все отлично работает.
Thom Porter
6
На самом деле это не рекомендуется и не считается хорошей практикой при разработке Node. Node.JS включает реализацию модульной системы, основанную на системе CommonJS, и полностью сконцентрирован на идее модулей, которые не имеют общей глобальной области видимости, вместо этого используется метод require. Это также устанавливает глобальную переменную js в Node вместо локальной для экспресс-представления / шаблонов, как запрашивается в вопросе.
Кори Гросс
@CoryGross Это хорошая практика - устанавливать объект запроса как глобальную переменную, как это?
Али Шерафат
Только это сработало. Спасибо, мистер Ф! @CoryGross, как разрешить всем файлам в моем приложении доступ к одному объекту?
Divij Sehgal
Это лучший ответ. Это означает, что глобальный объект доступен для передачи в представление или куда угодно. Как , global.cdnURL = "https://cdn.domain.comчто вы можете перейти к виду , чтобы загрузить статический conent.
Том первый
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

С разными ответами я реализовал этот код для использования внешнего файла 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>

Надеюсь, это поможет

Хуан - 6510866
источник
-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;

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

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

Деввальд
источник