Is generating JS code which defines constants, considered bad practice? - javascript

I've seen things like this in many projects. Server generates html page with <script> tag, and JS code in it, which defines some "constants", using templates.
For example.
<script>
window.CONSTANTS = {};
window.CONSTANTS.USER_ID = "<?= getUserId() ?>";
window.CONSTANTS.BASE_PATH = "<?= getBasePath() ?>";
</script>
The other way I can think of, would be letting client to make an ajax call, to get all the necessary data.

Assigning variables to the global namespace (in the case of the browser, "window.[somevariable]") is considered dangerous/evil/whatever.
You should always, as a matter of what they call "good practice", namespace your stuff. Lets say your application is called Jumpr (to give it a trendy hipster name), you might consider namespacing variables and modules that belong to your app under the global variable "Jumpr".
In the case of constants, I personally like assigning constants to an app.CONSTANTS namespace:
Jumpr.CONSTANTS
As far as dynamically outputting constants from the server, which is not a bad thing in my opinion (keeps your server constants that are shared with your application constants in sync), you could opt to import them via a constants script file, which then imports into your namespace like so:
Constants.js (this file could be auto-generated at request-time):
var Jumpr = Jumpr || {};
Jumpr.CONSTANTS = {
SOMECONST: "Some Constant Value 0"
SOMECONST1: "Some Constant Value 1"
}
...etc. But this is just one way of doing it. If you're unfamiliar with this pattern, what it's doing is checking for an already defined Jumpr module. If it's not defined, it makes a new object. Otherwise, it uses the existing one and "extends" it using the defined constants.
Also note these aren't true constants. To achieve the illusion of constants in JS you would need to create a get/set closure that would then act as a read-only retriever, but I'm not going to go into that here.
Edit
Since the context of the question has changed, I'm going to update my answer:
In my view, no, its not bad to have dynamically generated constants. Those constants, I would assume, are being generated from your back-end constants. You might want these environments to be in sync (you could capture everything from server routes, to form names, to whatever else in there). I personally think that this could be a good thing.
I would like to caveat that with the idea that you'll be taking a performance hit for doing that. I would rather recommend that you reference a constants file/module, which is then updated every time your constants on the server side change. It'll reduce computing power required to generate your pages and is worth the effort since it's generally easy to set this up, and constants rarely change (key word: they're constant) :)
Note, that's exactly what I already recommended above.

It is a bad practice. Global variables and functions can be overwritten by other scripts. Here there is a good example.
I've Heard Global Variables Are Bad, What Alternative Solution Should I Use?
http://www.w3schools.com/js/js_best_practices.asp

Related

Is there a way to access/modify the "Execution Context" of a Node module/function

