Turn off console.log inside the scope of a function - javascript

I am writing code in modules, and each module can be debugged individually. I want to turn on or off console.log messages on a module level, to focus on just the module I'm working on.
I could have a _debug_ variable for each module set to true or false, and write log messages like
if(_debug_) {
console.log('The is a debug message.');
}
I find this approach a little cumbersome. Can I do better?

You can hijack the console object upon entering the module scope if you want to disable debug statements. Here's a simple way to generate a substitute "console" object:
function noopConsole()
{
var konsol = {};
function noop(){}
for (var k in window.console)
{
konsol[k] = noop;
}
return konsol;
}
Then, at the beginning of the module:
var console = _debug_ ? window.console || noopConsole();
That's it.

You can redefine console in modules in which you want to deactivate logging.
Module without logging:
var console = {log: function(){}}
This assumes that each module is in its own scope.

Related

How to use this in javascript module pattern?

I'm studying module pattern and have a question.
I want to use 'settings' anywhere.
script1.js
var MODULE = (function() {
var t = {};
this.settings = { // this == Window
users: ['john', 'emma']
}
return t;
})()
script2.js
MODULE.dom = function() {
var t = this; // this == MODULE
document.querySelector('p').textContent = t.settings.users[0]; // error
function _say() {
return t.settings.users[1] // error
}
return {
say: _say
}
}
MODULE.DOM = MODULE.dom.call(MODULE)
When use this.settings = {...}, 'this' means Window so code doesn't work.
When use t.settings = {...}, 'this' means MODULE so code works but when write MODULE in dev console, settings is exposed in MODULE variable. Is it ok?
I'd greatly appreciate any help, thank you!
When use t.settings = {...}, 'this' means MODULE so code works
That's the right way to do it.
but when write MODULE in dev console, settings is exposed in MODULE variable. Is it ok?
It's mostly OK.
If you're worried about the client being able to type in the variable name and see the code that gets run - there's no way to avoid that. They can just look at the devtools to see what the network requests are, and what is downloaded - or look at the Sources panel.
If you're worried about running into naming collisions with larger scripts, then - sometimes, libraries deliberately assign themselves to the window to allow other parts of the code to access them. Perhaps you'd like your MODULE to be like this. If not, then you should utilize JavaScript modules instead, which allow for scripts to be imported inside other scripts without polluting the global namespace at all or having any possibility of naming collisions. For example, you could do
// script1.js
export const MODULE = {
settings: {
users: ['john', 'emma'];
}
};
// script2.js
import { MODULE } from './script1.js';
// proceed to use MODULE
And you can do import { MODULE } from './script1.js'; from any script file, not just script2.js.
Personally, I consider the IIFE module pattern in JavaScript to be mostly obsolete nowadays. For any reasonable-sized script, better to write code in separate files and then import and export as needed. (A 1000 line file is somewhat hard to debug and refactor. Ten 100 line files are easier to debug and refactor.)

node "require" hoisted to top outside of script -- loses access to variables from outer function

I'm requiring different files at the top of my main script in node. All my require statements are hoisted to the top. This creates a problem because when the methods within those imported scripts are invoked they do not have access to the function within which they are invoked (Because they are inevitably defined outside those functions due to the hoisting issue). Therefore, I must always pass variables in an options object. Has anyone experiences a similar issue? Is there some sort of standard workaround that people use? Thanks!
function outer(){
//let's pretend we're in a node environment
//this required script will get hoisted to the very top and therefore lose access to the "something" variable!
var common = require('../globals/common.js');
var something = "something";
common.printsomething();//will return "something is not defined"
};
outer();
Hm.
I would assume that it'd ultimately be better to pass 'something' to the printsomething method, like so.
common.printfoo('bar'); //returns 'bar'
Typically, what you're doing there isn't how modules in node works. Yes, breaking up a large program into separate files is an excellent way to organize a project, but I'm afraid that I have to say you're doing it wrong here. In the context of 'outer', you could do:
/*script.js*/
var common = require('../globals/common.js');
function outer(str){
common.printsomething(str);//will return "something"
};
var something = 'something';
outer(something);
/*common.js*/
function printthing(str){
console.log(str);
}
module.exports = {
printsomething: function(str){
printthing(str)
}
}
module.js:
module.exports.print = function (data) {
console.log(data);
}
module.exports.add = function (a, b, callback) {
callback(a + b);
}
main.js
var mymodule = require('module');
module.print('Some data'); //Will print "Some data" in the console
module.add(25, 12, function (result) {
console.log(result); //Will print 37
});
As you can see, in main.js, I do not need to know the content of module.js to wrk. that is the goal of modules: put the hard logic somewhere else, to build better code. Modules like async or fs are huge and complex, but I just have to import them to work with it, and don't need to know how it does it.
While building your own module, think of it as a new library of tools, so that you can reuse it in another project without the need to set specific variables to use them. Imagine the chaos it would be if two module were able to get the content of your var something for unrelated goal!
Modules are self contained, to be reusable. A "de hoisting" of thoses would reduce their efficacity.
EDIT:
If you have a lot of environment variable, you can try a pattern where you set them once inside the module, but you have to make sure to provide a way to interact with them.
module:
var data = {};
function set(key, value) {
data[key] = value;
}
function get(key) {
return data[key];
}
function print(key) {
console.log(data[key]);
}
function add(keyA, keyB) {
return data[keyA] + data[keyB];
}
module.exports = {
set: set,
get: get,
print: print,
add: add
};
main.js
var mymod = require('mymod');
mymod.set('data', 'something');
mymod.set('a', 25);
mymod.set('b', 12);
mymod.print('data'); //Print "something"
var c = mymod.add('a', 'b');
console.log(c); //Print 32

