21

A lot of projects I work on install eslint as a dev dependency, with a custom set of eslint plugins. Right now, flycheck uses the globally installed version of eslint rather than the version of eslint installed with each project.

I would like to make flycheck point to node_modules/eslint/bin/eslint.js instead. The full path should depend on the path of the current buffer's file so I can be working on multiple projects at the same time with each buffer using a potentially different eslint executable.

Is this possible? Any suggestions for how I would go about doing this?

31

You can programmatically change flycheck-javascript-eslint-executable, e.g.

(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/.bin/eslint"
                                 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)

This code looks for a node_modules directory in any parent of the buffer's directory and configures Flycheck to use an eslint executable from that directory if any exists.

  • I wish my emacs-fu were this good. Thanks for the answer! – pcardune Apr 4 '16 at 16:35
  • 1
    If you have global-flycheck-mode set, then I recommend (and eslint (file-executable-p eslint)) I was encountering errors otherwise trying to, i.e. edit my .emacs file – Jason Dufair Jun 14 '16 at 15:31
  • Here's what you can do if you need an inline hook (and avoid adding custom functions) : emacs-fu.blogspot.in/2008/12/hooks.html – Shivek Khurana Dec 6 '17 at 16:12
  • security note: only open files in trusted folders/projects; you will auto-execute any malicions eslint binary – maxy May 14 '18 at 9:21
  • 2
    I would use the path "node_modules/.bin/eslint", just in case eslint ever changes their directory structure. – Cody Reichert Jun 25 '18 at 3:01
3

I don't have enough reputation to comment on the accepted solution. But I made a variation of it, that works well with nested packages (for example using lerna). This is the exact same code, however it looks up the parent node_modules folder recursively until it finds an eslint binary, and uses it. This way, you can have a lerna project have only one eslint configuration, shared between all sub-packages.

(defun my/use-eslint-from-node-modules ()
  (let ((root (locate-dominating-file
               (or (buffer-file-name) default-directory)
               (lambda (dir)
                 (let ((eslint (expand-file-name "node_modules/eslint/bin/eslint.js" dir)))
                  (and eslint (file-executable-p eslint)))))))
    (when root
      (let ((eslint (expand-file-name "node_modules/eslint/bin/eslint.js" root)))
        (setq-local flycheck-javascript-eslint-executable eslint)))))
(add-hook 'flycheck-mode-hook #'my/use-eslint-from-node-modules)
0

I'm on windows and this wasn't working for me, I think the file-executable-p or perhaps the flycheck internals were failing to locate the correct file. As when its working it is pointing to the .cmd file and not the .js file.

I found a comment in flycheck-eslint does not use version of eslint installed in JavaScript project and their blog post to use directory variables instead.

In the root directory of the project create a file .dir-locals.el

((nil . ((eval . (progn
                   (add-to-list 'exec-path (concat (locate-dominating-file default-directory ".dir-locals.el") "node_modules/.bin/")))))))

Now when I visit the javascript file flycheck-verify-setup correctly finds the file <dir>/node_modules/.bin/eslint.cmd

0

My previous solution was a pain to get working across different projects.

I've modified the accepted answer to hard code windows stupidities.

(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/.bin/eslint.cmd"
                                        root))))
    (when (and eslint (file-exists-p eslint))
      (setq-local flycheck-javascript-eslint-executable eslint))))
0

Here's a solution that combines Bae's and lunaryorn's answers using a dir-locals.el file in the root directory of the project (or, more specifically, in the directory that contains the node_modules/ folder where the eslint binary lives). Create said dir-locals.el file with the following content.

((js2-mode
   (flycheck-checker . javascript-eslint)
   (eval . (setq-local flycheck-javascript-eslint-executable
             (concat (locate-dominating-file default-directory
                       ".dir-locals.el") "node_modules/.bin/eslint")))))

Here I'm assuming you are using the js2-mode emacs major mode to edit javascript files. If that's not the case, change that line accordingly. The second line of the file makes the javascript-eslint syntax checker the only one to be used within this project. The third line sets the variable flycheck-javascript-eslint-executable to <root-dir>/node_modules/.bin/eslint. In this way we don't modify emacs' exec-path.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.