I've installed Dreamweaver CC 2015 and found out that I have MYRIAD errors in my working JavaScript files.
Also I have MYRIAD errors in imported JavaScript libraries, including jQuery.
The most important "error" is this one in the beginning of every working function:
Missing "use strict" statement.
It worked quite well without "use strict" and I've never even seen this statement anywhere.
Another strange one is:
Extending prototype of native object: 'Array'.
Here is the code which provokes the warning:
Array.prototype.sortOn = function(key){
this.sort(function(a, b){
if(a[key] < b[key]){
return -1;
}else if(a[key] > b[key]){
return 1;
}
return 0;
});
};
So my options are:
Ditch Dreamweaver and use another IDE (the worst, because it works perfectly fine for my purposes - I'm sole HTML/CSS/JS/PHP/MySQL developer in my project.
Fix all errors like Dreamweaver wants, because it has a good point. Then please explain why? I'm OK with changing "==" to "===", adding "var" before variable declarations, not using "return" after "if" without curly braces, but that "use strict" thing bothers me.
Tweak the JavaScript validation, so only critical errors are shown - the best option for me - but I don't know HOW to do it?
What's the best option to go with?
Any help greatly appreciated.
Here's what I figured out.
The problem was that I was not aware of JSHint and JSLint solutions for validating javascript. JSHint is integrated into Dreamweaver CC and is easily configurable, provided you know what to do.
Normally JSHint has three ways to tweak it, but they don't work in the Dreamweaver environment.
What you should do is:
From the top menu select Edit -> Preferences (Dreamweaver -> Preferences on Mac)
Choose "Linting" from the side menu.
Select "JS" and click "Edit and save changes".
The file JS.jshintrc will be opened in Dreamweaver.
Edit the file like you normally would (see JSHint options) and save.
In my specific case I changed this:
"strict":false,
"undef":false,
"unused":false
...which means that I don't have to put "use strict" everywhere and may leave definitions and usage of variables in different files. YES, I don't use wrapper functions and use lots of globals. YES, I know it's bad, but refactoring this is not the highest priority in my schedule.
Of course I will change all three those options to "true" and refactor all my JS files to comply to standards when the time comes.
Turning off the "undef" check is a sledge hammer, as JSHint will then ignore all variable and function name typos. You won't find the typo until run time, which is annoying and time wasting.
Rather than disabling the "undef" messages completely, I've been using JSHint Inline Directives near the top of my .js files. For example:
/* globals myGlobalVar, myGlobalFunction */
var myLocalVar = myGlobalVar;
myGlobalFunction();
With the globals directive in the file, JSHint will not mark myGlobalVar or myGlobalFunction() as undefined errors. Using "globals" inline directives has the added benefit of documenting the dependencies between your .js files.
Read about JSHint inline directives here:
http://jshint.com/docs/#inline-configuration
Related
This is going to be a problem that very few if any people have, but it was time consuming and difficult to solve and i figured it out, so here is the solution, one other person in the world who has this problem.
Are you getting all kinds of weird "this.getOnOffValueFromModelValue is not a function" kinds of errors from guideRuntime.js, guide.js , or guidelib -- or other adobe frontend libraries that you do not control?
These may not apply to you directly but if they do definitely keep reading:
Are you using webpack and including custom code on the page elsewhere (perhaps via a data-sly-use or something)?
Does your project use lodash? or perhaps another library that uses a "_" global variable?
Or perhaps jQuery? or other frontend library?
Then you may be asking questions like:
Why is my form not working properly?
Why is some stuff on the form just not working?
Some rules are just not working... why not and how do i fix them?
Oh I'll feed you, baby birds.
( can someone with a higher reputation add the tags adobe-form, aem-form to this, please)
TLDR:
If you're using Webpack, add this to your module rules:
module: {
rules: [
{ parser: { amd: false } }
// ... your other rules
]
}
or if you're not using webpack, make sure your own variables are not leaking into the global scope, because adobe's are and yours may overwrite theirs or vice-versa.
The explanation that may be applicable even if you're not using webpack that may get you in the right direction:
Adobe's client libraries (like guide.js and guideRuntime and the like) aren't particularly good at dependency injecting their stuff. Their code leaks global variables a lot. For example (see picture below) they use underscore's _.each a lot. if you're using lodash, the function signatures are different-- underscores' allows you to define a "this" context as the third parameter, whereas lodash's doesn't.
So, in our case, our lodash was overwriting their underscore causing a bunch of weird issues... EVEN THOUGH we were NOT declaring lodash globally anywhere. WEBPACK WAS defining lodash globally
So moral of the story, open up console, check to see if any of your libraries are defined globally, and if they are, figure out how to make them not global until Adobe decides to fix their stuff (don't hold your breath).
I know that I can type into Chrome or FF the following command:
Object.keys(window);
but this displays DHTMLX stuff and also function names in which I'm not interested in. And it doesn't display variables in functions that have not been executed yet. We have more than 20,000 lines of JavaScript codebase, so I would prefer static code analyis. I found JavsScript Lint. It is a great tool but I don't know how to use it for displaying global vars.
So I'm searching for memory leaks, forgotten var keywords, and so on...
To do [only] what you're asking, I think you're looking for this:
for each (obj in window) {
if (window.hasOwnProperty(obj)) {
console.log(obj);
}
}
I haven't linted that code, which is unlike me, but you get the idea. Try setting something first (var spam = "spam";) and you'll see it reported on your console, and not the cruft you asked about avoiding.
That said, JLRishe is right; JSLint executes JavaScript in your browser without "phoning home", so feel free to run it. There are also many offline tools for JSLinting your code. I use a plugin for Sublime Text, for instance.
If you'd like some simplest-case html/JavaScript code to "wrap" JSLint, I've got an example here. Just download the latest jslint.js file from Crockford's repository into the same directory, and poof, you're linting with a local copy of JSLint.js. Edit: Added code in a new answer here.
Though understand that you're linting locally with that wrapper or when you visit JSLint.com. Honestly, I can say with some confidence, Crockford would rather not see our code. ;^) You download JSLint.js (actually webjslint, a minified compilation of a few files) from JSLint.com, but you execute in the browser.
(Admittedly, you're technically right -- you never know when that site could be compromised, and to be completely on the up and up, you sh/c/ould vet jslint.js each time you grab a fresh copy. It is safer to run locally, but as of this writing, you appear safe to use JSLint.com. Just eyeball your favorite browser's Net tab while running some test, non-proprietary code, and see if any phoning happens. Or unplug your box's network cable!)
Rick's answer to use "use strict"; is another great suggestion.
A great way to catch undeclared variables is to add 'use strict' to your code.
The errors will appear in the console, or you could display them in a try ... catch block:
'use strict';
try {
var i= 15;
u= 25;
} catch(ee) {
alert(ee.message);
}
I found a very good solution to list all the global variables with the jsl command line tool:
Here is the documentation
I just have to put /*jsl:option explicit*/ into each file that I want to check. Then it is enough to run ./jsl -process <someFile> | grep 'undeclared identifier'
It is also possible to use referenceFile that contains some intentional global variables /*jsl:import <referenceFile>*/ so these variables will not be listed.
I've seen some of the console wrappers that stop errors in browser with a console and more advanced ones that enable logging in older browsers. But none that I've seen help switch on and off the debug code.
At the moment I do a find and replace to comment out debug code. There must be a better way?
I'm using Combres which uses YUI to minify the JavaScript. I've seen some posts that mention using double semi colons to mark lines to be removed in the minification process. Is this a hack or good practice?
Probably you should have your own wrapper around console.log() and log your debug info via that wrapper. That way you can replace that single function with an empty function once you deploy to production so the console won't flood with debugging info. You can also replace the actual console.log function with an empty function, but that would prevent any Javascript from outputting to console, not just yours.
If you look at how the YUI Framework does it, they actually use a regex and generate 3 files from source. One that has the logging -debug, one that has the logging stripped out, just the file name, and a minified version with no logging. Then you can set a global config to say which version you want. I've worked that way in the past and works nicely.
Define your own debugging function that'd be wrapper around console.log or anything else you want and make sure that minifier can easily deduce that it is no-op if you make it empty. After that, once you comment function body out, most minifiers should detect that there's nothing to call or inline and remove references to your function completely.
Here's the example:
(function() {
function debug() {
console.log(arguments)
}
function main() {
debug(123)
alert("This is production code!")
debug(456)
}
main()
})()
I've put it into anonymous function to restrict scope of debug and don't let it be assigned to window - that allows minifier to easily decide if it is necessary or not. When I paste this code to online GCC, I get:
(function(){function a(){console.log(arguments)}a(123);alert("This is production code!");a(456)})();
But once I add // before console.log to make debug empty, GCC compiles it to:
(function(){alert("This is production code!")})();
...removing all traces of debug code completely!
Use Y.log() instead, and then you can use gallery-log-filter to filter the log messages that you want to see printed.
require.js states the way of defining objects inside modules with define([requiremens], object) as best way.
So every page, or other js file, will do require() call and receive modules as parameters.
This works pretty fine, each function/module has own namespace.
The problem is that I have:
// AJAX/Requests.js
define(['UI/Message'],function(Message){
var Requests={
checkResponse:function(response){
//1==ok
//0==error
//2==good message
//3==good message, but still stop
if(response.status==1){
return true;
}
else if(response.status==2){
Message.good(response.message);
return true;
}
else if(response.status==3){
Message.good(response.message);
return false;
}
else{
Message.bad(response.message);
return false;
}
}
};
return Requests;
});
Now the UI/Message is defined in the same way, and it returns object.
But when I edit file with requests, I can't navigate by code, so if I want to edit Message object, the only way is to go and open file the myself and to find function I need, rather than have the IDE jump there for me.
Is there some workaround for pycharm specifically or to require.js in common to solve this issue? When you have a lot of code it becomes a mess to navigate it, which is why I use an IDE in the first place!
And what worse: The editor never knows what functions objects have!
The one possible solution I can see is to not to use enclosed namespaces, and to declare global variable before the define() call, but in this case all objects shall be called like UI_Message, AJAX_Requests. In order to be sure, that I don't have some Message in two different locations....
And I am not sure, if require.js optimizer will use this correctly. Require.js documentation states very clear, to stay away from global variables.
It's a known issue, please star/vote.
From the issue description:
The dojo library switched to AMD's format define() for loading modules
instead of dojo.require(). Previously I was able to use Ctrl+B on
dojo.require('path.to.someJs') to jump to the declaration. This does
not work on the new format define(['path/to/someJs]', ...).
As PyCharm, WebStorm, PhpStorm and IntelliJ IDEA share the same JavaScript plug-in, this issue also applies to the product that you are using. You will continue to observe the described problem until this bug is fixed. Sorry for the inconvenience.
WebStorm (at least 6.0.2) supports code navigation with RequireJs if you're defining your modules with the CommonJs wrapper and use the exports and module arguments:
//foo.js
define(function(require, exports, module) {
//use exports to expose properties for code navigation in other modules
exports.bar = function() {}
});
Apparently, it works even if the module using it doesn't use the CommonJs wrapper format:
define(['./foo'], function(foo) {
foo.bar(); //code navigation works here
}
If the other IDEs use the same JavaScript plug-in as CrazyCoder said, it may work on their newer releases as well.
Where I work, all our JavaScript is run through a compiler before it's deployed for production release. One of the things this JavaScript compiler does (beside do things like minify), is look for lines of code that appear like this, and strip them out of the release versions of our JavaScript:
//#debug
alert("this line of code will not make it into the release build")
//#/debug
I haven't look around much but I have yet to see this //#debug directive used in any of our JavaScript.
What is it's possible usefulness? I fail to see why this could ever be a good idea and think #debug directives (whether in a language like C# or JavaScript) are generally a sign of bad programming.
Was that just a waste of time adding the functionality for //#debug or what?
If you were using a big JavaScript library like YUI that has a logger in it, it could only log debug messages when in debug mode, for performance.
Since it is a proprietary solution, we can only guess the reasons. A lot of browsers provide a console object to log various types of messages such as debug, error, etc.
You could write a custom console object is always disabled in production mode. However, the log statements will still be present, but just in a disabled state.
By having the source go though a compiler such as yours, these statements can be stripped out which will reduce the byte size of the final output.
Think of it as being equivalent to something like this:
// in a header somewhere...
// debug is off by default unless turned on at compile time
#ifndef DEBUG
#define DEBUG 0
#endif
// in your code...
var response = getSomeData({foo:1, bar:2});
#if DEBUG
console.log(response);
#endif
doStuffWith(response);
This kind of thing is perfectly acceptable in compiled languages, so why not in (preprocessed) javascript?
I think it was useful (perhaps extremely useful) back a few years, and was probably the easiest way for a majority of developers to know what was going on in their JavaScript. That was because IDE's and other tools either weren't mature enough or as widespread in their use.
I work primarily in the Microsoft stack (so I am not as familiar with other environments), but with tools like VS2008/VS2010, Fiddler and IE8's (ugh! - years behind FF) dev tools and FF tools like firebug/hammerhead/yslow/etc., peppering alerts in your JavaScript isn't really necessary anymore for debugging. (There's probably a few instances where it's useful - but not nearly as much now.) Able to step through JavaScript, inspect requests/responses, and modify on the fly really makes debugging alert statements almost obsolete.
So, the //#debug was useful - probably not so much now.
I've used following self-made stuf:
// Uncomment to enable debug messages
// var debug = true;
function ShowDebugMessage(message) {
if (debug) {
alert(message);
}
}
So when you've declared variable debug which is set to true - all ShowDebugMessage() calls would call alert() as well. So just use it in a code and forget about in place conditions like ifdef or manual commenting of the debug output lines.
For custom projects without any specific overridden console.
I would recommend using: https://github.com/sunnykgupta/jsLogger , it is authored by me.
Features:
It safely overrides the console.log. Takes care if the console is not available (oh yes, you need to factor that too.)
Stores all logs (even if they are suppressed) for later retrieval.
Handles major console functions like log, warn, error, info.
Is open for modifications and will be updated whenever new suggestions come up.