I am using web-mode for javascript files that contain jsx:
(add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.js[x]?$" . web-mode))
Is there a way to enable go to symbol with web-mode?
I submit critical patches to both web-mode and js2-mode. Currently as a front end architect, I'm developing a big ReactJS project from the scratch.
The simple answer is: helm-etags+ctags or counsel-etags(based on ivy)+ctags
web-mode is good for handling ReactJS files (JSX). Since ctags uses only regular expression, it can work seamlessly with web-mode.
Another solution is rjsx-mode (https://github.com/felipeochoa/rjsx-mode), it inherits from js2-mode and can handle mixed html/javascript perfectly. But certain js2 commands like js2-jump-to-definition
won't work when you try to jump from html tags inside render() method, you got js2-name-node-name accessing a non-js2-name-node
error.
One advantage of use rjsx-mode is you could jump to the symbol using js2-mode's imenu commands, it works out of box. Here is the screenshot of my imenu in a React component,
Whatever major mode you use, you still need ctags and helm-etags (most people use helm, but some guy prefer ivy). For example, now postcss,es6 are popular in ReactJS developers, if a css class name is embedded inside a es6 template string, ctags is the only solution.
Here is my ~/.ctags:
--exclude=*.hg*
--exclude=*.cvs*
--exclude=*.svn*
--exclude=*.git*
--exclude=*compiled*
--exclude=*public_html*
--exclude=*.idea*
--exclude=*bower_components*
--exclude=*images*
--exclude=*.DS_Store*
--exclude=*log*
--exclude=*target*
--exclude=*deployment*
--exclude=*.war
--exclude=*.jar
--exclude=*.class
--exclude=*flymake*
--exclude=*.min.js
--exclude=*.min.css
--exclude=*.pack.js
--exclude=*.log
--exclude=*vender*
--exclude=*.sql
--exclude=*.sass
--exclude=*.ftl
--exclude=tags
--exclude=TAGS
--exclude=GTAGS
--exclude=GPATH
--exclude=*node_modules*
--exclude=GRTAGS
--exclude=*doc*
--exclude=*tmp*
--exclude=.#*
--tag-relative=yes
--recurse=yes
--c-kinds=+defgpstux
--langmap=html:.htm.html.erb.cmp.page.component
--regex-html=/[ \t]+ng-(controller|click|change|show|if|blur|focus|disabled|repeat)[ \t]*=[ \t]*['"][^a-zA-Z0-9$]*([a-zA-Z0-9$]{4,})/\2/o,object/
--langdef=js
--langmap=js:.js.ts
--regex-js=/\.controller[ \t]*\([ \t]*['"]([A-Za-z0-9_$.]+)['"][ \t]*,/\1/,controller/
--regex-js=/\.controllerAs[ \t]*:[ \t]*['"]([A-Za-z0-9_$.]+)['"][ \t]*,/\1/,controller/
--regex-js=/\.filter[ \t]*\([ \t]*['"]([A-Za-z0-9_$.]+)['"][ \t]*,/\1/,filter/
--regex-js=/\.state[ \t]*\([ \t]*['"]([A-Za-z0-9_$.]+)['"][ \t]*,/\1/,state/
--regex-js=/^[ \t]*state:[ \t]*['"]([A-Za-z0-9_$.]+)['"][ \t]*,/\1/,state/
--regex-js=/\.factory[ \t]*\([ \t]*['"]([A-Za-z0-9_$.]+)['"][ \t]*,/\1/,factory/
--regex-js=/\.constant[ \t]*\([ \t]*['"]([A-Za-z0-9_$.]+)['"][ \t]*,/\1/,constant/
--regex-js=/\.service[ \t]*\([ \t]*['"]([A-Za-z0-9_$.]+)['"][ \t]*,/\1/,service/
--regex-js=/\.directive[ \t]*\([ \t]*['"]([A-Za-z0-9_$.]+)['"][ \t]*,/\1/,directive/
--regex-js=/.*[.][\s]*module\(['"]([a-zA-Z0-9_.-]+)['"], *\[([ ,"'a-zA-Z0-9_.-]+)* *\]\)/\1/m,module/
--regex-js=/[.](when\(['"][a-zA-Z0-9_\/]+['"])/\1/r,ngRoute/
--regex-js=/function[ \t]+([A-Za-z0-9_$]+)[ \t]*\([^)]*\)/\1/,function/
--regex-js=/(,|^|\.)[ \t]*([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*[:=][ \t]*function[ \t]*\(/\2/,function/
--regex-js=/^[ \t]*([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*\([^a-zA-Z0-9, ]*\) *\{ *$/\1/,function/
--regex-js=/^[ \t]*([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*=[ \t]*\(?[a-zA-Z0-9, ]*\)?[ \t]*=>[ \t]*\{/\1/,function/
--regex-js=/^[ \t]*export[ \t]+const[ \t]+([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*=/\1/,function/
--langdef=less
--langmap=less:.less
--regex-less=/^[ \t]*\.([A-Za-z0-9_-]+)/\1/c,class,classes/
--regex-less=/^[ \t]*#([A-Za-z0-9_-]+)/\1/i,id,ids/
--regex-less=/^[ \t]*(([A-Za-z0-9_-]+[ \t\n,]+)+)\{/\1/t,tag,tags/
--regex-less=/^[ \t]*@media\s+([A-Za-z0-9_-]+)/\1/m,media,medias/
--langdef=css
--langmap=css:.css
--regex-css=/^[ \t]*(\$[A-Za-z0-9_-]+)[ \t]*:[ \t]*.*;[ \t]*$/\1/c,class/
--regex-css=/^,?[ \t]*#?[ \t]*\.([A-Za-z_][A-Za-z0-9_:"' \t\-]+)[ \t]*[\{,]/\1/c,class/
--regex-css=/^[ \t]*\.([A-Za-z_][A-Za-z0-9_:"' \t\-]+)[ \t]*,/\1/c,class/
--regex-css=/^,?[ \t]*([A-Za-z_][A-Za-z0-9_:()="' \t\-]+)[ \t]*[\{,]/\1/t,tags/
--langdef=scss
--langmap=scss:.scss.sass
--regex-scss=/^[ \t]*@mixin ([A-Za-z0-9_-]+)/\1/m,mixin,mixins/
--regex-scss=/^[ \t]*\$([A-Za-z0-9_-]+)/\1/m,variable,variables/
--regex-scss=/^[ \t]*\.([A-Za-z0-9_-]+)/\1/c,class,classes/
--regex-scss=/^[ \t]*&\.([A-Za-z0-9_-]+)/\1/c,class,classes/
--regex-scss=/^[ \t]*#([A-Za-z0-9_-]+)/#\1/i,id,ids/
--regex-scss=/^[ \t]*(([A-Za-z0-9_-]+[ \t\n,]+)+)\{/\1/t,tag,tags/
--regex-scss=/^[ \t]*@media\s+([A-Za-z0-9_-]+)/\1/m,media,medias/
This answer just covers the basics. Check my blog http://blog.binchen.org/categories/emacs.html and my js setup https://github.com/redguardtoo/emacs.d/blob/master/lisp/init-javascript.el for advanced skills.
for javascript I highly recommend js2-mode. Take a look here https://elpa.gnu.org/packages/js2-mode.html it has function that you are looking for: js2-jump-to-definition
which is by default bound to M-.