Emacs vs. WebStorm for Node.js Development

If you’ve ever worked with me, or read my blog posts, you know I am an Emacs junkie. Emacs is my first and last editor, and I’ll happily spend hours making it just the way I want it.

Lately though, I’ve been doing a lot of Node development and feeling some pain from using my favorite tool. I also recently ended a large Java project where I had been using IntelliJ as my editor, since it was much more advanced than anything Emacs could offer. Since I had been using IntelliJ and some other JetBrains products, I was aware of WebStorm, their IDE geared towards JavaScript development.

I decided to give WebStorm a try and see if it solved any of the pain I had been feeling. After using both tools for JavaScript development for quite a while, I have a good idea of the pros and cons of both Emacs and WebStorm for Node.js development.

Things Both Emacs & WebStorm Do Well

There are a few critical features where both Emacs and WebStorm work just fine. For one, they both do a great job of hooking into external code quality tools like ESLint. Either one can hook into these tools and provide real-time linting and error checking.

Additionally, both tools can provide some deeper analysis of JavaScript code. Emacs has js2-mode, and WebStorm has its own proprietary JavaScript analysis engine. Both of these engines can find issues like functions that don’t return a value, and they can perform trivial refactors like extracting variables.

Lastly, both tools have good support for intelligent auto-completion. WebStorm does this through its own proprietary engine, which, among other things, parses JSDoc annotations and TypeScript descriptor files. Emacs, on the other hand, can be configured to use Tern, which is an open source JavaScript code analyzer that different editors can hook into.

Things WebStorm is Better At / Emacs Can’t Do

While Emacs is great, there are a few things it is just plain worse at or can’t do at all. Critically, all of the most annoying ones are things WebStorm can do, which makes it very appealing.

One of the key features in this category is debugging. The default Node.js debugger is terrible and slow, and WebStorm is the only replacement I’ve found that is worth using. I would go as far as to say the debugger alone makes WebStorm worth having for non-trivial JavaScript development. Emacs has some built-in editor support for debugger integration, but it does not work with the default Node.js debugger. Even if it did, it would likely still be crippled by the very slow performance of the default debugger.

Symbol and definition lookup is another great feature of WebStorm. While Emacs can find symbols and definitions in a single file via Tern, WebStorm can actually inspect your whole project and find a definition, or at least give you a very pruned list of candidates to choose from. This makes navigating through code exponentially faster, and it really reduces the strain of context switching between files.

Testing integration is the last big win for WebStorm. When using the most common JavaScript testing frameworks, Mocha and Jasmine, WebStorm makes it trivial to run individual tests, whole test files, and whole test suites with just a few keyboard shortcuts.

When you combine this last feature with debugging and code navigation between files (or through test failure stack traces), WebStorm becomes an amazing TDD tool. Emacs can be trivially set up to run a whole test suite, but not to run individual tests for any of the common JavaScript testing frameworks. While writing something to do this is entirely possible in Emacs (such an integration exists for Ruby’s RSpec tool), no one, including myself, has invested the time to get it working.

Things Emacs Is Still Better At

Despite all the advantages WebStorm has, there a still a number of things Emacs does better.  One of the simplest is “dumb” auto-completion. I previously mentioned that both Emacs and WebStorm can do some level of intelligent, context-aware completion. The reality of a dynamic language like JavaScript, however, is that many times, there is no contextual completion available because there is too much ambiguity or the code lacks structure.

In these cases, WebStorm just doesn’t offer any completion, leaving you to type everything manually. Emacs does something wonderful in this situation, though. It simply tokenizes all of the words in every buffer of the same type, e.g. every JavaScript buffer, then looks at the characters you have started to type and tries to find a match. Surprisingly, I find that most of the time, if I type around three characters of a word I’ve used before in the project, it will offer me that word as one of the first three to five completion options. This drastically improves my speed, since I only have to type three or four characters of most words.

Another thing Emacs is much better at is Vim emulation. While WebStorm’s Vim emulation is decent, I find frustrating bugs quite often. These include keys not registering, getting into weird states where I appear to be halfway between insert and normal mode, and a weirdly sensitive mouse selection that always seems to put me in visual mode when I don’t want to be. Additionally, some advanced features like macros rarely work right for me, and I have basically given up on using them. It also really irritates me that yanking does not copy things to my system clipboard, which Emacs does by default. I find that whenever I need to do any advanced editing like large find/replacements or macro-driven refactoring, I’m better off just opening the file in Emacs and doing it there.

