I would like to expose a node.js server variable to the client. I am trying to get express-expose to work.
I am not sure how to initialise and use that library.
In the express-expose guide the usage doesn't make sense
var express = require('express');
var expose = require('express-expose');
app = expose(app);
app.expose(...);
how can I use app in 'expose(app') before it was initialised ?
I used
const app = expose(express());
app.expose('var some = "variable";','head');
but that doesn't seem to work either.
Can anyone supply me please with an example that initialises the express-expose library and exports var 'some' to the client ?
(By exposing to the client I mean it will be available to all my javascript files as a global variable so that I could do 'console.log(some);' and it would print its value)
Using Pug
Since you're using Express with Pug, you can just call the res.render function and give it the variable you want. Here's how to do that.
Let's say you have a template called index.pug, it may look like this:
html
head
title= title
body
h1= message
On your server, the code responsible for the rendering should look like this. In this case we're passing someVariable to the view that needs to be rendered.
const someVariable = 'hello world!';
app.get('/', function (req, res) {
res.render('index', { title: 'Hey', message: someVariable })
})
A note on express-expose
The express-expose library is not maintained and hasn't been updated in 5 years. My advice would be to just render your variable as described previously or just use AJAX requests.
A note on using a global variable
I am using the 'pug' view engine. It is passed to the view but I want
it as a global javascript variable.
A better idea is to use Template Inheritence to create "generic layouts" and extend them as needed. Sharing a global variable with file you're rendering will not update it magically on the front-end if you're changing it in the back-end. Even if the variable is global.
If you want to reflect "real-time changes" you should look into Socket.io.
This seems like a code smell... But regardless, there are cleaner ways to do it.
If you want to expose a data object, that is, an object just containing keys and values, you could embed it in the rendered webpage, make it available via some API endpoint that the client can acquire via an AJAX request, or expose a raw Javascript file that can be included via <script> (or I guess script(...) in pug).
If you want to expose a more complex Javascript object, such as a class or an object with function definitions, you could expose the Javascript file and include it via script(...).
However, you should be very careful exposing a file used by the server. If there are any vulnerabilities, they are now public. If there are any hard-coded passwords (which shouldn't be in code anyway), they are now public. Anything in this file is now public, so if you do indeed want to do this, be very careful about what code gets into this now client-side file.
If you need more details on how this could work, please comment :)
Edit: Also be aware that using the embedded and include methods would not allow the variable to be updated on-the-fly. If you need the client to track any changes to the data as it changes on the server, you will want to use AJAX. This is the best method, in my opinion. It offers you the most flexibility.
Another edit: Judging by the issues on the express-expose project, it seems not well supported and maybe has security issues. For now, I would avoid it. Maybe at a later time, it will be helpful and secure.
If you want to expose a variable value to the client from server , that never changes or updates, you can simply add a hidden input field in your template and add the value of it
In your EJS template file this would look like
<% if (data) { %>
<input type="hidden" value="<%= data %>" id="myGlobal"/>
<% } %>
you must pass the data value in your res.render('template',{data:"hello"}) function to the template.
You can access this variable value from client using a simple document.getElementById("myGlobal").Again don't pass any sensitive information in hidden fields.
If you want to pass sensitive information , implement an endpoint in your server with authentication and call the endpoint from client via an ajax call .This is also a best approach to update the value of the variable from client side.
Related
I'm looking to create a single node.js application that will render multiple different client websites.
We currently run one node.js application per client website, but I think this might be overkill as the serverside logic is exactly the same for all of them, the only difference being the handlebars template.
I'm looking to re-architecture to have a single node.js application which will then render the different client's websites based on some incoming information, will use nginx to add a header or something to the request so the app knows which website to render.
Is it possible to store the handlebars template within a database and then request the template at render time? Rendering a simple single page should be easy enough, but I'm struggling to understand how partials would be rendered?
Looking to achieve something similar to Shopify's Storefront Renderer, not sure if it's possible to do with handlebars or if it's better to use of of the LiquidJs ports for Node to achieve this?
https://shopify.engineering/how-shopify-reduced-storefront-response-times-rewrite
I do this with different countries, same concept as you with different Clients.
You just create the Handlebars layout and put it in your partials folder. No need to put template in your database.
Then your server logic will have eg clientName, and your Handlebars will have IfEqual tags (you'll need an IfEqual helper)
Example:
Server route will give a variable clientName.
Handlebars you have the main view page with only the IfEqual helpers.
{{#ifEqual clientName 'Client Name 1'}}
{{> client/clientName1}}
{{/ifEqual}}
{{#ifEqual clientName 'Client Name 2'}}
{{> client/clientName2}}
{{/ifEqual}}
Your helper function will be
, helpers: {
ifEqual: function(x, y, options) {
return(x == y) ? options.fn(this) : options.inverse(this)
} // {{#ifEqual statusLogin 'unconfirmed'}} {{/ifEqual}}
Search nodejs handlebar helper if you dont know how to set it.
So my partial folder, you can create a folder in it called client, and put all your Handlebars template in there. Search for nodejs handlebars partial folder setup if you dont know how to do it.
The handlebar helper function I found it I think in stack overflow, so you can search for others if you want, but for me it works.
Your partial template files just do as normal Handlebar files.
So the main idea is User loads the page, depending on what Client flag you put it, it loads up that template.
I'm building isomorphic app using Node.js and ReactJS.
I've met a situation when inside some isomorphic React component (rendered both on client and server sides) I need to include only client-side dependency (some notifications library for example).
What is the best way to have it worked (compiled) both on server/client sides?
P.S: I have few thoughts about possible workarounds something like checking for browser env variables (ex. some typeof window !== 'undefined') etc. but I'm not sure it's a good way to go.
Use the lifecycle method componentDidMount which is not invoked on the server instead of checking if window is undefined.
The "downside" is if your client side dependency enhances an element for example or changes any property of it, it'll get the default property first since it was rendered server side and when componentDidMount runs it'll get changed causing a "blink".
If you are using browserify I often use process.browser which is only true in browserified code.
If you wanted to get fancy and remove server code from the browser instead there is also isbrowser which will do just that.
Another way (webpack or browserify) is to take advantage of the browser field in the package.json. You can make it so that the server requires a noop file and the browser requires a file the exposes the client side api.
I have defined variable in webpack configuration file called process.env.WEBPACK and in my code when i need something like bottstrap js or something else i just write
if(process.env.WEBPACK){
//awesome lib included or scss or whatever
}
how to restrict global variables and functions in node js?
like: require method
i want to limit use of require method.
i don't want any node app to access "fs" in my node framework which i build on top of express, they can only require modules which i want them to.
and also i want to restrict access to process, global scope .
suppose when i load any js library for any app
like:
var x=require('app1.js');
in my framework
then i want to make sure this app1.js cannot access filesystem using require("fs")
app1.js
var x=require("fs");
exports.hello=function(){
console.log(typeof x.readSync);
}
i want this console to print undefined;
and in this sample
var x=require("helper.js");
exports.hello=function(){
console.log(typeof x.hello);
}
i want this console to print function;
thanks in advance
I'd create a new function that will act like require.
requireSafe = function(param){
if(!isAllowedLogic(param)) return null;
else return require(param);
}
And when someone submits code, you append var require; at the top to prevent them to use the regular require. Or you search in their submission and only approve it if it doesn't contain require nor eval.
Why would you want to do that?
It is not possible to change the way require works, as it is a build-in node.js function.
Try this library,
for a bit of detail of how its security works, from the README :
A Node.js subprocess is created by the Jailed library;
the subprocess (down)loads the file containing an untrusted code as a
string (or, in case of DynamicPlugin, simply uses the provided string
with code)
then "use strict"; is appended to the head of that code (in order to
prevent breaking the sandbox using arguments.callee.caller);
finally the code is executed using vm.runInNewContext() method, where
the provided sandbox only exposes some basic methods like
setTimeout(), and the application object for messaging with the
application site.
On my node.js server I have the following code:
//Generate a token
var token = capability.generateToken();
//Serve the page
var html = fs.readFileSync('learn.htm').toString();
response.writeHead(200, {"Content-Type": "text/html"});
response.end(html);
}
Now on the client side (in learn.htm) I want to access the token variable. My question is, how do I pass the variable to the client in the response? There must be a simple way of doing this but I'm struggling to wrap my head around it.
You should look into using a template language for your HTML. There are several available, just search for node.js template language or using npm:
npm search templates
Edit: Some popular ones are jade, ejs, hogan.js.
You could send some JavaScript to the client which sets the variable. Or you could store it in a data- attribute e.g. of the body tag (<body data-token="...">) and then access it via $('body').data('token') in case you have jQuery on the client side.
If you need it for a form you can also store it in a hidden input field.
Put something like:
<input type="hidden" value="{{TOKEN}}">
in your HTML, then replace the {{TOKEN}} string with the token at each request.
Then use JS like:
var token = $("input#csrf_token").val();
to get the value in your client script.
Edit: I haven't used it myself, but nowjs (http://nowjs.com/) is a more general way of getting your server's variables to the client. It's probably not what you want for passing a simple token, but it might be of interest.
I have several environment settings that I need to inject into my javascript assets. Thinks like database uri and facebook app id. I'm currently using EJS as my view engine.
Is there a simple way of templating javascript files in NodeJS?
Rather than trying to template your static files, I'd suggest using an initializer script instead.
Simply put a <script> block in your layout, where you call a function in your JS file, which takes the DB uri and the FB app id as its parameters. The function can then store the values someplace where the rest of the scripts know how to access them.
You can easily pass your parameters into the layout (and views) for example by using helpers