1

When I work with JSX files Emacs automatically switches to js-jsx-mode and acts sluggishly. When I switch it to rjsx-mode it works much faster. So the idea is to override one mode with another, so that rjsx-mode is used instead of js-jsx-mode.

What is the best way to achieve this effect?

phils
  • 48,657
  • 3
  • 76
  • 115
Navidot
  • 732
  • 5
  • 12
  • See the variable `auto-mode-alist`. – NickD Dec 31 '20 at 23:21
  • @NickD thanks but this not quite solve an issue. `auto-mode-alist` binds certain file extensions to certain major modes but in case of JS, JSX and JS files often use the same ".js" extension. I look for smarter solution, that will not only figure out the file is JS file but JSX in particular, as `js-jsx-mode` does in some way. – Navidot Jan 01 '21 at 14:02

1 Answers1

1

Starting from Emacs 27.1, this will depend on whether or not you want C-hv js-jsx-detect-syntax to be taken into account.

When that option is enabled, the default js-mode will inspect the syntax of Javascript files with a plain .js filename extension and decide whether or not to enable JSX support.

When that option is NOT enabled (or if you are using Emacs 26), the decision is purely based on whether or not the filename has a .jsx extension.

If your JSX files will always have the .jsx extension, then you could do this:

;; Use `rjsx-mode' for .jsx files.
;; `auto-mode-alist' is already taken care of if you've
;; installed `rjsx-mode' as a package.
;; (add-to-list 'auto-mode-alist '("\\.jsx\\'" . rjsx-mode))
;; Never check for JSX syntax in regular .js files.
(setq js-jsx-detect-syntax nil)

If there's a chance that the syntax checking is needed, then integrating the two turns out to be a little fiddly, on account of js-mode still being an ancestor of rjsx-mode. Try the following config:

;; Use `rjsx-mode' for JSX files.
;; `auto-mode-alist' is already taken care of if you've
;; installed `rjsx-mode' as a package.
;; (add-to-list 'auto-mode-alist '("\\.jsx\\'" . rjsx-mode))
(advice-add 'js-jsx-enable :override #'my-js-jsx-enable)
(defun my-js-jsx-enable ()
  "Use `rjsx-mode' instead of `js-jsx-mode'."
  (cl-letf (((symbol-function 'js-jsx--detect-and-enable) (lambda () t)))
    (rjsx-mode)))
;; Prevent the `rjsx-mode' ancestor `js-mode' from continuing to check
;; for JSX code.
(add-hook 'rjsx-mode-hook (lambda ()
                            (remove-hook 'after-change-functions
                                         #'js-jsx--detect-after-change t)))

You might check the issue queue for rjsx-mode, and open a new issue if necessary, so that this sort of thing could be addressed by default.

Note that in Emacs 27.1 the actual minor mode js-jsx-mode is just one of multiple possible ways for js-jsx-enable to be called, and consequently there's no benefit to targeting this mode specifically. This was different in earlier versions of Emacs, however it looks as if (a) js-jsx-mode didn't do very much before Emacs 27.1, and (b) it was only triggered for .jsx filenames (which we've already accounted for); so regardless of which Emacs version you're using, I don't believe there's any benefit to messing with js-jsx-mode itself.

phils
  • 48,657
  • 3
  • 76
  • 115
  • `(advice-add 'js-jsx-mode :override #'rjsx-mode)` looks very interesting, I will test it in battle. Thanks! – Navidot Jan 01 '21 at 14:07
  • I tried it but I get an error `File mode specification error: (error Lisp nesting exceeds ‘max-lisp-eval-depth’)` when opening js file. So it end up in `fundamental mode`. – Navidot Jan 01 '21 at 21:46
  • I've now looked at `rsjx-mode` and I see that it derives from `js-mode`, meaning that my initial suggestion introduced some infinite recursion. Try it now. I've changed the approach to supporting the syntax checking feature in 27.1, and also fixed a dumb typo (extra parens) in the `auto-mode-alist` code (but also commented that line out, because `rsjx-mode.el` already updates `auto-mode-alist`, so you shouldn't need to do that. – phils Jan 02 '21 at 00:40
  • Thanks @phils , meanwhile I switched entirely to rjsx for every JS matters - it seams faster. Will see how it handle everything, and in case of problems I will try your solution. – Navidot Jan 02 '21 at 15:43
  • You could also consider using `js2-mode` for regular JS (you already have it -- `rjsx-mode` builds on top of it). I've no idea whether there are advantages to doing that, or if in practice it's fine to use `rjsx-mode` for everything. (My answer is very specific to the standard `js-mode` implementation though.) – phils Jan 02 '21 at 22:28
  • Yes, `rjsx-mode` handle all JS pretty well so far, definitely faster than `js-mode`. I will check your solution on spare time and approve an answer if everything works well. – Navidot Jan 03 '21 at 12:25