Lastly, you can pry Magit, the Emacs git source control tool, from my cold dead fingers. I’ll admit that I haven’t even really tried using the VCS management inside of WebStorm because I can’t comprehend anything being better than Magit.

Pain Points Shared by Both Tools

I still have some JavaScript development pain points that neither of these tools (and no tools I am aware of) solve well. A big one is automated refactoring. Automated refactoring in a dynamic language is an incredibly difficult problem. Unfortunately, neither Emacs or WebStorm are able to go much beyond the level of simple variable renames or extractions. This can make refactoring across files a tedious, error-prone process.

In the same vein, both tools are pretty poor at generating code for JavaScript in my experience. Both tools support expanding developer-defined templates, but not much else. WebStorm appears to at least be making strides in this regard. Right now, it can generate a method that you call in code, but only into the same file you are in, and it will often call the method wrong.

My Current Workflow

Currently, my Node development workflow has me using WebStorm most of the time. The fact that it can easily run small subsets of tests, plus debugging and quicker code navigation, all mesh well with my TDD workflow.

I still keep Emacs open to my project, though. I use it to do all of my git work, and also to do complex edits using Vim macros.

What tools are you using for JavaScript development? Is there something better I should check out?

Conversation
  • Aleksey Kladov says:

    >Despite all the advantages WebStorm has, there a still a number of things Emacs does better. One of the simplest is “dumb” auto-completion.

    There is hippie expand in WebStorm! It is even bound to M-/ by default :)

    Docs: https://www.jetbrains.com/webstorm/help/hippie-completion-expanding-words.html

    You might also find this plugin useful: https://plugins.jetbrains.com/plugin/7906?pr=clion

    • Al Scott Al Scott says:

      I didn’t know about hippie expand, I’ll have to check it out. Call me lazy but its a bummer it is not just worked into the automatic (not key driven) completion when there are no intelligent completions :).

  • Rudolf Olah says:

    You’ve forgotten to mention the most important aspect of Emacs: it’s programmable. I’m working on code that’s split between a Rails API and a JavaScript frontend; I’ve written under 100 lines of code so that I can jump between the code and the tests for the code, between the controllers and their templates, and between the serializers and their models. It’s really quite useful to be able to press C-c C-f and jump to the other file that uses/defines the current file or to press C-c C-t and jump to the test/spec file for the current file.

    Admittedly it does takes some time to code up Emacs-Lisp scripts but this is the kind of tool building that is just part of the job and pays dividends over time.

    Refactoring anything in JavaScript is just a plain nightmare and the debugger situation isn’t that good either. It’s sad because other dynamic languages such as Scheme or Smalltalk always had decent refactoring support and decent debuggers. Strange that JS is lagging behind for so many years (especially since in 2007 we could see it growing beyond simple scripts to web apps).

    • Alexander Temerev says:

      Have you tried refactoring in Webstorm? It is not “nightmare”, it just magically works. These guys actually replicate lexer/parser part of Javascript compiler _inside IDE_ and cross-reference the resulting AST with all tokens in config files etc.

      End result: in 98% of cases, if you want to rename something globally in the project / change function signature, it JUST WORKS. And giving things better names is crucial in delivering better code.

      • Al Scott Al Scott says:

        In my experience it is spotty at best for JS. Renaming and extracting variables works really well. Extracting functions sometimes works, but often ends up calling the extracted function the wrong way, e.g. not using “this” to call it even when you extract it into the same class (granted this is an amazingly hard problem in JS). Inlining on the latest version of WebStorm literally does nothing, you click it and the code doesn’t change.

        WebStorm has the best refactoring of any JavaScript IDE I’ve use, but unfortunately that still isn’t very good at all compared to any modern Java IDE for example.

        • Al Scott Al Scott says:

          Sorry for the comment spam, when I try to reply to the comment above yours, it keeps replying to you.

  • Samuel Adam says:

    Have you looked into [Visual Studio Code](https://code.visualstudio.com/)? I think people tend to dismiss it because it’s from MS but they certainly know how to make good IDEs and developer tools.

    And if you are on Windows, give [Node.JS Tools for Visual Studio](https://www.visualstudio.com/en-us/features/node-js-vs.aspx) a try. It’s even better with the full power of Visual Studio behind it.

  • Morgan says:

    If you’ve never used webstorm/idea’s git conflict resolution tool, then you’re working too hard. It’s the most comprehensive, easy-to-use system I’ve ever seen for conflicts, and produces correct code with less chance of errors.

    • Al Scott Al Scott says:

      You should try magit before you say that :)

      • Aleksey Kladov says:

        I do everything except conflict resolution in magit. But for merge conflicts IDEA is imo superior.

        • Al Scott Al Scott says:

          I’m curious what you like better about it? The latest versions of Magit just open up conflicted files with Emacs’s built in smerge mode which I find perfect.

          • Aleksey Kladov says:

            Hm, I actually never reflected on this before. Looks like mostly it’s just inertia and personal preferences :)

            I think I like IDEAs UI here more (gutter marks for changes, sync mouse wheel (sic!) scrolling of three windows), and I also find inspections especially useful, because it’s easy to introduce some silly error during merging.

  • Marijn says:

    > While Emacs can find symbols and definitions in a single file via Tern

    Tern does cross-file lookups too, though this sometimes needs a little configuration (to set up a module-loader plugin). Just do alt-. twice, once to go to the import and once to go to the actual definition.

    • Al Scott Al Scott says:

      I’ve tried that without success before, I may have my configuration wrong. I’ll be sure to try again soon and see if i can have any more luck.

    • Al Scott Al Scott says:

      I’ve been using tern more the last few weeks, and you are right that it can do cross file lookups. Unfortunately, at least for me it only works maybe 50% of the time. Sometimes, I can even get a particular symbol looked up in another file, and then try that exact same symbol again a few minutes later and see it fail. The unfortunate thing is that unless a tool is reliable it really isn’t useful.

      Maybe i’ll see if I can do some open source work on Tern to make it work better in these cases.

  • Pontus Palmenäs says:

    @Rudolf Olah
    > You’ve forgotten to mention the most important aspect of Emacs: it’s programmable.

    You can build your own plugins for WebStorm, and if you make something others may find useful you can share it.

  • Mike Nichols says:

    What about emacs’ ctags/etags for symbol lookup? That’s been around for a while and you have to generate a TAGS file initially, but you can definitely do that in emacs. If you want to do it the brute force way, you can use Projectile’s built in integration with grep/ack/ag and just search for “function doSomething()” to find a function definition, for example.

    I’m surprised that you cite emacs as being unable to doing these things, because I believe emacs’ greatest strength is that you can augment it to do anything you can think of. It does require sometimes significant investment, but you cite the fact that you enjoy customizing emacs and you “spend hours making it the way I want it”. I would encourage you to dive in and write some elisp to add these features yourself to those packages you mention. I fully understand that adding features yourself is not the same as having them baked-in in WebStorm/IntelliJ.

    • Al Scott Al Scott says:

      Of course you can add things to emacs, you can add things to Webstorm too in the form of programmable extensions. I was reviewing features that are available out of the box or with easy to add extensions that anyone can use though.

    • Al Scott Al Scott says:

      Also, CTAGS has been a pain in my experience, and es6 which I am using is not well supported. and you have to set up something to continually regenerate your definitions as you add code.

  • John says:

    Any tips for using Tape for unit testing in Webstorm? Did anybody find any helpful plugins for this? Any success stories about using Tape?

  • Damon says:

    I find it strange that you tried Webstorm and not Atom – considering Atom and all of it’s packages are written in JavaScript (or transpiled to it), you can give it any functionality using the language you’re already using – JS. I find Atom to be great for working with Node.js, and there’s already an existing package for pretty much any functionality you could need, such as a Node.js debugger: https://atom.io/packages/node-debugger

  • Zachary says:

    Hi AL.
    I have always worked on WebStorm and though there are some hardships, I find it quite useful. But after reading this I would love to give it a try to Emacs too.

  • Tarun Elankath says:

    You forgot to mention that WebStorm JS debugger utterly rocks. Does emacs even have JS debugging ?

  • In fact you can use PhpStorm as well which is prices almost the same. Because Phpstorm has all features of WebStorm as well as PHP.

    • Francis Kim says:

      I don’t believe that is true. WebStorm seems to have a lot more JS focused features that PhpStorm does not have.

      • lrg says:

        Like what? Even if not enabled by default, can be downloaded for free.

  • Comments are closed.