Skip to content

Latest commit

 

History

History
310 lines (258 loc) · 12.2 KB

ome-javascript.org

File metadata and controls

310 lines (258 loc) · 12.2 KB

Oh My Emacs JavaScript

This is part of oh-my-emacs.

As with python, there’re many choices to do JavaScript programming in Emacs, however, IMHO, none of them are perfect, and easy to use. I’ve spent weeks of spare time to experience various emacs packages for JavaScript, and only figured out a not too bad solution based on js3-mode, nodejs-repl, and tern.

Prerequisites

PackageWindowsUbuntu/Debian/MintArchLinuxFedoraMac OS XMandatory?
nodejsnodejsYes
tern[npm][npm][npm][npm]Yes

El-get packages

PackageStatusDescription
js3-modeRequiredA chimeric fork of js2-mode and js-mode
ternRequiredA great JavaScript code analyzer
nodejs-replRequiredRun Node.js REPL and communicate the process
js-comintDeprecatedRun JavaScript in an inferior process window
js2-modeDeprecatedParse JavaScript to AST using elisp
swank-jsDeprecatedSwank backend for Node.JS and in-browser JavaScript
skewer-modeDeprecatedBrowser JavaScript REPL in Emacs.

js3-mode

As the author said, js3-mode is a “A chimeric fork of js2-mode and js-mode”. The main advantage of js3-mode over js2-mode, IMHO, is its indentation work as I expected. However, some third party packages depend on js2-mode, so this is a trade-off. I’m familiar with the internals of js2-mode, any discussion is welcomed if you prefer js2-mode over js3-mode.

And another small issue is, js3-mode bind the RET key to js3-enter-key, which break smartparens’s newline and indentation. I didn’t figure out a good way to solve this.

