Emacs: Evaluating Javascript and CSS in Chrome using Skewer Mode

Posted: - Modified: | emacs, geek

I build a lot of quick prototypes, using Javascript and CSS to build little tools on top of the Jive social business platform. Since Javascript syntax errors could prevent the proper loading of the overview page customization screen and require me to reset the overview page through the admin console, my previous Javascript workflow involved copying and pasting code into Google Chrome's developer console. Most of the time, I used narrow-to-region to focus on just the specific script block or set of functions I was working on, and I used js2-mode to handle syntax highlighting and indentation. Once the Javascript was sorted out, I'd widen to get back to the full HTML, JS, and CSS file, using web-mode for indentation.

Copying code between Javascript buffers and the developer console was a bit of a hassle. I'd use C-x h (mark-whole-buffer) to select the buffer, then C-w to copy it, change over to the Chrome window (possibly wading through a number of tabs and windows to find the right one), find the developer console, click in it, paste the code, and run it. My first step was to define a custom function that copied the whole buffer:

(defun sacha/copy-buffer ()
  "Copy buffer contents to kill ring."
  (interactive)
  (kill-new (buffer-substring-no-properties (point-min) (point-max))))
(global-set-key (kbd "C-c w") 'sacha/copy-buffer)

I still had to find the Chrome window and paste the code in, though.

My CSS workflow had its own challenges. I used Inspect Elements to look at CSS properties, and then I modified them on the fly. When I was happy with the rules I added or changed, I wrote the corresponding CSS code in my local file. Because I often ended up modifying several elements, it was hard to remember all the changes I needed to make, apply different sets of changes, or apply the changes after reloading the page. I used Stylish to make some of my changes persistent, but that still involved going back and forth between screens.

Since I'll continue to work on web development over the next year (at least!), I thought I'd invest some time into improving my workflow. I'd seen several demos of Skewer Mode for Emacs, and I'd even given it a try a few times before. I hadn't integrated it into my workflow yet, but it looked like it was definitely worth a try. Skewer allows you to interact with Google Chrome from Emacs. You can send HTML, CSS, and Javascript fragments to your browser.

If you use the included Greasemonkey-compatible script, you can even use this interactive capability on any website. I used the Tampermonkey extension for Google Chrome to run the script. When I tried it on the site I was working on, though, the https/http mismatch resulted in a content security error. It turns out that you need to run chrome --allow-running-insecure-content in order to let Chrome inject HTTPS sites with the scripts from the local HTTP server that Skewer Mode runs inside Emacs. If you had other Chrome sessions open, you'll want to close them before starting up Chrome with that option. Once I sorted that out, it was easy to run skewer-setup, open a JS file, and start sending code to my browser.

I quickly became a fan of how C-c C-k (skewer-load-buffer in JS, skewer-css-eval-buffer in CSS) let me send my buffer to my browser. I narrowed my buffer to the parts I was working on, wrote some tests using console.assert(...), and kept the console visible as I coded. I periodically loaded the buffer to check whether my tests passed. I also liked having a proper file identifier and correct line numbers for errors. (It's amazing how small things matter!)

Then to top it all off, I wanted a function that would prepare the source code for easy pasting into an HTML widget:

<script type="text/javascript">
// filename
</script>

Since Emacs is Emacs, you can do that. =)

(defvar sacha/javascript-test-regexp (concat (regexp-quote "/** Testing **/") "\\(.*\n\\)*")
  "Regular expression matching testing-related code to remove.
See `sacha/copy-javascript-region-or-buffer'.")

(defun sacha/copy-javascript-region-or-buffer (beg end)
  "Copy the active region or the buffer, wrapping it in script tags.
Add a comment with the current filename and skip test-related
code. See `sacha/javascript-test-regexp' to change the way
test-related code is detected."
  (interactive "r")
  (unless (region-active-p)
    (setq beg (point-min) end (point-max)))
  (kill-new
   (concat
    "<script type=\"text/javascript\">\n"
    (if (buffer-file-name) (concat "// " (file-name-nondirectory (buffer-file-name)) "\n") "")
    (replace-regexp-in-string
     sacha/javascript-test-regexp
     ""
     (buffer-substring (point-min) (point-max))
     nil)
    "\n</script>")))

(define-key js2-mode-map (kbd "C-c w") 'sacha/copy-javascript-region-or-buffer)

So now I can fiddle around with Javascript and CSS, send it to my browser with C-c C-k, and then use C-c w to wrap the Javascript in script tags and prepare it for copying.

Emacs!

You can comment with Disqus or you can e-mail me at sacha@sachachua.com.