I understand the scoping rules of Node/JavaScript, and from, for example, Understanding Execution Context and Execution Stack in Javascript, I think I understand the principle of how Execution Contexts work: the question is can you actually get access to them?
From an answer to the 2015 question How can I get the execution context of a javascript function inside V8 engine (involving (ab)using (new Error()).stack), and the answer to the 2018 question How can we get the execution context of a function?, I suspect the answer is "no" but just in case things have changed: is it possible to access/modify the Execution Context of a Node module/function?
(I'm very aware this screams either XY Problem or a desire to abuse Node/JavaScript: hopefully the Background section below will provide more context, and – if there's a different way of achieving what I want – that will work as well.)
In a nutshell, I want to achieve something like:
sharedVar = 1 ;
anotherModule.someFunction() ;
console.log( sharedVar ) ; // Where 'sharedVar' has changed value
Having a function in a different module being able to change variables in its caller's scope at will seems the definition of "A Dangerous Thing™", so – if it's possible at all – I expect it would need to be more like:
sharedVar = 1 ;
anotherModule.hereIsMyExecutionContext( SOMETHING ) ;
anotherModule.someFunction() ;
console.log( sharedVar ) ; // Where 'sharedVar' has changed value
and anotherModule would be something like:
let otherExecutionContext ;
function hereIsMyExecutionContext( anExecutionContext ) {
otherExecutionContext = anExecutionContext ;
}
function someFunction() {
//do something else
otherExecutionContext.sharedVar = 42 ;
}
and the question becomes what (if anything) can I replace SOMETHING with?
Notes / Things That Don't Work (for me)
You shouldn't be trying to do this! I realize what I'm trying to achieve isn't "clean" code. The use-case is very specific, where brevity (particularly in the code whose value I want changing) is paramount. It is not "production" code where the danger of forgotten, unexpected side-effects matters.
Returning a new value from the function. In my real use-case, there would be several variables that I would like someFunction() to be able to alter. Having to do { var1, var2, ... varN } = anotherModule.someFunction() would be both inconvenient and distracting (while the function might change some of these variables' values, it is not the main purpose of the function).
Have the variables members of anotherModule. While using anotherModule.sharedVar would be the clean, encapsulated way of doing things, I'd really prefer not to have to use the module name every time: not only is it more typing, but it distracts from what the code that would be using these variables is really doing.
Use the global scope. If I wasn't using "use strict";, it would be possible to have sharedVar on the global object and freely accessible by both bits of code. As I am using strict-mode (and don't want to change that), I'd need to use global.sharedVar which has the same "cumbersomeness" as attaching it to anotherModule.
Use import. It looks like using import { sharedVar } from anotherModule allows "live" sharing of the variables I want between the two modules. However, by using import, the module using the shared variable has to be an ES Module (not a CommonJS Module), and cannot be loaded dynamically using require() (as I also need it to be). Loading it dynamically the ESM way (using import() as a function returning a promise) appears to work, but repeated loadings come from a cache. According to this answer to How to reimport module with ES6 import, there isn't a "clean" way of clearing that cache (cf. delete require.cache[] that works with CommonJS modules). If there is a clean way of invalidating a cached ESM loaded through import(), please feel free to add an answer to that question (and a comment here, please), although the current Node JS docs on ESMs don't mention one, so I'm not hopeful :-(
Background
In early December, a random question on SO alerted me to the Advent of Code website, where a different programming problem is revealed everyday, and I decided to have a go using Node. The first couple of problems I tackled using standalone JS files, at which point I realized that there was a lot of common code being copy-pasted between each file. In parallel with solving the puzzles, I decided to create a "framework" program to coordinate them, and to provide as much of the common code as possible. One goal in creating the framework was that the individual "solution" files should be as "lean" as possible: they should contain the absolute minimum code over that needed to solve the problem.
One of the features of the framework relevant to this question is that it reloads (currently using require()) the selected solution file each time, so that I can work on the solution without re-running the framework... this is why switching to import and ES Modules has drawbacks, as I cannot (cleanly) invalidate the cached solution module.
The other relevant feature is that the framework provides aoc.print(...) and aoc.trace(...) functions. These format and print their arguments: the first all the time; the second conditionally, depending on whether the solution is being run normally or in "trace" mode. The latter is little more than:
function trace( ... ) {
if( traceMode ) {
print( ... )
}
}
Each problem has two sets of inputs: an "example" input, for which expected answers are provided, and the "real" input (which tends to be larger and more involved). The framework would typically run the example input with tracing enabled (so I could check the "inner workings") and run the "real" input with tracing disabled (because it would produce too much output). For most problems, this was fine: the time "wasted" preparing the parameters for the call, and then making the call to aoc.trace() only to find there was nothing to do, was negligible. However, for one solution in particular (involving 10 million iterations), the difference was significant: nearly 30s when making the ignored trace; under a second if they calls were commented-out, or I "short-circuited" the trace-mode decision by using the following construct:
TRACE && aoc.print( ... )
where TRACE is set to true/false as appropriate. My "problem" is that TRACE doesn't track the trace mode in the framework: I have to set it manually. I could, of course, use aoc.traceMode && aoc.print( ... ), but as discussed above, this is more to type than I'd like and makes the solution's code more "cluttered" than I'd ideally want (I freely admit these are somewhat trivial reasons...)
One of the features of the framework relevant to this question is that it reloads the selected solution file each time
This is key. You should load not leave the loading, parsing and execution to require, where you cannot control it. Instead, load the file as text, do nefarious things to the code, then evaluate it.
The evaluation can be done with eval, new Function, the vm module, or by messing with the module system.
The nefarious things I was referring to would most easily be prefixing the code by some "implicit imports", whether you do that by require, import or just const TRACE = true;. But you can also do any other kind of preprocessing, such as macro replacements, where you might simply remove lines that contain trace(…);.
Looks like you're heading the wrong way. The Execution Context isn't meant to be accessible by the user code.
An option is to make a class and pass its instances around different modules for your purpose. JS objects exist in the heap and can be accessed anywhere as long as you have its reference, so you can control it at will.

