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


81

Гаразд, отже, я створив блог за допомогою Jekyll, і ви можете визначити змінні у файлі _config.yml, доступні у всіх шаблонах / макетах. В даний час я використовую Node.JS / Express із шаблонами EJS та ejs-local (для часткових компонувань / макетів. Я прагну зробити щось подібне до глобальних змінних, подібних до 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 3 Express, я виявив, що шукав. Зокрема, записи, 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 і просто вимагати () її скрізь, де вам це потрібно. Файл завантажується лише один раз під час роботи програми, і кожен модуль, який вимагає від нього, отримує доступ до визначених ним значень. Дивіться різні відповіді на stackoverflow.com/questions/5869216/…
Joe Lapp

51
У Express 4 locals це не функція, а об'єкт. Щоб встановити властивість:app.locals.site.title = 'Example';
Марті Лайн

Оце Так! Тепер цілу програму можна налаштувати через один файл. Чистий постріл. +1
Діпак

@MarttiLaine Дякую приятелю!
Алі Емре Чакмакоглу

55

Це можна зробити, додавши їх до об’єкту місцевих жителів у загальному проміжному програмному забезпеченні.

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

Місцеві жителі - це також функція, яка розширює об’єкт місцевих жителів, а не перезаписує його. Отже, працює і наступне

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,

Чи можу я запитати дані, які мають бути загальнодоступними, наприклад, наприклад, дані навігаційної панелі, які завантажуються безпосередньо з db кожного запиту сторінки? Очевидно, ця ідея може перевищувати використання місцевих жителів, наприклад, мангустський дзвінок. Я шукаю пряме завантаження на кожному маршруті, оскільки навігаційна панель є глобальною, пізніше буде розглядатися кешування. Як варіант, можливо, мені потрібна функція, яка запускається один раз, а потім завантажує їх місцевим жителям після збору даних.
blamb

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

1
Також експрес-сервер потрібно перезапустити, коли нові коди додаються в код.
Wtower

14

У своєму app.js потрібно додати щось подібне

global.myvar = 100;

Тепер у всіх ваших файлах, які ви хочете використовувати цю змінну, ви можете просто отримати до неї доступ як myvar


Я використовую модулі require, і мені довелося посилатися на нього, як і global.myvarскрізь, і це спрацювало. Це було приємне просте рішення для socket.io, де я хочу надсилати повідомлення від обробників в інших файлах. Я надів свій об'єкт "io", global.myIOі все працює чудово.
Том Портер,

6
Це насправді не рекомендується або вважається хорошою практикою у розробці Node. Node.JS включає реалізацію модульної системи, засновану на системі CommonJS, і повністю зосереджена на ідеї модулів, які не мають загального обсягу, замість цього використовує метод require. Це також встановлює глобальний js-змінний у Node замість локального для вигляду / шаблону Express, як запитує запитання.
Кори Гросс

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

Сподіваючись, це допоможе


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

Виконання цього дозволить створити новий екземпляр лише один раз і поділитися ним всюди, де файл включений. Я не впевнений, чи це тому, що змінна кешована, чи це через внутрішній посилальний механізм для програми (який може включати кешування). Будь-які коментарі щодо того, як вузол вирішує це, були б чудовими.

Можливо, також прочитайте це, щоб дізнатися про те, як потрібно працювати: http://fredkschott.com/post/2014/06/require-and-the-module-system/

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.