Ale: tsserver running entire .vue files

Created on 13 Sep 2017  路  31Comments  路  Source: dense-analysis/ale


Hi! First off, thanks for all your work on ale. I love how everything just works out of the box!

I use TypeScript in Vue single file component (.vue) files. tsserver currently reports a bunch of errors because it is checking the entire contents of the file, rather than just the contents of the script tag (as is expected).

Is there any way we could have it only check the contents of that tag? I know that might be out of the scope of this project. I believe other editor integrations run JavaScript/TypeScript linters on the contents of those tags only (unless ESLint is configured with a plugin to parse the template tag contents as well).

I'd be happy to try to take a look at this if someone could point me in the right direction (though I'm not too familiar with VimScript). Thanks!

My ale .vimrc config:

let g:ale_lint_on_text_changed = 'never'
let g:ale_echo_msg_format = '%linter%: %s'
let g:ale_linters = {
  \ 'javascript': ['eslint', 'flow'],
  \ 'typescript': ['eslint', 'tslint', 'tsserver'],
  \ 'vue': ['eslint', 'stylelint', 'tsserver'],
  \ 'php': ['phpcs'],
  \ 'html': []
\ }
let g:ale_linter_aliases = {'vue': ['css', 'javascript', 'typescript']}

Results of :ALEInfo:

 Current Filetype: vue
Available Linters: ['csslint', 'stylelint', 'eslint', 'flow', 'jscs', 'jshint', 'standard', 'xo', 'eslint', 'tslint', 'tsserver', 'typecheck']
  Enabled Linters: ['stylelint', 'eslint', 'tsserver']
 Linter Variables:
 Global Variables:
let g:ale_echo_cursor = 1
let g:ale_echo_msg_error_str = 'Error'
let g:ale_echo_msg_format = '%linter%: %s'
let g:ale_echo_msg_warning_str = 'Warning'
let g:ale_enabled = 1
let g:ale_fix_on_save = 0
let g:ale_fixers = {}
let g:ale_keep_list_window_open = 0
let g:ale_lint_delay = 200
let g:ale_lint_on_enter = 1
let g:ale_lint_on_save = 1
let g:ale_lint_on_text_changed = 'never'
let g:ale_linter_aliases = {'vue': ['css', 'javascript', 'typescript']}
let g:ale_linters = {'typescript': ['eslint', 'tslint', 'tsserver'], 'vue': ['eslint', 'stylelint', 'tsserver'], 'php': ['phpcs'], 'html': [], 'javascript': [
'eslint', 'flow']}
let g:ale_open_list = 0
let g:ale_set_highlights = 1
let g:ale_set_loclist = 1
let g:ale_set_quickfix = 0
let g:ale_set_signs = 1
let g:ale_sign_column_always = 0
let g:ale_sign_error = '>>'
let g:ale_sign_offset = 1000000
let g:ale_sign_warning = '--'
let g:ale_statusline_format = ['%d error(s)', '%d warning(s)', 'OK']
let g:ale_warn_about_trailing_whitespace = 1
  Command History:
