Configuring emacs to use eslint and babel with flycheck for javascript and React.js JSX
ES6 and JSX are awesome, but because they are relatively new, there is little documentation on how to set them up with your environment. After spending time tracking down all the pieces and configuring for use with emacs, I created this article to help those that will follow. It enables realtime linting of JS and JSX files in emacs using eslint and babel.
Meta Information
- Author: Jeff Barczewski
- Published: April 2nd, 2015
- Updated: January 14, 2017
- Tags: reactjs, javascript,emacs
- Versions: GNU Emacs 24.4.51.2, Aquamacs 3.2, ESLint v0.17.1, Babel-eslint 2.0.2
Summary
My preferred weapon of choice for editing code for the last 11 years has been Emacs. Normally it already has support for all the types of files I edit, however since React.js introduced JSX, emacs needed some additional setup to get everything to play nicely. The config below should work well with any modern version of Emacs 24.4+ or Aquamacs 3.2+.
I will be using the following for js, and jsx editing
- flycheck - emacs realtime lint runner
- eslint - pluggable linter for js and jsx
- eslint-plugin-react - React.js specific linting rules for eslint
- babel-eslint to enable ES6 and jsx parsing for eslint
- web-mode for jsx files
- js2-mode for js and ES6+ files
- exec-path-from-shell which can fix issues with emacs exec path not matching your shell (OS X)
Once you complete the setup, you will have automatic realtime syntax checking right in Emacs for js and jsx files.
Emacs configuration for ESLint and JSX
Install eslint and babel
You will need node.js (or io.js), eslint, and babel-eslint installed on your system.
- To install node.js see https://nodejs.org/
- To install io.js see https://iojs.org/en/index.html
Installing eslint and babel-eslint just use npm
npm install -g eslint babel-eslint eslint-plugin-react
eslint -v # view version and confirm that its in your path
Note: These examples are for Babel 5. Babel version 6 changed its configuration considerably, so if you are using that make sure it is compatible with your version of babel-eslint and adjust your configuration according to the Babel website. You will need to include some preset plugins.
Configure eslint
Create a default ~/.eslintrc
and/or a local .eslintrc
to customize your eslint configuration. It is a json file, so edit it in emacs and create something like this.
The key thing to add is the parser
which is set to babel-eslint and also ecmaFeatures
should have the jsx
set true. Also if you would like to use the eslint-plugin-react features, add "plugins": ["react"]
as well. eslint-plugin-react helps you tune eslint to your needs while using jsx.
There are additional jsx specific rules the eslint-plugin-react enables. See the full list at the eslint-plugin-react README.
Here is my current .eslintrc
(including all my rules and feature customizations). Adjust for your own use.
{
"parser": "babel-eslint",
"plugins": [ "react" ],
"env": {
"browser": true,
"es6": true,
"node": true
},
"ecmaFeatures": {
"arrowFunctions": true,
"blockBindings": true,
"classes": true,
"defaultParams": true,
"destructuring": true,
"forOf": true,
"generators": true,
"modules": true,
"spread": true,
"templateStrings": true,
"jsx": true
},
"rules": {
"consistent-return": [0],
"key-spacing": [0],
"quotes": [0],
"new-cap": [0],
"no-multi-spaces": [0],
"no-shadow": [0],
"no-unused-vars": [1],
"no-use-before-define": [2, "nofunc"],
"react/jsx-no-undef": 1,
"react/jsx-uses-react": 1,
"react/jsx-uses-vars": 1
}
}
Install emacs packages
Emacs 24 has a nice package management system bundled in it, so I would recommend using that to install. This system makes it easy to find new packages and also to upgrade them later. It also takes care of getting all the dependencies you need.
Xah Lee has a great tutorial about the emacs package system and its use, so check it out if you need information on that.
To list the available packages
M-x list-packages
Scroll/search down to find the package you want to install, type i
to mark for installation and x
to execute the installation of all marked packages. Note that the package list is sorted by status initially, so new or updated packages are listed as available
, then installed packages are next with status installed
.
I am using these packages for my web app development with javascript, and JSX.
Emacs packages to install
- flycheck - modern lint runner which has support for 30 programming languages with more than 60 different syntax checking tools. Replaces flymake. This will run our eslint command in background for us.
- web-mode - mode which can handle mixed js and html like jsx
- js2-mode - nice js editing mode which recognizes modern ES6+ features
- json-mode - upgraded json mode (optional)
- exec-path-from-shell - updates emacs exec path from your shell (optional) On OS X, when I was having issues getting emacs exec path setup correctly I installed this and it fixed my issues. I did not need it on other OS’s so I only run it conditionally. See below.
Once you have installed them you should see something like this in your *Packages*
buffer.
Package | Version | Status | Description |
---|---|---|---|
flycheck | 20150401…. | installed | Modern on-the-fly syntax checking for GNU Emacs |
js2-mode | 20150202 | installed | Improved JavaScript editing mode |
json-mode | 20141105.138 | installed | Major mode for editing JSON files |
web-mode | 20150401.252 | installed | major mode for editing web templates |
exec-path-from-shell | 20141212.846 | installed | Get environment variables such as $PATH from the shell |
Configuring Emacs
We need to:
- register
*.jsx
files with web-mode - require flycheck so it will be started
- turn on flycheck globally
- disable jshint checker, so eslint will be used
- register eslint with flycheck web-mode
- disable json checking (just my preference to not use it)
- make sure emacs exec path finds eslint (optionally install and run exec-path-from-shell)
For steps 4 and 6, you can optionally use Emacs customize variable to add javascript-jshint
and json-jsonlist
to the flycheck-disabled-checkers
list. I just use code to customize those variables so that I can keep all my config in one place.
Step 7 only became an issue for me on OS X. Emacs needs to be able to find eslint on its exec-path which it should get from the shell. You can see your exec path by executing this command in emacs.
M-x describe
exec-path
If eslint -v
works from your shell but emacs isn’t finding it (the exec-path is probably wrong), then installing exec-path-from-shell and enabling it should fix the issue for you. I only need it for OS X so I have it conditionally run, see below.
In your .emacs
file, add the following
;; use web-mode for .jsx files
(add-to-list 'auto-mode-alist '("\\.jsx$" . web-mode))
;; http://www.flycheck.org/manual/latest/index.html
(require 'flycheck)
;; turn on flychecking globally
(add-hook 'after-init-hook #'global-flycheck-mode)
;; disable jshint since we prefer eslint checking
(setq-default flycheck-disabled-checkers
(append flycheck-disabled-checkers
'(javascript-jshint)))
;; use eslint with web-mode for jsx files
(flycheck-add-mode 'javascript-eslint 'web-mode)
;; customize flycheck temp file prefix
(setq-default flycheck-temp-prefix ".flycheck")
;; disable json-jsonlist checking for json files
(setq-default flycheck-disabled-checkers
(append flycheck-disabled-checkers
'(json-jsonlist)))
;; https://github.com/purcell/exec-path-from-shell
;; only need exec-path-from-shell on OSX
;; this hopefully sets up path and other vars better
(when (memq window-system '(mac ns))
(exec-path-from-shell-initialize))
Customizing flycheck to use local node_modules eslint if exists
If you want flycheck to prefer a local eslint in your node_modules directory rather than the default, you can add this hook. The main reason you might watn this is if you have different versions of eslint, eslint-plugins, and eslint config then you would want to run the version that your local project uses rather than the default you use globally otherwise you could get lots of errors for incompatible versions.
I got this solution from stack overflow here.
;; use local eslint from node_modules before global
;; http://emacs.stackexchange.com/questions/21205/flycheck-with-file-relative-eslint-executable
(defun my/use-eslint-from-node-modules ()
(let* ((root (locate-dominating-file
(or (buffer-file-name) default-directory)
"node_modules"))
(eslint (and root
(expand-file-name "node_modules/eslint/bin/eslint.js"
root))))
(when (and eslint (file-executable-p eslint))
(setq-local flycheck-javascript-eslint-executable eslint))))
(add-hook 'flycheck-mode-hook #'my/use-eslint-from-node-modules)
Customizing indent
To adjust the indent in web-mode to my preference of two spaces I also added the following code.
;; adjust indents for web-mode to 2 spaces
(defun my-web-mode-hook ()
"Hooks for Web mode. Adjust indents"
;;; http://web-mode.org/
(setq web-mode-markup-indent-offset 2)
(setq web-mode-css-indent-offset 2)
(setq web-mode-code-indent-offset 2))
(add-hook 'web-mode-hook 'my-web-mode-hook)
Improving the JSX syntax-hightlighting in web-mode
Patrick @halbtuerke suggested this JSX syntax highlighting adjustment.
;; for better jsx syntax-highlighting in web-mode
;; - courtesy of Patrick @halbtuerke
(defadvice web-mode-highlight-part (around tweak-jsx activate)
(if (equal web-mode-content-type "jsx")
(let ((web-mode-enable-part-face nil))
ad-do-it)
ad-do-it))
Flycheck usage
Read the comprehensive flycheck manual for information on how to use and configure.
Flycheck is running by default so you will get feedback as you edit.
To use flycheck features, you start by entering C-c
, then !
, followed by the command key. You may also map these to your own keys as you see fit.
C-c ! l
- see full list of errors in a buffer. DetailsC-c ! n
- next errorC-c ! p
- previous error
Resources
- ESLint - The pluggable linting utility for JavaScript and JSX by Nicholas C. Zakas.
- eslint-plugin-react - React.js specific linting rules for eslint
- Emacs package system - Xah Lee Emacs package system tutorial
- Lint like it’s 2015 - Dan Abramov’s Lint like it’s 2015 article describing eslint and babel
- Flycheck - Flycheck features and demo animation
- Flycheck manual - user guide for flycheck