bugs-javascript
Posted on Sat 07 March 2015 in Tutorials
When someone says: 'I want a programming language in which I need only say what I wish done', give him a lollipop. ~Alan J. Perlis
The problem
Javascript can be notoriusly difficult to debug if you are coming from a language with tight degugger integration like C/C++ or Java. Even if you are coming from other scripting languages like R or Python. Peering into code running in the browser can be a real pain. Now, I understand that Firefox has firebug and Chrome has its own developer tools but I have never really felt comfortable in them. I think it is becuase there graphical tools cover the entire screen and I mostly develope on a laptop. (Think grad school, not Google.)
Skewer Mode
Skewer mode is an amazing lightweight way to get debugging tools for Javascript into the editor where you actually write the code. Here is a link to the youtube screencast. The screencast has no audio and while it shows the amazing things it can do, I had a very hard time reproducing it.
At the time of this writing it, (three years after its development) it has garnered 10 thousand views but few tutorials or stack overflow answers. There are instructions in the github repo. There is also this answer on emacs.stackexchange.com.
The setup
In order to set up skewer-mode, you technically only need httpd-simple server and js2 mode. However, when you are a beginner you really need auto-commplete and the snippets from YAS (yet another snippet library). This marginally adds to the burden of set-up. However, the major focus of this is set-up so I think it is worth it. I am also including, R and ESS mode (Emacs-Speaks-Statistics). I came to javascript visualizations from static graphs in R. I could have configured IPython as well and there is some benefit to showing the analogue but I have not done it for the time being.
The configuration file (known in the emacs world as .emacs, pronounced dot emacs) is available as a gist. To install packages, I am going to refer you to the excellent tutorial by Xah Lee available here.
Modes
Skewer mode has two ways to operate. Confusingly, these are also
called modes. They are distinct from which functions are made
available in Emacs. This is the primary definition of modes in
Emacs. The first of these is called automatic mode. In the README
file of the skewer mode repo on github, automatic mode is outlined in
Quick Start. If everything is properly configured you can find a
javascript file (using C-x C-f
) and issue the command M-x
run-skewer
. Here the keystroke Control-x is abbreviated C-x
and
the keystroke Alt-x si abbrevieated M-x
. Let's review the
instructions in the README.
- Put this repository directory in your load-path
- Load skewer-mode.el
M-x run-skewer
to attach a browser to Emacs- From a js2-mode buffer with skewer-mode minor mode enabled, send forms to the browser to evaluate
Details on step 1
You want to have all of the requisite packages installed and configured correctly. If you get any error on start up, you have to correct it before attempting to start skewer mode. This is what an error might look like.
Details on step 2
Loading skewer-mode.el should occur in the .emacs file.
(add-to-list 'load-path
"/Users/emisshula/.emacs.d/elpa/skewer-mode-20141215.1525")
(require 'skewer-mode)
(add-hook 'js2-mode-hook 'skewer-mode)
(add-hook 'css-mode-hook 'skewer-css-mode)
(add-hook 'html-mode-hook 'skewer-html-mode)
Details on step 3
For this step you can just follow the instruction:
M-x run-skewer
to attach a browser to Emacs
This won't show anything in the browser but you can interact with the browser through Emacs. What should happen is that your computer will switch focus to the browser and it will open a blank tab with address 127.0.0.1:8080/skewer/demo See the picture of my Safari browser below:
It is not very informative but at least when you see it, you won't be surprised.
Details on step 4
- From a js2-mode buffer with skewer-mode minor mode enabled, send forms to the browser to evaluate
This is what is done in the first 2 minutes of the demo. In order to see if this is working you must pay attention to the bottom of the screen. The second to last line is called the mode-line. It displays information about the file. At a minimum, the file name and what line the cursor. To the right in parentheses are the modes of the file. These modes dictate what functions are available for editing. It will be easier to edit a Python file in python-mode, a C file in c-mode, an elisp file in lisp mode. Well for skewer mode to work, you have to be in js2 major mode and skewer minor mode.
In the picture above in parentheses it says both Javascript-IDE and skewer, this means that we are in the right modes. Unfortunately, js2 is both not the only javascript mode and not the default mode for javascript in Emacs. Regular javascript mode was written before Google made the V8 javascript API available so if your mode line does not have IDE in it you are probably in Javascript mode and skewer mode won't work. When you try to execute a statement, you will get an error that no javascript AST is available. AST stands for Abstract Syntax Tree and the communication to the V8 api is performed only by js2-mode, not the javascript mode.
Well assuming now that you have checked your mode line you can execute the
simple javascript statements. Just put the cursor after the semi-colon and
press C-x C-e
(Control x Control e).
Math.pow(3,14.1);
var x = { foo: "Hello, World" };
x.foo += '!';
Math.floor( Math.random() * 6000);
x.foo;
The first one will print the answer in the last line of Emacs. This is
called the mini-buffer. The definition of x as a key-value pair will
return undefined, but that is OK. The third statement appends an
exclamation point to the value of x.foo
. The fourth statement uses
the javascript Math library. The final statement prints the value of the foo
property of x in the mini-buffer.
If you made this much work. Swagger over to the bar and:
Buy yourself a drink!
More in quick mode
The second demo file in the shows that in skewer-mode you can define a function and apply it
function square(n) {
return n * n;
}
square(14.4);
[1,3,5,7,21].map(square);
In the above code snippet, I follow the video but add the function being applied to an array via the map method. The results are all printed in the mini-buffer. Now in demo3.js, skeeto shows the invocation of the skewer-repl. A repl is Read-Evaluation-Print-Loop also called a shell or console. In R, the repl is called the R console and it is an essential part of buiding programs and performing analysis. In Python, the repl of choice is the extremely popular IPython. Here is an example of a complicated graph drawn using the repl.
# data
set.seed(4566)
data <- rnorm(100)
# layout where the boxplot is at top
nf <- layout(mat = matrix(c(1,2),2,1, byrow=TRUE), height = c(1,3))
par(mar=c(3.1, 3.1, 1.1, 2.1))
boxplot(data, horizontal=TRUE, outline=TRUE,ylim=c(-4,4), frame=F, col = "green1")
hist(data,xlim=c(-4,4), col = "pink")
# layout boxplot is at the bottom
nf <- layout(mat = matrix(c(1,2),2,1, byrow=TRUE), height = c(3,1))
par(mar=c(3.1, 3.1, 1.1, 2.1))
hist(data,xlim=c(-4,4), col = "pink")
boxplot(data, horizontal=TRUE, outline=TRUE,ylim=c(-4,4), frame=F, col = "green1", width = 10)
If we want to examine the first 5 rows of data we can send it to the console as seen here:
Demo3
It is also possible to send data to the javascript repl. Although we have to wrap
it in the skewer.log()
function. The first step is to open the skewer-repl with the command
M-x skewer-repl
. (This is also bound to the keys C-c C-z
.) From a file a
javascript file which we have named demo3.js to match the movie, we place the
cursor immediately after the semi-colon in either statement:
skewer.log(" 5 + 6 =" + (5+6));
skewer.log("Hello, World");
Now instead of writing to the mini-buffer it is writing to the repl, just like we can do in R or Python. Here is a picture.
Manual
We can also insert live changes in the browser for a page we are developing. However, the set up changes as now use manual mode. Again, here are the directions and we will add some detail.
- Load the dependencies
- Load skewer-mode.el
- Start the HTTP server (httpd-start)
- Include "http://localhost:8080/skewer" as a script (see example.html and check your httpd-port)
- Visit the document from your browser
We will break these down step by step.
Details on step 1 and 2
- Load the dependencies
- Load skewer-mode.el
This should happen when start up Emacs if you made the first part work.
Details on step 3
- Start the HTTP server (httpd-start)
It is important to note that you do not use skewer-run
. You start
the server in the directory that you want to serve. Many books on
d3.js recommend this and have you use the python simple server. We are
going to have Emacs the page. The next code snippet is not something
you should use here, it is just an example of another simple web
server that serves a directory to localhost.
python -m SimpleHTTPServer 8000
Although, if you have configured the direcory you want to run in your
.emacs file you can run httpd-start
, I prefer not to rely on the
configuration. An example of the configuration appears below:
(setq httpd-root "/Users/emisshula/Documents/skewerDemo/boid-js")
Instead I prefer to use the command: M-x httpd-serve-directory
so I am
sure that I know what directory is being served and on what port.
This bleeds a little into step 4 but I really like understanding what
my server is doing on my machine. In fact, for debugging one other
command line tool that I find useful is nmap
which can tell you what
ports are open. If you are on unix variant machine (sometimes denote
*nix), you can just take the version from your package manager.
For Mac, use brew:
brew install nmap
For Debian, Ubuntu:
sudo apt-get install nmap
For Windows, download all of CygWin (so you can forget you are even on a Windows box). To check the server has started:
nmap -p 8080 localhost
The results of which will look like:
Starting Nmap 6.47 ( http://nmap.org ) at 2015-03-08 09:30 EDT
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00015s latency).
PORT STATE SERVICE
8080/tcp open http-proxy
Nmap done: 1 IP address (1 host up) scanned in 0.05 seconds
Now stop that server, using httpd-stop
. Then you can clone Chris Wellon's boids-js repo. Try
restarting the server by pointing it at that directory.
Details on step 4
- Include "http://localhost:8080/skewer" as a script (see example.html and check your httpd-port)
Now examine the head of example.html
.
#+BEGIN_SRC md :exports code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"></meta>
<title>Boids</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript" src="http://localhost:8080/skewer"></script>
<script src="boids.js"></script>
</head>
<body style="background: darkgray; text-align: center;">
<canvas id="canvas" width="640" height="640"
style="position: absolute; left: 0; top: 0;">
</canvas>
</body>
</html>
#+END_SRC
I have added a meta tag so that you won't get any inconsequential errors complaining that we have
not specified the charset. The first script tag calls jquerey
, a very popular cross browser
library. Skewer-mode used to depend on jquerey but that dependency has been removed. However,
code that we are running in this example does have the dependency so it can't be removed. The
script's source is on a website ajax.googleapis.com
so we have to be connected to the internet
to run this demo. The prior ones would work on our subway commute. They only relied on our local
files and server. Web pages can load javascript from a variety of different sources. These include
different sites and local files.
The second script is a local script. It is running on our localhost at port 8080. This is why you can't start this with some other local webserver. Emacs knows about both files in the local directory and what to do with skewer. In fact, we are serving both example.html and skewer on the same port. This is very different than if you have ever served a leaflet.js map embeded in an html page. In that case, you serve the page on one port and the map tiles on another.
The third script, is the script that defines the ``boids'' and their motion.
Details on the fifth step
- Visit the document from your browser
In the address bar put http://localhost:8080/example.html
. Split
your screen between your browser and emacs so that you can see both
and little else. To change the size of the birds, go to line 9 of
boids.js
and replace 6 with 2. Now put the cursor after the
semi-colon and press C M x
which is bound to the command
skewer-html-eval-tag
. The size of the ``boids'' should change
instantly.
Evaluating a new file
In demo4.js Chris Wellon's adds a new javascript file which was not loaded when the browser visited
example.html
. He does this to experiment with assigning random colors to the boids. Here he
needs to change the boids.js script to load a random color. He changes line 16 from
ctx.fillStyle = 'blue';
to:
ctx.fillStyle = this.color;
After, you make the change put the cursor after the semi-colon next to this.color;
and evaluate the
tag (C M x
). Don't worry if the page goes blank remember you have not yet defined this.color
.
We define those random colors in demo4.js:
for (var i = 0; i < swarm.boids.length; i++) {
swarm.boids[i].color = '#' + Math.floor( Math.random() * 0xfff);
}
Now demo4.js needs to be loaded into the example.html page. This is
done with C-c C-k
(control-c, control-k).
The boids change colors. Everything else is a variation on this theme. I may add later more later but this should get you debugging javascript.