(defun ome-js3-mode-setup ()
  (add-hook 'js3-mode-hook
            (lambda ()
              (setq js3-auto-indent-p t
                    js3-curly-indent-offset 0
                    js3-enter-indents-newline t
                    js3-expr-indent-offset 2
                    js3-indent-on-enter-key t
                    js3-lazy-commas t
                    js3-lazy-dots t
                    js3-lazy-operators t
                    js3-paren-indent-offset 2
                    js3-square-indent-offset 4)
              (linum-mode 1)))

            ;; https://github.com/Fuco1/smartparens/issues/239
            ;; (defadvice js3-enter-key (after fix-sp-state activate)
            ;;   (setq sp-last-operation 'sp-self-insert))

            ;; (sp-local-pair 'js3-mode
            ;;                "{"
            ;;                nil
            ;;                :post-handlers
            ;;                '((ome-create-newline-and-enter-sexp js3-enter-key))))
  (add-to-list 'ac-modes 'js3-mode))

(ome-install 'js3-mode)

Tern

Tern is a stand-alone code-analysis engine for JavaScript. It is written in JavaScript, and capable of running both on nodejs and in the browser.

IMHO, tern is really an awesome project, various editors including Emacs provides tern support. The author of tern, Marijin Haverbeke, is really a cool guy, an excellent JavaScript/Lisp hacker. He is also a tech writer, the author of “Eloquent JavaScript”.

Tern is really cool, besides the parser, it even has type inference for JavaScript. And it works both for browser and nodejs in an extensible way. For example, to get completion for both nodejs and jquery, just put a .tern-project file in your js project root directory, the content of this .tern-project file is self-explained, see tern’s manual for tech details.

{
  "libs": [
    "browser",
    "jquery"
  ],
  "plugins": {
    "node": {}
  }
}

It is quite easy to setup and configure tern, the only thing you need to do is sudo npm install -g tern. Enjoy the auto-completion support from tern and auto-complete for JavaScript programming in Emacs.

(defun ome-tern-setup ()
  (when (el-get-package-installed-p 'js2-mode)
    (add-hook 'js2-mode-hook (lambda () (tern-mode t))))
  (when (el-get-package-installed-p 'js3-mode)
    (add-hook 'js3-mode-hook (lambda () (tern-mode t))))
  (setq tern-command (cons (executable-find "tern") '()))
  (eval-after-load 'tern
    '(progn
       (require 'tern-auto-complete)
       (tern-ac-setup))))

(ome-install 'tern)

js2-mode

js2-mode is really an awesome emacs package for JavaScript programming. It is originally written by Steve Yegge. I said it is awesome since it build a JavaScript AST using emacs-lisp, thus there’re even some third party “plugins” for js2-mode:

  • js2-refactor: A JavaScript refactoring library for emacs.
  • ac-js2: Javascript auto-completion in Emacs using Js2-mode’s parser and Skewer-mode.

The only thing I dislike about js2-mode is indentation. That’s why I adopt js3-mode for oh-my-emacs since js3-mode provides more friendly indentation settings and works as expected.

(defun ome-js2-mode-setup ()
  (add-hook 'js2-mode-hook
            (lambda ()
              (setq js2-basic-offset 2)))
  (setq js2-bounce-indent-p t))
  ;; (add-to-list 'auto-mode-alist '("\\.json$" . js2-mode))
  ;; (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode)))

(ome-install 'js2-mode)

swank-js

I really love the SLIME way, I hope that one day every programming language can work the SLIME way. I was really exciting when I first saw swank-js. It is really great and awesome if I can do JavaScript programming in SLIME way.

Unfortunately, things do not always work as expected. There’re some serious show-stop bugs, and it is under little development due to lack of developers. Another problem of swank-js is installation since it depends on SLIME, which is not quite easy to setup and configure, either.

However, I still keep my code here for reference, which records some of my initial setup of swank-js and maybe useful for you, or in future.

To use swank-js, you must have nodejs installed, and then sudo npm install -g swank-js. If you have any problems, I recommend you to upgrade your nodejs to latest version and try again. And to make the following code work, you must setup and configure SLIME and js3-mode correctly.

(defun ome-swank-js-setup ()
  (require 'slime-js)
  (add-hook 'js3-mode-hook
            (lambda ()
              (slime-js-minor-mode 1)))
  (add-hook 'css-mode-hook
            (lambda ()
              (define-key css-mode-map (kbd "M-C-x") 'slime-js-refresh-css)
              (define-key css-mode-map (kbd "C-c C-r") 'slime-js-embed-css))))

;; Wow, swank-js has lots of dependencies.
(when (and (require 'slime nil 'noerror)
           (require 'js3-mode nil 'noerror)
           (executable-find "npm")
           (executable-find "swank-js"))
  (ome-install 'swank-js))

(eval-after-load 'auto-complete
  '(progn
     (add-to-list 'ac-modes 'js-mode)
     (add-to-list 'ac-modes 'js2-mode)
     (add-to-list 'ac-modes 'js3-mode)
     (add-hook 'slime-mode-hook 'set-up-slime-ac)
     (add-hook 'slime-repl-mode-hook 'set-up-slime-ac)))

(eval-after-load 'slime
  '(progn
     (slime-setup '(slime-repl slime-js))))

nodejs-repl

There’re multiple choices to get a JavaScript repl in Emacs. Unfortunately, none of them are perfect and work as expected. I myself prefers nodejs-repl over js-comint since it provides good support for TAB completion. However, it lacks some interactive commands, which need to be improved.

(defun ome-nodejs-repl-setup ())

(ome-install 'nodejs-repl)

js-comint

js-comint.el is a comint mode for emacs which allows you to run a compatible javascript repl in Emacs, it is an alternative to nodejs-repl. Actually, Nodejs is not born when js-comint was first released.

(defun ome-js-comint-setup ()
  (setq inferior-js-program-command "node")
  (add-hook 'js3-mode-hook
            '(lambda ()
               (local-set-key (kbd "C-x C-e")
                              'js-send-last-sexp)
               (local-set-key (kbd "C-M-x")
                              'js-send-last-sexp-and-go)
               (local-set-key (kbd "C-c b")
                              'js-send-buffer)
               (local-set-key (kbd "C-c C-b")
                              'js-send-buffer-and-go)
               (local-set-key (kbd "C-c l")
                              'js-load-file-and-go)))
  (setenv "NODE_NO_READLINE" "1")
  (setq inferior-js-mode-hook
        (lambda ()
          ;; We like nice colors
          (ansi-color-for-comint-mode-on))))

(ome-install 'js-comint)

Skewer-mode

What’s wrong with swank-js?

Skewer provides nearly the same functionality as swank-js, a JavaScript back-end to SLIME. At a glance my extension seems redundant.

The problem with swank-js is the complicated setup. It requires a cooperating Node.js server, a particular version of SLIME, and a lot of patience. I could never get it working, and if I did I wouldn’t want to have to do all that setup again on another computer. In contrast, Skewer is just another Emacs package, no special setup needed. Thanks to package.el installing and using it should be no more difficult than installing any other package.

Most importantly, with Skewer I can capture the setup in my .emacs.d repository where it will automatically work across any operating system, so long as it has Emacs installed.

– The author of skewer-mode

To tell the truth, I have installed skewer-mode but didn’t dive into it since I want to work with nodejs, while skewer-mode didn’t support nodejs yet. The code is kept here just for reference.

(defun ome-skewer-mode-setup ()
  (add-hook 'js2-mode-hook 'skewer-mode)
  (add-hook 'css-mode-hook 'skewer-css-mode)
  (add-hook 'html-mode-hook 'skewer-html-mode))

(ome-install 'skewer-mode)