9

Questions

How to serve javascript file dynamically? Specifically, the scripts maintain most of its body but with some variables changable (imagine HTML Jade template, but this is for pure javascript).

Scenario

When user or browser (http GET in general) visits /file.js passing parameter api, e.g. /file.js?api=123456, I would like to output pure javascript where I can take that 123456 and put in inside of my code, dynamically. Content-Type is application/javascript.

Sample:

var api = #{req.query.api}; //Pseudo
//The rest of my javascripts template
...

From my main .js file, I have set up the route:

app.get( '/file.js', function( req, res ) {

    //Pseudo code that I would like to achieve
    var name = req.query.name;
    res.render( 'out_put_javascript_file_from_jade_file.jade', { name: name } );

});

So when a person visits /file.js, the script file will be rendered differently based on the parameter api passed in the URL. The only possible dynamic way I can think of is using Jade, but it doesn't allow pure javascript template. I believe there must be other solutions.

Please excuse my explanation. The problem is somewhat like this: How to generate a pure JavaScript file with Jade

4
  • 1
    Mmm, it's a bit dangerous to generate JS dynamically ? Why do you need a such feature ? you could call a my_common.js and generate inline JS in you JADE template. This inline JS would be the only JS which changes. But it's difficult to advice without more information :) Commented Sep 29, 2014 at 7:57
  • 1
    I am writing a small API snippet, but it needs to generate the API key from database in the javascript file. It's been fairly easy with PHP, but I have a lot to learn about NodeJS. You can picture it like this: User visits http://example.com/file.js?api=123, the browser returns application/javascript with the following code alert( 'Your API key is 123' );. Any method should work, but my limited knowledge doesn't come up with anything bright enough. Please advise. Commented Sep 29, 2014 at 16:02
  • Jade is a template engine for HTML. It makes no sense what you try to explain. Why do you need to generate a JS file? You don't really want to generate an alert()? So tell us what do you want to do with the generated output? Who handle it / is processing it? Commented Sep 29, 2014 at 19:58
  • Jade is just what I came up with, because I don't have any other solution. I believe there is a better solution. alert() is pseudo code only. I'd like that when a route is visit, e.g. /file.js?api=123, the browser will output pure javascript code that has part of its generated dynamically. PSEUDO: http.get /file.js?api=123 will produce api = 123; do_something_with_that_api(); OR http.get file.js?api=456 will produce api = 456; do_something_with_that_api();. Commented Sep 29, 2014 at 20:13

1 Answer 1

11

If you want to do something quick and dirty, then you can do something like this (based on your example in the comments).

App init - read the .js template file and cache it:

// this should be async, but hey, not teaching you that part here yet
var fileJs = fs.readFileSync('file.js.template');

File.js:

(function() {
  $(window).on('load', function() {
    alert('Your api key is API_KEY_CONST');
  });
})();

Request:

GET /api/file.js?key=123

Router:

app.get('/api/file.js', function(req, res) {

    var key = req.query.key;
    var key = fetchKeyFromDBSync(); // just to make it easier here, no async.
    var out = fileJs.replace(API_KEY_CONST, key);

    res.setHeader('content-type', 'text/javascript');
    res.write(out);
    res.end();
});

Now, this is really dumb and you should not try it at home, but it simply demonstrates how to do what you wanted.

Edit:

Depending on the file length, you might perform a bit better if you put the chunks of the file into an array, like:

var fileChunks = ['(function(){ blablabla;', 'var myAPIKey=', 'KEY_PLACEHOLDER', '; alert (myAPIKey);', '})()']

So later when you're resolving it with the real API key, you join the file.

fileChunks[2] = '12345';
var responseData = fileChunks.join('');
res.write(responseData);

But your last-accessed api key is then held in an array. Not quite future proof, but it shouls work if you need something quick.

Sign up to request clarification or add additional context in comments.

7 Comments

Wow! This is pretty quick and indeed dirty lol. But it really works for what I am asking for! I just have a quick question, is the fileJS.replace() really a String.prototype.replace? I just want to know how to use it correctly! Also, not dumb at all. I'm not trying it at home. I'll put it in production if there is no there possible solutions. I don't see any security concerns here.
Yes, fileJS.replace is doing that on the results of readFileSync (which gives back content of a file, so if it's a binary...) Anyway, you should ideally lazily load these and not serve them until they're ready (which is probably several miliseconds after your server starts). You could also do this: read the file contents as a stream, and make a transform stream to put between request and responses. Transformer would pipe data out to res as long as it sees no constants (CAPS). When it runs into caps, it pauses the writes and buffers input until it reads&replaces the constant and then pipe out.
The first approach only caches the file contents once. The stream reads the file every time. Depends on what you need.
I have a doubt on why is this a stupid way to do things? Maybe it is insecure, but I can't think of anything apart from URL spoofing. Wouldn't a server side validation be able to get rid of any sort of attacks?
Well, it feels smelly and I'm sure there are better ways to it. As for security, I wasn't even talking about that aspect. Do you have a specific question about it?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.