如何使用 Express/Node.JS 在所有视图中创建可访问的全局变量?

好的,我已经使用 Jekyll建立了一个博客,你可以在一个文件 _config.yml中定义变量,这些变量可以在所有的模板/布局中访问。我目前使用 Node JS/特快EJS模板和 本地人(部分/布局。我期待做一些类似的全局变量,如 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的选项传递给它们。有没有一种方法可以做到这一点,同时仍然允许我传递特定于每个页面的其他变量?

115768 次浏览

You can do this by adding them to the locals object in a general middleware.

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 is also a function which will extend the locals object rather than overwriting it. So the following works as well

res.locals({
siteTitle: "My Website's Title",
pageTitle: "The Home Page",
author: "Cory Gross",
description: "My app's description",
});

Full example

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

I also added a generic render middleware. This way you don't have to add res.render to each route which means you have better code reuse. Once you go down the reusable middleware route you'll notice you will have lots of building blocks which will speed up development tremendously.

After having a chance to study the Express 3 API Reference a bit more I discovered what I was looking for. Specifically the entries for app.locals and then a bit farther down res.locals held the answers I needed.

I discovered for myself that the function app.locals takes an object and stores all of its properties as global variables scoped to the application. These globals are passed as local variables to each view. The function res.locals, however, is scoped to the request and thus, response local variables are accessible only to the view(s) rendered during that particular request/response.

So for my case in my app.js what I did was add:

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

Then all of these variables are accessible in my views as site.title, site.description, author.name, author.contact.

I could also define local variables for each response to a request with res.locals, or simply pass variables like the page's title in as the optionsparameter in the render call.

EDIT: This method will not allow you to use these locals in your middleware. I actually did run into this as Pickels suggests in the comment below. In this case you will need to create a middleware function as such in his alternative (and appreciated) answer. Your middleware function will need to add them to res.locals for each response and then call next. This middleware function will need to be placed above any other middleware which needs to use these locals.

EDIT: Another difference between declaring locals via app.locals and res.locals is that with app.locals the variables are set a single time and persist throughout the life of the application. When you set locals with res.locals in your middleware, these are set everytime you get a request. You should basically prefer setting globals via app.locals unless the value depends on the request req variable passed into the middleware. If the value doesn't change then it will be more efficient for it to be set just once in app.locals.

In your app.js you need add something like this

global.myvar = 100;

Now, in all your files you want use this variable, you can just access it as myvar

For Express 4.0 I found that using application level variables works a little differently & Cory's answer did not work for me.

From the docs: http://expressjs.com/en/api.html#app.locals

I found that you could declare a global variable for the app in

app.locals

e.g

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

And then in your application you can access these variables & in your express middleware you can access them in the req object as

req.app.locals.baseUrl

e.g.

console.log(req.app.locals.baseUrl)
//prints out http://www.google.com

One way to do this by updating the app.locals variable for that app in app.js

Set via following

var app = express();
app.locals.appName = "DRC on FHIR";

Get / Access

app.listen(3000, function () {
console.log('[' + app.locals.appName + '] => app listening on port 3001!');
});

Elaborating with a screenshot from @RamRovi example with slight enhancement.

enter image description here

you can also use "global"

Example:

declare like this :

  app.use(function(req,res,next){
global.site_url = req.headers.host;   // hostname = 'localhost:8080'
next();
});

Use like this: in any views or ejs file <% console.log(site_url); %>

in js files console.log(site_url);

What I do in order to avoid having a polluted global scope is to create a script that I can include anywhere.

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

Doing this will only create a new instance once and share that everywhere where the file is included. I am not sure if it is because the variable is cached or of it because of an internal reference mechanism for the application (that might include caching). Any comments on how node resolves this would be great.

Maybe also read this to get the gist on how require works: http://fredkschott.com/post/2014/06/require-and-the-module-system/

With the differents answers, I implemented this code to use an external file JSON loaded in "app.locals"

Parameters

{
"web": {
"title" : "Le titre de ma Page",
"cssFile" : "20200608_1018.css"
}
}

Application

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 Page

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

Hoping it will help