VIM 中编辑 Javascript 保存时使用 ESLint 进行语法检查

文章目录

    为何迫切需要语法检查

    昨天再次因为一个语法错误,交流浪费了不少时间。本以为是小改动,改完没看就发给别人了,没想到还是出错了。

    对于需要编译的语言还好,编译时可以过滤掉语法错误。

    但是对于 js 这种动态语言,特别是单文件,没有打包需求的情况下。
    极易写出有语法错误的代码。之前是使用 gulp 插件实现的 js 语法检查

    对于写 tampermonkey 这种单文件的小功能,我只能在 VIM 里进行配置了。

    全局安装 ESLint

    sudo npm install eslint --global
    

    (不推荐) VIM Syntastic 配置

    Syntastic 是 VIM 的一个语法检查插件。支持通过多种其他工具组合对多种语言进行语法检查。我发现之前的 golang 语法检测也是基于 Syntastic 的。

    Plugin 'vim-syntastic/syntastic'
    
    " ... 其他配置
    
    let g:syntastic_javascript_checkers=['eslint']
    
    " Syntastic has numerous options that can be configured, 
    " and the defaults are not particularly well suitable for new users.
    " 不添加下面的配置,无法看到错误提示
    set statusline+=%#warningmsg#
    set statusline+=%{SyntasticStatuslineFlag()}
    set statusline+=%*
    
    let g:syntastic_always_populate_loc_list = 1
    let g:syntastic_auto_loc_list = 1
    let g:syntastic_check_on_open = 1
    let g:syntastic_check_on_wq = 0
    

    安装

    :PluginInstall
    

    (推荐) VIM ALE 配置

    syntastic 有一个严重的问题,其是阻塞的。在打开大的文件时,会有明显的卡顿现象。
    例如,antd pro 的一个 ts 文件,打开用了 10 秒。在其执行完之前,啥也干不了。这非常的不友好。

    找了一个替代品 ALE,充分利用了 NeoVim 及 Vim8 的异步特性,体验好太多。

    ALE (Asynchronous Lint Engine) is a plugin providing linting (syntax checking and semantic errors) in NeoVim 0.2.0+ and Vim 8 while you edit your text files, and acts as a Vim Language Server Protocol client.

    Plugin 'dense-analysis/ale'
    
    " ALE plugin
    let g:ale_fixers = {
    \   '*': ['remove_trailing_lines', 'trim_whitespace'],
    \   'javascript': ['eslint'],
    \}
    
    " show errors in location list
    let g:ale_open_list = 1
    " Show 5 lines of errors (default: 10)
    let g:ale_list_window_size = 5
    " Set this variable to 1 to fix files when you save them.
    let g:ale_fix_on_save = 1
    let g:ale_lint_on_text_changed = 'never'
    let g:ale_lint_on_insert_leave = 0
    

    https://github.com/dense-analysis/ale

    ESLint 配置文件

    个人 home 目录新建一个配置文件 ~/.eslintrc.js

    module.exports = {
        "env": {
            "browser"      : true,
            "es6"          : true,
            "greasemonkey" : true,
            "jquery"       : true,
            "node"         : true,
        },
        "extends": "eslint:recommended",
        "rules": {
            // enable additional rules
            "linebreak-style": ["error", "unix"],
        },
        "parserOptions": {
            // Required for certain syntax usages
            "ecmaVersion": 2020
        },
    }
    

    配置文件的规范可以参考这里:


    https://eslint.org/docs/user-guide/configuring/configuration-files

    至此,就配置好了。

    打开之前写的 js 文件,一堆错误,惨不忍睹。。。

    Parsing error: Unexpected token

    在语法检查时,发现诡异的错误。例如这行:

    let coursesCount = courses.length;
    

    提示错误内容:

    sunzhongwei.com.user.js|315 col 7 error| Parsing error: Unexpected token coursesCount

    修复方法,增加配置

    "parserOptions": {
        // Required for certain syntax usages
        "ecmaVersion": 2020
    },
    

    “window” is not defined

    由于是给 tampermonkey 开发插件,即 js 文件是运行在浏览器中的,所以 window 对象就被当成了未定义。

    两种修复方法:

    "globals": {
        "document": true,
        "window": true
    }
    

    或:

    "env": {
        "browser": true,
    },
    

    第二种做法更简洁直观,而第一种做法则可以处理更多场景,例如 tampermonkey 里的各种全局变量。
    但实际上 eslint 还内置了 greasemonkey, jquery 这些 env 非常贴心。

    ‘module’ is not defined

    "env": {
        "node": true
    },
    

    不设置 eslint 配置文件的报错信息

    打开 VIM 编辑一个 js 文件,故意写一行语法错误的代码。
    在保存时,并没有看到对应的语法错误提示。

    为了排查,我在命令行里手动运行了一下 eslint,果然报错:

    $ eslint sunzhongwei.com.user.js
    
    Oops! Something went wrong! :(
    
    ESLint: 8.16.0
    
    ESLint couldn't find a configuration file. To set up a configuration file for this project, please run:
    
        npm init @eslint/config
    
    ESLint looked for configuration files in /mnt/d/work/sunzhongwei.com/src/ and its ancestors. If it found none, it then looked in your home directory.
    
    If you think you already have a configuration file or if you need more help, please stop by the ESLint chat room: https://eslint.org/chat/help
    

    看起来是没有对 eslint 进行配置导致的。

    其他的语法检查方案

    • CI: 多人合作时,这个更靠谱一点
    • VSCode: 其 snippet 语法太恶心,无法继承我的 VIM 财产;再就是 IDE 里写代码没有感觉

    TODO

    • [X] 开发环境自动部署配置
    • [X] 是否有快捷键自动跳到下一行错误: :lnext, :lprevious。如果要快速重复 lnext,可以用 @@

    快速重复上个命令
    > The last command entered with ‘:’ can be repeated with @: and further repeats can be done with @@

    lnext 与 lprevious

    l 前缀代表 location。

    VIM location list 与 quickfix list 的区别:

    • The location list is local to the current window so you can have as many location lists as windows.
    • The quickfix list is global so you can’t have more than one available at a time.

    参考

    • https://remarkablemark.org/blog/2016/09/28/vim-syntastic-eslint/

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式