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


81

좋습니다. 저는 Jekyll을 사용하여 블로그를 만들었 _config.yml으며 모든 템플릿 / 레이아웃에서 액세스 할 수 있는 파일에 변수를 정의 할 수 있습니다. 저는 현재 Node.JS / ExpressEJS 템플릿 및 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.localsres.locals함께 있다는 것입니다 app.locals변수 하나의 시간을 설정하고 응용 프로그램의 수명이 다할 때까지 유지됩니다. res.locals미들웨어에서 로컬을 설정하면 요청을받을 때마다 설정됩니다. app.localsreq이 미들웨어에 전달 된 요청 변수 에 의존하지 않는 한 기본적으로 전역 설정을 선호해야합니다 . 값이 변경되지 않으면에서 한 번만 설정하는 것이 더 효율적입니다 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.