Emacs as react native ide

最近又在写 react-native 了,对自己的环境又作了一番配置。记录一下。

web-mode

我主要用的 mode 是 web-mode。这个 mode 简直万能,能处理 html,jsx,js 等。具体配置如下。

(use-package web-mode
  :ensure t
  :config
  (add-to-list 'auto-mode-alist '("\\.html\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.js\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.ejs\\'" . web-mode))
  (setq web-mode-markup-indent-offset 4)
  (setq web-mode-css-indent-offset 4)
  (setq web-mode-code-indent-offset 4)

  (setq web-mode-content-types-alist
        '(("jsx" . ".*\\.js\\'"))
        )
)

主要是那个 web-mode-content-types-alist 的配置,让 web-mode 处理 js 文件的时候,把 <> 代码段识别成 jsx。这样能把缩进处理好。

我还试过 rjsx-mode,这个用起来也可以,基于 js2-mdoe,js2-mode 有的一些用法都支持,并且 flycheck 都不用做多余的配置。但是主要问题是,jsx 的代码缩进有问题。

flycheck

(use-package flycheck
  :ensure t
  :config
  (global-flycheck-mode t)
  (flycheck-add-mode 'javascript-eslint 'web-mode)
)

把 web-mode 的 checker 设置为 javascript-eslint,如果你用别的就设置成对应的。配合用的 .eslintrc 文件如下,可以根据自己需求调整。

{
    "parser": "babel-eslint",
    "env": {
        "es6": true
    },
    "parserOptions": {
        "ecmaVersion": 6,
        "sourceType": "module",
        "ecmaFeatures": {
            "jsx": true
        }
    },
    "plugins": [
        "react"
    ],
    "globals": {
        "require": false,
        "module": false,
        "setInterval": false,
        "clearInterval": false,
        "setTimeout": false,
        "clearTimeout": false,
        "console": false
    },
    "extends": [
        "eslint:recommended",
        "plugin:react/recommended"
    ],
    "rules": {
        // overrides
        "react/prop-types": 0,
        "indent": ["error", 4],
        "react/jsx-indent": ["error", 4],
        "no-trailing-spaces": 2,
        "no-console": 0,
        "comma-dangle": ["error", "never"]
    }
}

补全

(use-package tern
  :ensure t
  :config
  (add-hook 'web-mode-hook (lambda () (tern-mode t)))
  :bind (:map tern-mode-keymap
              ("M-*" . tern-pop-find-definition))
  )

(use-package company-tern
  :ensure t
  :config
  (add-to-list 'company-backends 'company-tern)
  )

我用的是 company 后端用的是 tern。.tern-project 的内容如下,可以根据自己的情况调整下。

{
  "ecmaVersion": 6,
  "libs": [
    "browser"
  ],
  "loadEagerly": [
    "Controller/*.js",
    "Utility/*.js",
    "App.js"
  ],
  "dontLoad": [
    "node_modules/**"
  ],
  "plugins": {
    "node": {},
    "es_modules": {},
    "jsx": {}
  }
}

补全 update

tern 这个东西用了一段时间,发现不是很好用。经常找不到 symbol,以及在 jsx 代码里面无法跳转。后来发现了 tide,简直好用到不行。

tide 是基于 vscode 用的 tsserver 来搞的。这个开始是给 TypeScript 用的,目前也支持普通 js。

(defun setup-tide-mode ()
  (interactive)
  ;; (setq tide-tsserver-process-environment '("TSS_LOG=-level verbose -file /tmp/tss.log"))
  (tide-setup)
  ;;(setq flycheck-check-syntax-automatically '(save mode-enabled))
  (eldoc-mode +1)
  (tide-hl-identifier-mode +1)
  ;; company is an optional dependency. You have to
  ;; install it separately via package-install
  ;; `M-x package-install [ret] company`
  )


(use-package tide
  :ensure t
  :bind (("M-." . tide-jump-to-definition)
         ("M-," . tide-jump-back)
         )

  :config
  (setup-tide-mode)
  ;; aligns annotation to the right hand side
  (setq company-tooltip-align-annotations t)

  ;; formats the buffer before saving
  ;;(add-hook 'before-save-hook 'tide-format-before-save)

  ;; configure javascript-tide checker to run after your default javascript checker
  (flycheck-add-next-checker 'javascript-eslint 'javascript-tide 'append)

  (add-hook 'web-mode-hook
            (lambda ()
              (when (string-equal "js" (file-name-extension buffer-file-name))
                (setup-tide-mode))))
  ;; configure jsx-tide checker to run after your default jsx checker
  (flycheck-add-mode 'javascript-eslint 'web-mode)
  (flycheck-add-next-checker 'javascript-eslint 'jsx-tide 'append)
  )


;; 针对 web-mode 做一个配置
    (add-hook 'web-mode-hook
            (lambda ()
              (set (make-local-variable 'company-backends)
                   '(
                      company-tide
                      ;company-react
                      company-dabbrev-code
                      company-keywords
                      company-files
                      company-yasnippet))))

其实我也没做啥配置,就是官方的那几个就可以。然后还有一个 jsconfig.json 的配置文件如下。

{
    "compilerOptions": {
        "allowJs": true,
        "allowSyntheticDefaultImports": true
    },
    "exclude": [
        "node_modules",
        "ios",
        "android",
        ".git"
    ]
}

这就支持了好多功能,比如光标停留在一个 keyword 上面就会高亮相关的,比如 company 的补全啥的,都很不错。还支持 refactor。