Express / Node.JS를 사용하여 모든보기에서 액세스 할 수있는 전역 변수를 만드는 방법은 무엇입니까?


81

좋습니다. 저는 Jekyll을 사용하여 블로그를 만들었 _config.yml으며 모든 템플릿 / 레이아웃에서 액세스 할 수 있는 파일에 변수를 정의 할 수 있습니다. 저는 현재 Node.JS / Express 를 EJS 템플릿 및 ejs-locals (partials / layouts 용) 와 함께 사용하고 있습니다. 누군가 Jekyll에 익숙한 경우 에있는 전역 변수와 유사한 작업을 수행하려고합니다. 다음과 같은 변수 site.title가 있습니다 _config.yml. 내 모든 페이지에서 동일하게 유지되는 사이트의 제목 (페이지 제목 아님), 작성자 / 회사 이름.

다음은 내가 현재하고있는 작업의 예입니다. :

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

내 사이트의 제목, 설명, 작성자 등과 같은 변수를 한 곳에서 정의하고 .NET에 대한 각 호출에 대한 옵션으로 전달할 필요없이 EJS를 통해 내 레이아웃 / 템플릿에서 액세스 할 수 있도록하고 싶습니다 res.render. 이 작업을 수행하고 각 페이지에 특정한 다른 변수를 전달할 수있는 방법이 있습니까?

답변:


109

Express 3 API 참조 를 조금 더 공부 한 후 제가 찾고있는 것을 발견했습니다. 특히 항목에 대한 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있습니다.

편집 : 이 방법 을 사용하면 미들웨어에서 이러한 지역을 사용할 수 없습니다 . Pickels가 아래 의견에서 제안한 것처럼 실제로 이것을 실행했습니다. 이 경우 그의 대안 (및 감사) 답변에서 미들웨어 기능을 만들어야합니다. 미들웨어 함수는 res.locals각 응답에 대해 추가 한 다음 next. 이 미들웨어 기능은 이러한 로컬을 사용해야하는 다른 미들웨어 위에 배치되어야합니다.

편집 : 를 통해 지역 주민을 선언하는 또 다른 차이점 app.locals과 res.locals함께 있다는 것입니다 app.locals변수 하나의 시간을 설정하고 응용 프로그램의 수명이 다할 때까지 유지됩니다. res.locals미들웨어에서 로컬을 설정하면 요청을받을 때마다 설정됩니다. app.locals값 req이 미들웨어에 전달 된 요청 변수 에 의존하지 않는 한 기본적으로 전역 설정을 선호해야합니다 . 값이 변경되지 않으면에서 한 번만 설정하는 것이 더 효율적입니다 app.locals.


1
app.locals는 내가 제안한 것보다 더 의미가 있습니다. 하지만 미들웨어의 로컬에 액세스 할 수 없습니다. 이 경우에는 아마도 중요하지 않지만 때때로 부딪히는 문제 중 하나입니다.
— Pickels 2013 년

또한 js 또는 json 파일에서 구성을 정의하고 필요한 모든 곳에서 간단히 require () 할 수 있습니다. 파일은 응용 프로그램 중에 한 번만로드되며이를 필요로하는 모든 모듈은 정의 된 값에 액세스 할 수 있습니다. 에서 다양한 답변을 참조 stackoverflow.com/questions/5869216/...을
— 조 라플란드

51
Express 4 에서는 locals함수가 아니라 객체입니다. 속성을 설정하려면 :app.locals.site.title = 'Example';
— Martti Laine

와! 이제 단일 파일을 통해 전체 앱을 구성 할 수 있습니다. 깨끗한 샷. +1
— Dipak

@MarttiLaine 감사합니다 친구!
— Ali Emre Çakmakoğlu

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를 추가 할 필요가 없으므로 코드 재사용이 향상됩니다. 재사용 가능한 미들웨어 경로를 따라 가면 개발 속도를 엄청나게 높일 수있는 많은 빌딩 블록이 있음을 알게 될 것입니다.


나는이 오래된 대답은 알고 있지만 당신의 PARAMS globalLocals에 대한 기능 req과는 res거꾸로입니다.
— brandon927

예를 들어 각 페이지 요청을 db에서 직접로드하는 navbar 데이터와 같이 전역 데이터를 쿼리 할 수 ​​있습니까? 몽구스 호출과 같은이 아이디어는 현지인의 사용을 능가하는 것 같습니다. navbar가 전역이므로 나중에 캐싱을 조사 할 것이므로 모든 경로에서 직접로드를 찾고 있습니다. 또는 한 번 실행되는 함수가 필요할 수 있으며 데이터를 수집 한 후 로컬에로드합니다.
— blamb

1
res.locals더 이상 함수가 아닌 것 같습니다.
— killjoy

귀하의 접근 방식을 사용하여 일부 제품을 바닥 글에 표시합니다. 감사합니다!
— Carnaru 발렌틴

18

Express 4.0의 경우 응용 프로그램 수준 변수를 사용하는 것이 약간 다르게 작동하고 Cory의 답변이 작동하지 않는다는 것을 알았습니다.

문서에서 : 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하고 모두 훌륭하게 작동합니다.
— Thom Porter

6
이것은 실제로 노드 개발에서 권장되지 않거나 좋은 사례로 간주되지 않습니다. Node.JS는 CommonJS 시스템을 기반으로 한 모듈 시스템 구현을 포함하며 require 메소드를 사용하는 대신 전역 범위를 공유하지 않는 모듈의 아이디어에 완전히 집중되어 있습니다. 이것은 또한 질문이 요구하는 것과 같은 Express 뷰 / 템플릿에 대해 로컬 대신 Node에 전역 js var를 설정합니다.
— Cory Gross

@CoryGross 요청 객체를 이와 같은 전역 변수로 설정하는 것이 좋은 습관입니까?
— Ali Sherafat

이것 만이 효과가있었습니다. 감사합니다 Mr. F! @CoryGross 내 응용 프로그램의 모든 파일이 단일 개체에 액세스하도록하려면 어떻게해야합니까?
— Divij Sehgal

이것이 최고의 답변입니다. 이는 전역 개체를 뷰 또는 원하는 위치로 전달할 수 있음을 의미합니다. 마찬가지로 global.cdnURL = "https://cdn.domain.com당신이 정적의 conent을로드 뷰에 전달할 수 있습니다.
— 볼륨 1

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

다른 답변으로 "app.locals"에로드 된 외부 파일 JSON을 사용하도록이 코드를 구현했습니다.

매개 변수

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

이렇게하면 새 인스턴스가 한 번만 생성되고 파일이 포함 된 모든 곳에서 공유됩니다. 변수가 캐시 되었기 때문인지 또는 응용 프로그램에 대한 내부 참조 메커니즘 (캐싱이 포함될 수 있음) 때문인지 확실하지 않습니다. 노드가 이것을 어떻게 해결하는지에 대한 모든 의견은 좋을 것입니다.

require 작동 방식에 대한 요점을 얻으려면 http://fredkschott.com/post/2014/06/require-and-the-module-system/ 을 읽으십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.