Is it possible to output log/trace in chrome, and remove for production?

Is there a way for me to output logging information in my javascript/jquery code during my development so I can see the log messages in chrome/firefox, and then in production I run some tool on my javascript to minify it and also remove these logging statements.
Is there anything out there currently that can do what I want?
I know that logging is different depending on what browser you are using, is there some kind of a logging plugin that works for both chrome and firefox?
Well this depends a lot on your dev environment. I usually declare a global ENV variable in which I store the app state.
You could make a new module Log in which you will check if the ENV is development. If this is the case then you will call console.log() or what do you prefer for your logging needs. If the ENV var tells the browser that the app is in production mode than in your Log module you do nothing.
Something like this:
(function (window, env){
'use strict';
var logger = {
log: function(what) {
if (env !== 'production') {
console.log(what);
}
}
}
window.myLogger = logger;
}(window, ENV));
And when you will call:
myLogger.log('Hello, I am a logger');
The message will only be logged in development mode.
Hope this helped, let me know.
Cheers!
One simple suggestion, you could overwrite the console.log() method as an empty function for production. This answer here goes over it in more detail.
This is what I do. You have to define a variable that indicates you are in development, and not in production. Output that to your HTML with your pre processor language (PHP.., etc). Some old IE browsers don't have the console object.
You have options when figuring out how to define __DEV__ You can check the host-name with JavaScript and define __DEV__ if it doesn't equal your production domain name, or you could output the JavaScript code on the server side after checking some environment variable.
if(typeof window.console === 'undefined') {
window.console = {
log: function() {}
// etc, define all the methods for which you will call
// while developing.. warn, debug..
}
}
var CONSOLE = window.console.log; // get a reference to the function
window.console.log = function() {
if(typeof window.__DEV__ != 'undefined') {
return CONSOLE.apply(this, arguments);
}
}
This is more efficient then writing something to remove all of the console.* calls in your code. You don't want to have to get used to a new calling construct such as logger.log because that would just waste time. This way you can still use your normal logging conventions, but it won't output in your production environment.
If __DEV__ is not found, then it won't log. By default it won't log. You need to define __DEV__ at the top of your HTML document.
JSFiddle Example

Node.js, Mocha, make globals in closures available

