1

I've been arguing for some time against embedding server-side tags in JavaScript code, but was put on the spot today by a developer who seemed unconvinced

The code in question was a legacy ASP application, although this is largely unimportant as it could equally apply to ASP.NET or PHP (for example).

The example in question revolved around the use of a constant that they had defined in ServerSide code.

'VB
Const MY_CONST: MY_CONST = 1
If sMyVbVar = MY_CONST Then
    'Do Something
End If

//JavaScript
if (sMyJsVar === "<%= MY_CONST%>"){
    //DoSomething
}

My standard arguments against this are:

  1. Script injection: The server-side tag could include code that can break the JavaScript code
  2. Unit testing. Harder to isolate units of code for testing
  3. Code Separation : We should keep web page technologies apart as much as possible.

The reason for doing this was so that the developer did not have to define the constant in two places. They reasoned that as it was a value that they controlled, that it wasn't subject to script injection. This reduced my justification for (1) to "We're trying to keep the standards simple, and defining exception cases would confuse people"

The unit testing and code separation arguments did not hold water either, as the page itself was a horrible amalgam of HTML, JavaScript, ASP.NET, CSS, XML....you name it, it was there. No code that was every going to be included in this page could possibly be unit tested.

So I found myself feeling like a bit of a pedant insisting that the code was changed, given the circumstances.

Are there any further arguments that might support my reasoning, or am I, in fact being a bit pedantic in this insistence?

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
James Wiseman
  • 29,946
  • 17
  • 95
  • 158
  • 3
    What's the difference between using server side code to output javascript as opposed to using server side code to output HTML? If it's necessary, it's necessary. – Paddy Jan 17 '11 at 14:27
  • Your assumption is flawed - there's nothing wrong with the code example you provided. – user229044 Jan 17 '11 at 14:30
  • @Paddy, @meagar: While appreciate your comments, I was hoping for more of a discussion as to "why?", as provided by @Pointy in his excellent answer. My original question directly addresses @Paddy's question ("What's the difference..."), while explaining why @meagar's assertion ("your assumption is flawed") is in itself flawed. – James Wiseman Jan 17 '11 at 14:59
  • In fact, it is not mbedding server-side tags in JavaScript code but quite contrary. Think of it – Your Common Sense Jan 17 '11 at 15:03
  • Just think of the order these instructions being executed in. What's going to be executed first? – Your Common Sense Jan 17 '11 at 15:11
  • Yes, but by that argument, everything in reality that cotains server side scripts is actually iself just embedded code within the script. While this might be the case in theory, in every-day prectice we refer to the abstraction which implies that the script is embedded, not vice versa. – James Wiseman Jan 17 '11 at 15:16
  • yup, you got it! That's the way server side templates works. Just learn it better. There are zillions of sites that works this way. And, in your place I'd avoid people who says that server side script is embedded. They have no idea what are they talking about. – Your Common Sense Jan 17 '11 at 15:44

3 Answers3

2
  • Script injection: The server-side tag could include code that can break the JavaScript code

So write the code properly and make sure that values are correctly escaped when introduced into the JavaScript context. If your framework doesn't include a JavaScript "quoter" tool (hint: the JSON support is probably all you need), write one.

  • Unit testing. Harder to isolate units of code for testing

This is a good point, but if it's necessary for the server to drop things into the page for code to use, then it's necessary. I mean, there are times when this simply has to be done. A good way to do it is for the page to contain some sort of minimal block of data. Thus the server-munged JavaScript on the page really isn't "code" to be tested, it's just data. The real client code included from .js files can find the data and use it.

Thus, the page may contain:

<script>
  (function(window) {
    window['pageData'] = {
      companyName: '<%= company.name %>',
      // etc
    };
  })(this);
</script>

Now your nicely-encapsulated pure JavaScript code in ".js" files just has to check for window.pageData, and it's good to go.

  • Code Separation : We should keep web page technologies apart as much as possible.

Agreed, but it's simply a fact that sometimes server-side data needs to drive client-side behavior. To create hidden DOM nodes solely for the purpose of storing data and satisfying your rules is itself a pretty ugly practice.

Coding rules and aesthetics are Good Things. However, one should be pragmatic and take everything in perspective. It's important to remember that the context of such rules is not always a Perfect Divine Creation, and in the case of HTML, CSS, and JavaScript I think that fact is glaringly clear. In such an imperfect environment, hard-line rules can force you into unnecessary work and code that's actually harder to maintain.

edit — oh here's something else I just thought of; sort-of a compromise. A "trick" popularized (in part) by the jQuery gang with their "micro template" facility (apologies to the web genius who actually hit upon this first) is to use <script> tags that are sort-of "neutered":

<script id='pageData' type='text/plain'>
  {
    'companyName': '<%= company.name %>',
    'accountType': '<%= user.primaryAccount.type %>',
    // etc
  }
</script>

Now the browser itself will not even execute that script - the "type" attribute isn't something it understands as being code, so it just ignores it. However, browsers do make the content of such scripts available, so your code can find the script by "id" value and then, via some safe JSON library or a native browser API if available, parse the notation and extract what it needs. The values still have to be properly quoted etc, but you're somewhat safer from XSS holes because it's being parsed as JSON and not as "live" full-blown JavaScript.

Pointy
  • 405,095
  • 59
  • 585
  • 614
1

The reason for doing this was so that the developer did not have to define the constant in two places.

To me, this is a better argument than any argument you can make against it. It is the DRY principle. And it greatly enhances code maintainability.

Every style guide/rule taken to extreme leads to an anti-pattern. In this case your insistence of separation of technology breaks the DRY principle and can potentially make code harder to maintain. Even DRY itself if taken to extreme can lead to an anti-pattern: softcoding.

Code maintainability is a fine balance. Style guides are there to help maintain that balance. But you have to know when those very guides help and when they themselves become a problem.


Note that in the example you have given the code would not break syntax hilighting or parsing (even stackoverflow hilights it correctly) so the IDE argument would not work since the IDE can still parse that code correctly.

Community
  • 1
  • 1
slebetman
  • 109,858
  • 19
  • 140
  • 171
0
  1. it simply gets unreadable. You have to take a closer look to divide the different languages. If JavaScript and the mixed-in language use the same variable names, things are getting even worse. This is especially hard for people that have to look at others people code.

  2. Many IDEs have problems with syntax highlighting of heavily mixed documents, which can lead to the loss of Auto-Completion, proper Syntax Highlighting and so on.

  3. It makes the code less re-usable. Think of a JavaScript function that does a common task, like echoing an array of things. If you separate the JavaScript-logic from the data it's iterating over, you can use the same function all over your application, and changes to this function have to be done only once. If the data it's iterating over is mixed with the JavaScript output loop you probably end up repeating the JavaScript code just because the mixed in language has an additional if-statement before each loop.

acme
  • 14,654
  • 7
  • 75
  • 109