Introduction
Windows supports the JavaScript in the shell and web server without the need to install node.js or any other server-side JavaScript engine. This article contains the most first steps for creating JavaScript applications for MS Windows Shell and MS Windows web server (IIS).
Background
Reasons to read the article:
Study on how to use MS JavaScript language on the server side in windows. Finally this enables to use one programming language for client side code (in-browser code) and server side code, which makes a great return when developing programs.
Part 1. JavaScript in Windows shell
Hello world
- write the following code in the Notepad.exe and save it in the file hello.js:
var msg = 'Hello world!';
WScript.Echo(msg);
- click the hello.js in the windows explorer. The message "Hello world!" appears.
What is going on:
When you click the script one of the following programs (that are called windows script host) is executed:
CScript.exe or WScript.exe, and the hello.js is sent as an input parameter, e.g.:
WScript.exe hello.js
The script host loads the content of the script and executes it.
Inside the JavaScript code there is a call
WScript.Echo(msg);
This WScript is one of built-in modules that extends the JavaScript functionality in Windows operating systems.
Why you may need the JavaScript without browser?
Windows script host allows to write complex scenarios, such as file and text processing, database updates, service calls, automation and so on.
JavaScript module
Let's write a module in JavaScript.
var myModule = (function() {
var msg = "Hello world!";
var hello = function() {
WScript.Echo(msg);
}
return {
hello: hello
}
})();
myModule.hello();
- save the text in the file module.js and click on it in the windows explorer. The system will show you the "Hello world!" message.
Why you need 7 rows of code instead of 2 ?
The modules make it easier to build complex and extendable applications.
If the example above still looks unfamiliar for you, I suggest making a pause here and google about JavaScript module pattern.
Debugging JavaSript in Windows.
The next sample is a bit more complex, so it is a good time to say about the JavaScript debugging in MS Windows.
You can run the WScript (or CScript) with option //X.
The system will run the script in debugger (if you have installed the Visual Studio Pro).
Visual Studio supports run-bypass, step-over, step-into debugging (keys F5,F10,F11)
With F5 (run-bypass) script will be executed to the end, unless the debugger meets the JavaScript directive "debugger".
Steps:
- make sure you have installed Visual Studio Professional
- in the command shell run the following command
cscript hello.js //X
- in the pop-up window "Visual Studio just-in time debugger" select to debug your script with the the new instance of Visual Studio.
- hit F11 key to debug the script.
- highlith the variables. Left click it and from the drop-down menu select "Add Watch" or "QuickWatch"
The further explanation heavily depends on your ability to debug the script code, to find errors, to evaluate the run-time values in the scripts using the Visual Studio.
Calling external services
Let's write a module that calls the external service, reads the binary data, and saves them in the file, and then calls the windows shell to play this data.
var helloController = (function() {
var serviceURL = "http://translate.google.com/translate_tts?ie=UTF-8&tl=es&q=";;
var msg = "¡Hola%20Mundo!";
var msgFile = "c:\\temp\\Gspeak.mp3";
var hello = function() {
HttpDownload(serviceURL + msg, msgFile);
}
var HttpDownload = function(strURL, strDestLocation) {
var ObjXMLHTTP = WScript.CreateObject("Msxml2.XMLHTTP");
objXMLHTTP.Open("GET", strURL, false);
objXMLHTTP.send()
if (objXMLHTTP.Status == 200) {
var objADOStream = WScript.CreateObject("ADODB.Stream");
objADOStream.Open();
objADOStream.Type = 1;
objADOStream.Write(objXMLHTTP.responseBody);
objADOStream.position = 0;
objADOStream.SaveToFile(strDestLocation, 2);
objADOStream.Close();
var wS = WScript.CreateObject("WScript.Shell");
wS.Run(strDestLocation);
}
else {
Wscript.Echo("Status not good:" + objXMLHTTP.Status);
}
}
return {
hello: hello
}
})();
helloController.hello();
Steps:
- Save this code into the file voice.js
- Create a new file debug.bat with the following text:
cscript voice.js //X
- Click the debug.bat and debug the script in the Visual Studio clicking F11(step-into).
- Find the error in the script and fix it.
If you succeed, the script will call the Google translate service, send the message there, and download the generated voice mp3 file that corresponds to the message, and play it.
(Please note that the Google may change the url. The actual url can be found on their page https://translate.google.com/ with firebug-like tools)
Part 2. JavaScript in the Windows Web Server (IIS)
Now when we can create JavaScript programs for Windows on the server side,
let's create the JavaScript program for IIS (IIS is a built-in web server of the all Windows operating systems).
(Please note - the following steps are NOT intended for the hosted or production environment, but are for local development environment only. Any version of Windows will suffice, even XP SP2)
Steps:
- make sure you have IIS up and running
- enable script debugging in the IIS
- enable ASP scripts (AKA Classic ASP) in the IIS
- in the root folder of the web server (typically c:\inetpub\wwwroot\) create a new file test.asp
Why ".asp"? The reason is that we are going to use a built-in IIS scripting engine that supports JavaScript scenarios for web pages.
- open your test.asp in the Notepad and insert the following code
<%@ language="javascript" %>
<%
var msg = 'Hello world!';
Response.Write(msg);
%>
- save the file
- open the browser and navigate to the page http://localhost/test.asp
The system should show the message "Hello world!"
What is going on here:
When you open the URL your browser sends the GET request to server with this URL.
IIS server locates the folder and file in the folder(in our case the folder in a a root folder) and loads the file into the scripting engine (note that if the IIS can't locate the folder or file, the error handler will be called for 404 Error. We will use this later for nice-formatted URLs). Scripting engine reads the code between pseudo-tags <% and %> and executes the found code. By default the VBScript is used as the scripting language. You can re-define the default scripting language with the IIS settings or with the directive
<%@ language="javascript" %>, which should be the first instruction in the file.
So after the script engine loads the file, the JavaScript code is executed. The variable msg takes the string value. Then the value of this variable is merged with the HTML content of the script file with Response.Write() call. Since there is no HTML content in the script file, the only output is the "Hello world!" message.
Read more about the built-in Response object here:
http://www.w3schools.com/asp/asp_ref_response.asp
Other built-in objects that we are going to use are here:
http://www.w3schools.com/asp/
ASP Response
ASP Request
ASP Application
ASP Session
ASP Server
ASP Error
Debugging:
Put the instruction debugger before the rows of code as shown below:
<%@ language="javascript" %>
<%
debugger;
var msg = 'Hello world!';
Response.Write(msg);
%>
If you set up the IIS script debugging correctly, then your code will be executed in debug mode in the Visual Studio.
Receiving GET values:
Steps:
- replace the code in the test.asp with the following code:
<%@ language="javascript" %>
<%
var controller = Request.QueryString("c");
var action = Request.QueryString("a");
Response.Write("{controller:" + controller);
Response.Write(",");
Response.Write("action:" + action);
Response.Write("}");
%>
- open your browser and navigate to the page http://localhost/test.asp?c=home&a=index
- the IIS will show the page with the following content:
{controller:home,action:index}
Read more about getting values from Request in Classic ASP here:
http://www.w3schools.com/asp/coll_querystring.asp
Structured code:
Let's modify the code above as following:
<%@ language="javascript" %>
<%
debugger;
var Controllers={};
var homeController = (function() {
var msg = "Hello world!";
var hello = function() {
Response.Write(msg);
}
return {
hello: hello
}
})();
Controllers["homeController"] = homeController;
function route(){
var controller = String(Request.QueryString("c")).toLowerCase() + "Controller";
var action = String(Request.QueryString("a")).toLowerCase();
if (typeof Controllers[controller]!="undefined")
if (typeof Controllers[controller][action]!="undefined")
if (typeof Controllers[controller][action]=="function"){
Controllers[controller][action]();
return;
}
Response.Write('error 404. controller or action was not found');
}
route();
%>
Steps:
- save the code
- open the browser and navigate to the URL
http://localhost/test.asp?c=home&a=hello
You should see the message "Hello world!"
What is important here:
1. We created the single entry of the application - a function route().
When this function is called it routes the request (passes the execution) to the appropriate Controller and Action. There is only one Controller - a "homeController", which has one actions - "hello" action in this sample; however you can extend the logic of your application.
Actually, the MVC pattern is applied here to the code.
If the purity of logic due to code separation have not convinced you to use this "unnecessary complication" of your code, please google more about the mvc architectural pattern.
2. Array "Controllers" allows to restrict the code execution. If we don't restrict it then some malicious valid JavaScript may be executed.
3. Local variables of the modules do NOT hold the values between requests. If you want to save something between two requests - use the database or session variables.
Extend modules logic:
Let's extend the homeControler with some new actions as shown below:
<%@ language="javascript" %>
<%
debugger;
var Controllers={};
var homeController = (function() {
var msg = "Hello world!";
var index = function() {
say("Welcome to my page");
};
var hello = function() {
say(msg);
};
var sayhello = function() {
var name = String(Request.QueryString("name"));
if (name=="undefined")
say("hello dude");
else
say("hello " + name + "!");
};
var say = function(txtMsg) {
Response.Write(txtMsg);
};
return {
index: index,
hello: hello,
sayhello:sayhello
}
})();
Controllers["homeController"] = homeController;
function route(){
var controller = String(Request.QueryString("c")).toLowerCase() + "Controller";
var action = String(Request.QueryString("a")).toLowerCase();
if (typeof Controllers[controller]!="undefined")
if (typeof Controllers[controller][action]!="undefined")
if (typeof Controllers[controller][action]=="function"){
Controllers[controller][action]();
return;
}
Response.Write('error 404. controller or action was not found');
}
route();
%>
Try to navigate the following links:
http://localhost/test.asp?c=home&a=index
http://localhost/test.asp?c=home&a=hello
http://localhost/test.asp?c=home&a=sayhello&name=Emmet
Add another controller:
<%@ language="javascript" %>
<%
debugger;
var Controllers={};
var homeController = (function() {
var msg = "Hello world!";
var index = function() {
say("Welcome to my page");
};
var hello = function() {
say(msg);
};
var sayhello = function() {
var name = String(Request.QueryString("name"));
if (name=="undefined") {
var token = String(Request.Cookies("token"));
if (token!="")
say("I remember you! you are " + token)
else
say("hi dude");
}
else
say("hello " + name + "!");
};
var say = function(txtMsg) {
Response.Write(txtMsg);
};
return {
index: index,
hello: hello,
sayhello:sayhello
}
})();
Controllers["homeController"] = homeController;
var securityController = (function() {
var login = function() {
var token = Math.floor(Math.random()*1001);
Response.Cookies("token") = String(token);
Response.Write("{result:true,");
Response.Write("token:" + String(token));
Response.Write("}");
};
var logout = function() {
Response.Cookies("token") ="";
Response.Write("{result:true}");
};
return {
login: login,
logout:logout
}
})();
Controllers["securityController"] = securityController;
function route(){
var controller = String(Request.QueryString("c")).toLowerCase() + "Controller";
var action = String(Request.QueryString("a")).toLowerCase();
if (typeof Controllers[controller]!="undefined")
if (typeof Controllers[controller][action]!="undefined")
if (typeof Controllers[controller][action]=="function"){
Controllers[controller][action]();
return;
}
Response.Write('error 404. controller or action was not found');
}
route();
%>
- Try it with the following URLs:
1 test case:
http://localhost/test5.asp?c=home&a=sayhello
2 test case:
http://localhost/test5.asp?c=security&a=login
http://localhost/test5.asp?c=home&a=sayhello
3 test case:
http://localhost/test5.asp?c=security&a=logout
http://localhost/test5.asp?c=home&a=sayhello
History
All samples are tested with Windows 2003, IIS 6.
This article is created as an attempt to answer the questions of users jaked6803 and kangchoi. I'm sorry guys, not all the questions can be answered because there are so many things to explain. There is a lack of simple tutorials on how to use JavaScript in Windows. I hope this effort will help to start using JavaScript in Windows and make it less painful.