I am currently setting up some mocha tests using Node and in general they work. I now came across a problem I am not able to resolve.
I have a JS file containing the following: MyClass.js
(General CoffeeScript output for class MyClass + constructor: ->)
EDIT: This is browser code, I just want to use Node to test it. (Is that even desirable?)
(function() {
window.MyClass = (function() {
function MyClass() {
// Do something cool here
}
return MyClass;
})();
}).call(this);
I now require MyClass.js in my test file. Once I run it, it directly throws an error
Testfile:
var myclass = require('MyClass.js');
...
describe('MyClass', function() { ... });
Error:
ReferenceError: window is not defined.
So far, I understand why this is happening, window does not exist in Node. But I cannot come up with a solution. I actually do not need the real window object specifically, so I thought mocking it would be enough. But it is not...
var window = {},
myclass = require('myclass.js');
...
describe('MyClass', function() { ... });
This command is also not helping: $ mocha --globals window
I still end up with the same error.
Any idea is much appreciated!
You don't actually want the window object, what you want is the global object. Here is some code that can get it in the browser (in which case it will be the same as 'window') or in node (in which case it will be the same as 'global').
var global = Function('return this')();
Then set things on that rather than on 'window'.
Note: there are other ways of getting the global object, but this has the benefit that it will work inside strict mode code too.
With following code you can use your class-like object in web-browser environment and Node.js without modification. (Sorry, I don't know how to translate that to CoffeeScript)
(function (exports) {
var MyClass = (function() {
function MyClass() {
// Do something cool here
}
return MyClass;
})();
exports(MyClass);
})(function (exported) {
if (typeof module !== 'undefined' && module.exports) {
module.exports = exported;
} else if (typeof window !== 'undefined') {
window.MyClass = exported;
} else {
throw new Error('unknown environment');
}
});
As you already have a scope which doesn't pollute global name-space, you could reduce it to:
(function (exports) {
function MyClass() {
// Do something cool here
}
exports(MyClass);
})(function (exported) {
// see above
});
I'm not an expert in AMD, require.js and other module loaders, but I think it should be easy to extend this pattern to support other environments as well.
Edit
In a comment you said that the above solution is not working when translated back to CoffeeScript. Therefore, I suggest another solution. I haven't tried it but maybe this could be a way to solve your problem:
global.window = {}; // <-- should be visible in your myclass.js
require('myclass.js');
var MyClass = global.window.MyClass;
describe('MyClass', function() {
var my = new MyClass();
...
});
It's a horrible piece of code, but if it works, maybe for testing purposes it's sufficient.
Due to the module loading behaviour of node.js this only works if your require('myclass.js') is the first require of this file in the node process. But in case of testing with Mocha this should be true.
1) What you are looking for is the module.exports to expose things in Node:
http://openmymind.net/2012/2/3/Node-Require-and-Exports/
2) Also you don't need IIFE in Node, you can drop the (function() {...
3) You can alway look at some popular Node repo on Github to see examples, look at the Mocha code since you're using it, you'll learn a thing or two.
Something like jsdom is lighter than PhantomJS and yet provides quite a few things you need to test code that expects to be running with a proper window. I've used it with great success to test code that navigates up and down the DOM tree.
You ask:
This is browser code, I just want to use Node to test it. (Is that even desirable?)
It is very desirable. There's a point at which a solution like jsdom won't cut it but as long as your code is within the limit of what jsdom handles, might as well use it and keep the cost of launching a test environment to the minimum needed.
#hgoebl: As I'm not the OP, I can not add his original CoffeeScript code, but here is my example:
pubsub.coffee:
window.PubSub = window.PubSub || {}
PubSub.subscribe = ( subject, callback )->
now the test:
assert = require "assert"
pubsub = require './pubsub.coffee'
describe "pubsub.http interface", ->
it "should perform a http request", ->
PubSub.subscribe 1, 2
what works for me up to now is:
window.PubSub = window.PubSub || {}
window.PubSub.subscribe = ( subject, callback )->
and the test:
`window = {}`
assert = require "assert"
pubsub = require './pubsub.coffee'
describe "pubsub.http interface", ->
it "should perform a http request", ->
window.PubSub.subscribe 1, 2
The main drawback of the solution, is that I have to explicitly mention the window object in the implementation and the test. User code executed in a browser should be able to omit it.
I now came up with an other solution:
window = window || exports
window.PubSub = window.PubSub || {}
PubSub = PubSub || window.PubSub
PubSub.subscribe = ( subject, callback )->
and then in the test, simply requiring the PubSub namespace:
PubSub = require( './pubsub.coffee' ).PubSub
And finally, the solution from kybernetikos applied looks like this:
global = `Function('return this')()`
global.PubSub = global.PubSub || {}
PubSub.subscribe = ( subject, callback )->
As now, the PubSub namespace is in the global namespace, just a simple require is needed in the file that contains the mocha tests:
require( './pubsub.coffee' )

Closure compiler removes more than what I want to remove

I've followed the advice from this other SO thread to remove console.log() statements from my code.
Unfortunately, now Closure compiler is removing my entire code and not just the console.log() statements.
Might someone explain this? I'm at a loss...
JS file 1
(function(){
/** #const */
LOG = false;
function log() {
return console.log.apply(console, arguments);
}
LOG && log('hello world !');
var foo='bar';
LOG && log("foo"+foo);
})();
JS file 2
(function(){
/** #const */
LOG = false;
function test(){
alert('testing...');
}
var baz='bazzy';
LOG && log("baz"+baz);
})();
Closure compiler step:
$ java -jar compiler-latest/compiler.jar --js j1.js j2.js --js_output_file compiled.js
Result:
(function(){LOG=!1})();(function(){LOG=!1})();
Because the compiler determines that the rest of your code is unreachable.
Both files have a constant LOG set to false and you are not exporting anything (goog.export* or window['...'] = ...).
The code which could get executed has a LOG && in front of it, which means it is not executed.
Therefor nothing can get executed, and thus the compiler removes it all.
Why is function test remoed: nobody calls it, simple as that. Call it in one of your files, and the compiler won't strip it away.
You can (should, actually) define LOG and log only in one file.
For that to work, remove the anonymous function call around your code in every file.
You can tell the compiler to add it back to the compiled code with the commandline option:
--output_wrapper=(function(){ %output% })();
So your two files should look like this:
JS file 1
/** #const */
var LOG = false;
function log() {
return console.log.apply(console, arguments);
}
LOG && log('hello world !');
var foo='bar';
LOG && log("foo"+foo);
JS file 2
function test(){
alert('testing...');
}
var baz='bazzy';
LOG && log("baz"+baz);
// call test, so it a) isnt stripped and b) well, executed :)
test();
Also, you might want to put your global vars and functions into a "namespace" to not pollute the global scope:
// create namespace (which is just a normal object)
var MyNamespace = {};
// create a namespaced function
MyNamespace.test = function() {
alert('test');
}
// call it
MyNamespace.test();

Categories

Resources