-
-
Notifications
You must be signed in to change notification settings - Fork 594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add vue.d.ts and typescript support #94
Conversation
Probably it should replace the space-replacing code for individual regions with a one-shot parsing that gets looked up for each mode as updateCurrentTextDocument is called.
1. Add an implicit `import Vue from 'vue'` and `new Vue(...)` around the default exported object literal. This provides a lot better intellisense than just a bare object literal because the Typescript language server knows that the object will be used by Vue. 2. Resolve other .vue files so that `import other from './other.vue'` provides correct completions. 3. If lang='typescript' is specified, put the TS language service in TS mode: all errors are reported and completions include only symbols that are known to be correct. 4. Also fix a bug in htmlServerMain so that errors are actually reported.
@mhegazy you were interested in this PR, you said. |
Thanks a lot for the PR! Just trying it out on this repo: https://github.com/vuejs/vue-hackernews-2.0, but IntelliSense didn't work:
Just a rough look at the code, it seems I need a properly configured jsconfig/tsconfig. Would you mind adding appropriate config for a sample vue project so it would work as you intended? Either https://github.com/vuejs/vue-hackernews-2.0 or something from here https://github.com/vuejs/vue/tree/dev/examples |
Oh and in vetur's language server I'm using TS 2.2.1. Is is I should install a dev build or build from typescript's master and link locally? |
I'll test with vue-hackernews-2.0, in particular without a tsconfig. I thought the change would work without a tsconfig, but I didn't test that way, so I'm not surprised that it doesn't.
// @filename:Item.vue
export default {
props: ['count'],
data: {
d1: 12
}
// etc ...
}
// @filename:SomeComponent.vue
// (or somethingElse.js)
import Item from './Item.vue'
Item./**/ // should see d1, $data, $parent, etc
Item.props./**/ // should see count The short answer is yes, those should work. But Unfortunately, better |
I tested with lodash and @types/lodash, module resolution works great. Thanks!
Something like that. I'm wondering if there is a way to get the Vue wrapper object's type information on
|
Yes, from typescript's perspective the object from Item.vue is already a Vue object because it was called from I think the Angular guys have done or were thinking about doing something like that for Angular 2. I don't know Angular though, so I'm not sure of the details. You might also do some other clever thing with a virtual TextDocument for each HTML element, which would make the |
One update and one question:
|
I think |
server/src/modes/typescriptMode.ts
Outdated
// (the span of the construct call is the same as the object literal) | ||
const objectLiteral = (exportDefaultObject as ts.ExportAssignment).expression as ts.ObjectLiteralExpression; | ||
const o = <T extends ts.TextRange>(n: T) => ts.setTextRange(n, objectLiteral); | ||
const vue = ts.setTextRange(ts.createIdentifier('Vue'), { pos: objectLiteral.pos, end: objectLiteral.pos + 1 }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind giving o
and n
more descriptive names? I'm not quite familiar with TS compilers but would want to fiddle with this part of code.
It's required to make sure that getXXXAtLocation works correctly, because if the ranges are missing from the synthetic nodes, the language service asserts, and if the ranges are wrong, the language service's AST search gets confused.
I improved the naming, structure and documentation of the AST creation utilities. Let me know if you have other questions about creating or altering ASTs. I'm still investigating the failure to resolve 'vue'. It works fine when I use './node_modules/vue/types/index' instead. My test project may have incorrect settings in tsconfig. |
server/src/modes/javascriptMode.ts
Outdated
return vueDocument.getEmbeddedDocument('typescript'); | ||
} | ||
return vueDocument.getEmbeddedDocument('javascript'); | ||
}); | ||
|
||
let compilerOptions: ts.CompilerOptions = { allowNonTsExtensions: true, allowJs: true, lib: ['lib.es6.d.ts'], target: ts.ScriptTarget.Latest, moduleResolution: ts.ModuleResolutionKind.Classic }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this i would defere to ts.getDefaultCompilerOptions
and just set:
let compilerOptions = ts.getDefaultCompilerOptions();
if (docs[fileName].languageId !== 'typescript') {
copilerOptions.allowJs = true
}
compilerOptions.allowNonTsExtensions = true;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I take that back..
{
"allowJs": docs[fileName].languageId !== 'typescript',
"lib" : ["dom", "esNext"],
"target" : ["esNext"],
"module": ts.ModuleKind.CommonJs
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"esnext" didn't ship as a lib target in 2.2, so I'll use "es2017" for now.
(It was committed Dec 30, but I guess it was part of a PR that got merged later.)
server/src/modes/javascriptMode.ts
Outdated
compilerOptions, | ||
configFile, | ||
undefined, | ||
[{ extension: 'vue', isMixedContent: true }]).fileNames; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should also set compilerOptions to the options from the file. we also need to set compilerOptions.allowNonTsExtensions = true;
all the time to allow .vue
files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
} | ||
|
||
export function createUpdater() { | ||
const clssf = ts.createLanguageServiceSourceFile; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these should be added to the LanguageServiceHost API in TS 2.3, I would also add a comment here with that to allow removing this global function hijacking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added comment where the hijacking happens. This part of the code may remain the same since it's basically the same way that the plugin API allows users to wrap the language service.
server/src/modes/javascriptMode.ts
Outdated
} | ||
return '1'; // default lib an jquery.d.ts are static | ||
else { | ||
return (ts as any).getScriptKindFromFileName(fileName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to expose this on the API for TS 2.3, also add a comment allowing removal of this cast.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added comment. I'll send out a PR for the API change after this.
server/src/modes/javascriptMode.ts
Outdated
|
||
let compilerOptions: ts.CompilerOptions = { allowNonTsExtensions: true, allowJs: true, lib: ['lib.es6.d.ts'], target: ts.ScriptTarget.Latest, moduleResolution: ts.ModuleResolutionKind.Classic }; | ||
let currentTextDocument: TextDocument; | ||
let scriptFileVersion: number = 0; | ||
let versions: ts.MapLike<number> = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use ES6 Map
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
All right, I addressed all of @mhegazy's comments. I think it's ready to go in but I'll spend time testing without a tsconfig now to make sure. |
The failure to resolve |
OK, vue-hackernews-2.0 is now working and gives nice (?) errors when you switch to For both javascript and typescript, the completions are pretty nice, though. I'm chasing down some bugs to do with changing the language back and forth between javascript and typescript. I think this is ready to merge as-is though. I'll send another PR if/when I track down the language-changing bug. |
Actually, the language-change bug repros when opening or closing files. Probably you should wait to merge this until I track it down. |
If you open a .vue file with |
I have the bug almost tracked down -- vue-hackernews works great as long as you don't change one of the files to typescript and then try to open other files :) |
Hm, so this is not an easy fix. The problem is that javascriptmode.ts doesn't know the languageId of files that are not opened yet, but the language service still wants to know whether they contain JavaScript or typescript. There are two basic approaches to fix this:
I think (2) is the right solution, but it's more work. I'll do what I can but my next 48 hours are pretty busy with non-work things, so it may be Monday before I have something working. |
The Typescript language service references files that are not open for editing, and thus don't have entries in the language model cache. Since they don't have entries, there is no way to know whether their script block is Javascript or Typescript. The fix is to load these files and register them with the language model cache.
Turns out the fix is pretty small after all: calling Unfortunately, since I was working from my laptop, a Windows machine, I discovered that path handling is completely broken on Windows. |
Are you looking for this? https://github.com/Microsoft/vscode/blob/master/src/vs/base/common/uri.ts#L126-L145 I'm not against including that as part of the source. I might need it too. However, overall I think it's better to have a fine-tuned default ts/js config internally, as I imagine most Vue users wouldn't bother to specify js/ts config. (Though reading tsconfig if it's present doesn't hurt). |
Yes, I am also looking at it right now and wondering what the public version of it is. I asked @mjbvz as well so I should know pretty soon. Unfortunately, the host also calls |
Looks this package is the right answer: https://github.com/Microsoft/vscode-uri |
TS server and VS Code normalise them in different ways. Standardise by passing everything through vscode-uri
…rsn/vetur into typescript-vue-dts-support
Ok, windows paths should be working now. Both URL encoding and slash normalisation had to be fixed. I'll check once more on my Linux box to make sure I didn't break anything there, but I think it's ready to merge now. |
All right, everything looks fine on Linux as well, so this PR is good to go. |
Thanks a lot! Will include this in 0.6 release. |
@sandersn Do you know @DanielRosenwasser's progress of the Or is is I should just start writing a dts lib that would transform a |
Right now you can try it all out on https://github.com/DanielRosenwasser/typescript-vue-todomvc, but I need to chat with @yyx990803 about it, but I think the earliest we could get it out is Vue 2.4. By the way, right now TypeScript users can't rely on contextually typing the object literal because at compile time, there is no call to In short, TypeScript users still need to wrap their components in calls to |
Working great for me, thanks!
That's fine. I'm wondering if it's possible to modify the source at compile time using a TS loader for webpack. export default class App extends Vue {
...
} with https://github.com/vuejs/vue-class-component so I guess that's fine. Also wondering what's your thoughts on typed props. I see some work towards that in Meanwhile I'll start building support for dynamic IntelliSense for template completion in #145. That seems doable without contextual typing anyway. |
Props is pretty crazy to type because it might come in as an array of strings, or it might come in as an object which you can infer from. Ideally I could have a I'll try it out after next week. Right now we're getting some stuff together for our Build conference. |
Add vue.d.ts and typescript support
import Vue from 'vue'
andnew Vue(...)
around the default exported object literal. This provides a lot better intellisense than just a bare object literal because the Typescript language server knows that the object will be used by Vue.import other from './other.vue'
provides correct info.Also fix a bug in htmlServerMain so that errors are actually reported.Looks like this is already fixed in master.Fixes #75