(started) ['/usr/local/bin/zsh', '-c', '/Users/cataldo/Work/behance/pro2-ui/node_modules/.bin/stylelint  --stdin-filename ''/Users/cataldo/Work/behance/pro2-u
i/app/js/components/ui/BackSpin.vue'' < ''/var/folders/c0/s_2jpbsj39zg_tbt9tsjm4rh0000gn/T/nvimpnXIsd/2/BackSpin.vue''']
(started) ['/usr/local/bin/zsh', '-c', '''/Users/cataldo/Work/behance/pro2-ui/node_modules/eslint/bin/eslint.js'' -f unix --stdin --stdin-filename ''/Users/ca
taldo/Work/behance/pro2-ui/app/js/components/ui/BackSpin.vue'' < ''/var/folders/c0/s_2jpbsj39zg_tbt9tsjm4rh0000gn/T/nvimpnXIsd/3/BackSpin.vue''']
(started) ['/usr/local/bin/zsh', '-c', '/Users/cataldo/Work/behance/pro2-ui/node_modules/.bin/tsserver']
(finished - exit code 0) ['/usr/local/bin/zsh', '-c', '/Users/cataldo/Work/behance/pro2-ui/node_modules/.bin/stylelint  --stdin-filename ''/Users/cataldo/Work
/behance/pro2-ui/app/js/components/ui/BackSpin.vue'' < ''/var/folders/c0/s_2jpbsj39zg_tbt9tsjm4rh0000gn/T/nvimpnXIsd/6/BackSpin.vue''']
<<<OUTPUT STARTS>>>
Deprecation Warning: 'declaration-block-properties-order'has been deprecated and in 8.0 will be removed. Instead use the community 'stylelint-order' plugin pa
ck. See: https://stylelint.io/user-guide/rules/declaration-block-properties-order/
Deprecation Warning: 'selector-no-empty' has been deprecated and in 8.0 will be removed. See: https://stylelint.io/user-guide/rules/selector-no-empty/
<<<OUTPUT ENDS>>>
(finished - exit code 0) ['/usr/local/bin/zsh', '-c', '''/Users/cataldo/Work/behance/pro2-ui/node_modules/eslint/bin/eslint.js'' -f unix --stdin --stdin-filen
ame ''/Users/cataldo/Work/behance/pro2-ui/app/js/components/ui/BackSpin.vue'' < ''/var/folders/c0/s_2jpbsj39zg_tbt9tsjm4rh0000gn/T/nvimpnXIsd/7/BackSpin.vue''
']
<<<NO OUTPUT RETURNED>>>
enhancement

Most helpful comment

For anyone trying to get this to work with Vue:

I had to install ts-vue-plugin from npm which is this up to date fork: https://github.com/HerringtonDarkholme/vue-ts-plugin

Need to add it to your tsconfig.json:

{
  compilerOptions: {
    "allowSyntheticDefaultImports": true,
    "plugins": [{ "name": "ts-vue-plugin" }]
  }
}

Then, I configured Ale to pick up vue as typescript:

let g:ale_linter_aliases = {'vue': 'typescript'}
let g:ale_linters = {'vue': ['tsserver', 'eslint']}
let g:ale_fixers = {'vue': ['eslint']}

Voila, typechecking for vue files!

All 31 comments

It's probably checking your file as TypeScript code because your filetype is something like typescript.vue. Or is something else reporting errors? Include the output of :ALEInfo like the issue template said.

Sure, sorry about that - I thought it was a feature request, didn't realize it was something that was already sorted out! Updated the original comment with my .vimrc config and the output of :ALEInfo.

I don't know how to handle this, but I'll mark this as an enhancement which can be worked on at some point in the future. The way tsserver works, you send an entire TypeScript file to the server and it gives you some diagnostics. It doesn't expect you to send anything else.

@w0rp Right, makes sense, and that's what I'd expect it to do :) .vue files are a special case (which is why I was wondering if this is maybe out of the scope of this project), but it would be amazing if we could get it working. And I'd be happy to try!

If you can come up with something that'll work, give it a go. :+1:

@kaicataldo any luck with your attempts?

I unfortunately haven't had time to look into this yet. Still on my backlog of things to do! But if someone else can get to it first, please feel free.

Ok, so this becomes a somewhat complex issue as tsc the typescript checker, cannot check individual files and use a config file.

Therefore, the only way I can see to use typescript is to parse the file on the way in, and on the way out (either through vim or some intermediate script).

I'm not an expert here, so maybe @w0rp could provide some insight. Let's say I wrote a python or python3 compatible program to do this. I understand that vim supports Python scripts, but is there a "pluggable" way to provide some kind of middleware or wrapper around either tslint or ale so that this program can filter the input or output?

To clarify, the tsc commandline tool isn't used by ALE, tsserver is. Many things are possible, but only a few things are sane. tsserver isn't designed to parse Vue files. I don't know what other editors check Vue files with tsserver, or how they do it.

Here's a popular Vue plugin for VS Code (it works really well!): https://github.com/vuejs/vetur

Might be able to glean some info from that.

Maybe someone who works with Vue could do something similar to whatever it is that does.

For anyone trying to get this to work with Vue:

I had to install ts-vue-plugin from npm which is this up to date fork: https://github.com/HerringtonDarkholme/vue-ts-plugin

Need to add it to your tsconfig.json:

{
  compilerOptions: {
    "allowSyntheticDefaultImports": true,
    "plugins": [{ "name": "ts-vue-plugin" }]
  }
}

Then, I configured Ale to pick up vue as typescript:

let g:ale_linter_aliases = {'vue': 'typescript'}
let g:ale_linters = {'vue': ['tsserver', 'eslint']}
let g:ale_fixers = {'vue': ['eslint']}

Voila, typechecking for vue files!

I'll close this. That seems like the solution. You could also alias vue to multiple filetypes, if you want to use linters for other filetypes, like html.

Awesome! Thanks for the solution @archSeer.

@archSeer this almost works for me, except it doesn't seem to see my tsconfig.json file in the current dir.

@cj I've come across the same thing I think, it doesn't run with the same tsconfig settings as vue-cli or Vetur would. Possibly related https://github.com/w0rp/ale/issues/1459

I narrowed it down further but forgot by now, I _think_ it had something to do with the linter being ran on a single file instead of the project (with project-wide settings)

@archSeer I see you've used eslint in your example, have you managed to get tslint to work correctly?

@cj Found a temporary patch https://github.com/vuejs/vetur/issues/815

This comment worked for me https://github.com/vuejs/vetur/issues/815#issuecomment-408026341

@dustinblackman I've had tslint working before but switched to eslint because of eslin-plugin-vue.

Hello,
I installed ALE and followed instructions from @archSeer but with no luck.
@lmiller1990 and me tried to understand why in this thread but without success.
The strange thing is that if I put:

let g:ale_linter_aliases = {'vue': 'typescript'}

I get an error like this:

Error detected while processing function ale#events#SaveEvent[13]..ale#Queue[32]..ale#linter#Get[5]..ale#linter#ResolveFiletype[1]..<SNR>93_Get
AliasedFiletype:
line   17:
E715: Dictionary required

All ALEInfo, packages.json, some pices of vimrc, are written in that thread and I do not repeat here just to keep clean this thread.

Any help is appreciated.

https://github.com/posva/vim-vue/blob/master/ftplugin/vue.vim

This plugin is screwing things up again. I'll fix this by allowing b:ale_linter_aliases to be set to a String for buffers.

You should also delete your g:ale_linter_aliases variable, and stick with the default of ['vue', 'typescript'] in that plugin instead.

b:ale_linter_aliases can now be set to a String, in case a default value is taken from a key in g:ale_linter_aliases. You should delete your g:ale_linter_aliases key, and prefer using b:ale_linter_aliases in ftplugin files instead.

Woah, @w0rp is a superstar. Great job on this plugin.

Thank you.
I removed my g:ale_linter_aliases and I let vim-vue set its default b:ale_linter_aliases ['vue', 'javascript']

From ALEInfo now I see

Enabled Linters: ['eslint', 'tsserver']

However I'm continuing linting the whole vue file.

I noticed the ts-vue-plugin folder under node_modules quite empty (at least there is no index.js file as in the repository) maybe this is the problem?

andreav@andreav-pc$ find  node_modules/ts-vue-plugin/
node_modules/ts-vue-plugin/
node_modules/ts-vue-plugin/README.md
node_modules/ts-vue-plugin/LICENSE
node_modules/ts-vue-plugin/package.json

Maybe that's the problem. I got this:

find  node_modules/ts-vue-plugin/
node_modules/ts-vue-plugin/
node_modules/ts-vue-plugin//LICENSE
node_modules/ts-vue-plugin//bin
node_modules/ts-vue-plugin//bin/index.js
node_modules/ts-vue-plugin//README.md
node_modules/ts-vue-plugin//package.json

You seem to be missing the bin dir. Reinstall? Or even rm -rf node_modules and just yarn again.

Yes it works!
Thank you so much @lmiller1990 and @w0rp!

Not exactly the same problem, but related: I'm using ale and ts-vue-plugin and it correctly makes tsserver only lint the script part of my .vue files. So far so good, thanks for this! It also correctly reports type errors when I've done something stupid :-)

The only thing which does not work is resolving imports: I always get a module not found lint error for every component import. For example I have a .vue file which imports another component ...

import Component from "@/components/Component.vue"

... and I get the error ...

2307: Cannot find module '@/components/Component.vue'.

I also tried with relative imports (./ instead of @) and even absolute imports (/path/to/component/Component.vue) to rule out it has something to do with the alias, but it still complains.

The whole project compiles fine though, so this error only happens on linting inside vim with ale and tsserver. Is there something I'm missing? Should I open a new issue for this?

Same here, and I confirm it is just a linting problem.

Deleted - it was a misconfiguration on my side, please ignore it ... in regular .ts files imports work as expected.

I think I found a hint to the solution, it is a problem with ts-vue-plugin. It seems to be that getExternalFiles only returns imported files from .ts files, but not .vue components.

https://github.com/ryo7000/vue-ts-plugin/commit/e4f7c8c932dbcba148f4853e1517b1981ea517cd tries to fix it afaik, and the error goes away. Though with it I don't get a linting for an invalid .vue import, e.g.

import Component from "@/components/Component.vue" // no linting error, :+1:

import NotExistent from "@/components/wrongNameComponent.vue"
// no linting error even though the file does not exist

import NotExistent from "@/something/wrongName" // no .vue component
// correct linting error about module not found

Looks like all .vue imports are considered valid then, not sure exactly why.

Though in the case with an invalid .vue import the project does not compile, so this will be noticed for sure (even though there is no linting error).

I think this definitely better than wrong linting errors.

All in all looks like there's an update needed for ts-vue-plugin and it has nothing to do with ale, sorry for the noise @w0rp

Okay. Someone else might find the information useful.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

garand picture garand  路  4Comments

chauncey-garrett picture chauncey-garrett  路  3Comments

alexlafroscia picture alexlafroscia  路  4Comments

EdmundsEcho picture EdmundsEcho  路  3Comments

ianchanning picture ianchanning  路  3Comments