Handling global variables in Meteor

I'm using a query on both server and client (pub/sub). So I have something like this at a few different locations.
const FOO = 'bar';
Collection.find({property:FOO})
Foo may potentially change and rather than have to update my code at separate locations, I was thinking it may be worth it to abstract this away to a global variable that is visible by both client and server.
I created a new file 'lib/constants.js' and simply did FOO = 'bar; (note no keyword). This seems to work just fine. I found this solution as the accepted answer How can I access constants in the lib/constants.js file in Meteor?
My question is if this a desired pattern in Meteor and even general JS.
I understand I can abstract this away into a module, but that may be overkill in this case. I also think using session/reactive vars is unsafe as it can kinda lead to action at a distance. I'm not even gonna consider using settings.json as that should only be for environment variables.
Any insights?
yes, If you are using older version of meteor then you can use setting.json but for updated version we have import option.
I don't think the pattern is that bad. I would put that file in /imports though and explicitly import it.
Alternatively, you can write into Meteor.settings.public from the server, e.g., on start-up, and those values will be available on the client in the same location. You can do this without having a settings file, which is nice because it doesn't require you to make any changes between development and production.
Server:
Meteor.startup(() => {
// code to run on server at startup
Meteor.settings.public.FOO = 'bar';
});
Client:
> console.log(Meteor.settings.public.FOO);
bar
This is actually a b̶a̶d̶ unfavoured pattern because with global variables you cannot track what things changed and in general constructing a modular and replaceable components is much better. This pattern was only made possible due to Meteor early days where imports directory/pattern was not supported yet and you'd have your entire code split up between both,server and client.
https://docs.meteor.com/changelog.html#v13220160415
You can find many write ups about it online and event stackoverflow answers so I don't want to restate the obvious.
Using a settings.json variable is not an option since we may dynamically change so what are our options? For me I'd say:
Store it the database and either publish it or retrieve it using methods with proper access scoping of course. Also you can dynamically modify it using methods that author DB changes.
Or, you may try using Meteor.EnvironmentVariable. I'd be lying if I said I know how to use it properly but I've seen it being used in couple Meteor projects to tackle a similar situation.
https://www.eventedmind.com/items/meteor-dynamic-scoping-with-environment-variables
Why are global variables considered bad practice?

In Javascript, can constants be shared between files, as in Ruby?

This is probably an odd question because it's more typical for people to ask how to avoid using globals.
Coming from the Ruby world, I've become very comfortable using globals in two specific examples:
Constants. When a file is imported in Ruby, all of its constants are automatically made available to the other files in the program.
(and this ties in with the first) Packages. When I load a Ruby Gem in a required file, it also becomes available in my other files.
I've been starting to use module.exports, but I'm finding that I'm importing same modules in lots of different files.
I'd really like to have these features in Javascript. The way I'm writing my code at the moment, I'm using a functional approach and passing all my constants as parameters. The problem is my code is getting too verbose for my liking.
I'm really not looking for a "short answer: no" type of response, here. Even if it is too difficult, I'd appreciate being pointed in a direction for how to avoid passing constants as parameters to functions.
One method of using globals could be to use HTML5 Local Storage.
My thinking is, have an object with your globals, and on page load save each global variable into its own local storage location.
So you have an object with your globals stored:
var globals = {
GLOBAL1: "SomeString",
GLOBAL2: 400
}
Then onload / or if you want to do it sooner have it called before the page loads, you can have a function run through your globals and save the values into local storage
for(var key in globals) {
localStorage.setItem(key, globals[key]);
}
Then, later on, when a function needs, for example GLOBAL2 you can call:
localStorage.getItem("GLOBAL2");

JavaScript Global Object referencing vs 'this'

I'm working on an application framework written as an object literal and for the sake of simplicity I'd like to do two things:
Have the object available globally
Use the object name (as globally defined) for all references (vs. using this)
So, I've run some tests, done research, and am not finding any good reason NOT to take this approach. My question is - am I missing something? Perf tests actually seem to favor my method and from a logistical level I don't see any issues. Looking at other frameworks I've seen a mix, but I know that the this reference is revered by many programmers.
For reference...
A very minimal example of my approach:
var myobj = {
someVal: 'foo',
init: function(){
// Make myobj available globally
window.myobj = myobj;
// Fire off a method
myobj.doStuff();
},
doStuff: function(){
// Just print out the contents...
console.log(myobj.someVal);
}
}
myobj.init();
Note the references are all to the global, not this.
Like I said, I've seen a mix of this, I guess I just would like to know if this could cause issues in the long-run or if this a much ado about nothing.
As far as limitations go, the first thing that comes to mind is that you could only have one instance of this object. Trying to initialize a new one would wipe out the object.
Another reason for using this rather than a global variable name is that this will point to the correct object even if the name of the variable changes.
If you really want this to be a "create once" global object whose name never changes then this technique isn't technically wrong. But it won't be able to be used in any other situation. It is probably wiser to consider writing code that will be more adaptable if the requirements change (for instance if you use a library that causes a naming conflict with the chosen variable name)
Using this lets you be flexible in renaming the variable and passing it in different contexts without worrying about tracking variable names. It also will make it easy to change if naming conflicts arise.

JSLint fails file due to undefined variable

I have just started putting JSLint into my build pipeline and it has been great. Although it has pointed out something in most of my files that is not an error as such, although it will see it as one. I have changed my constructor to now take an instance of this object so the tests pass, however I am not sure if I really should, as in all other major languages I would not need to do this.
I will have to add some more context to this, for it to make any sense so here goes.
I have the closest thing I can get to an Enum in javascript which is basically a globally scoped JSON style variable with a load of constants, it is used to describe event types so rather than every class that wants to raise/listen to events having to put hard coded strings, it can just use a constant from this enum variable. As I just mentioned I have these classes that make use of this static enum, but they just make use of the global version of this variable, not a local instance passed through the constructor, and this is where my problems begin, as in the actual app I know for a fact that the enum file will included which will make it globally accessible. However JSLint has no context of this, so it only sees an individual file without worrying about external dependencies, as it deems these to be bad, which in any other language would be true, but in JS you cannot achieve the same thing without having global variables (to my knowledge).
As I said originally, I have now added this enum to the constructor to let JSLint pass the files, however it just feels a bit wrong passing it in, but maybe this is because I am thinking about it as a regular developer and not a javascript developer...
Now should I stick to this, and pass it through the constructor, and just mock it in my tests, or should I take the approach that it should always be there?
I am sure this will be down to peoples personal opinions, but it would be nice to know if I am being an idiot and should just keep each file as its own silo, or if there is a way for me to have my cake and eat it.
I found that JSLint supports a comment to tell it of global variables:
/*globals myGlobal*/
I have decided to just use my enum as a global and get on with the more important things.
JavascriptLint greatly improves on JSLint in this respect, as it allows you to define inter-file dependencies:
If a script references a variable, function, or object from another script, you will need to add a /*jsl:import PathToOtherScript*/ comment in your script. This tells JavaScript Lint to check for items declared in the other script. Relative paths are resolved based on the path of the current script.
See: http://javascriptlint.com/docs/index.htm

Categories