Skip to content
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 support for custom file extensions #2035

Merged
merged 11 commits into from Oct 21, 2022

Conversation

cabal95
Copy link
Contributor

@cabal95 cabal95 commented Oct 18, 2022

This would implement custom file extensions for Vue files as mentioned in #1931.

Changes

  1. A new configuration setting called additionalExtensions was added to the vueserver namespace. This is a comma, semicolon or space separated list of filename extensions. An optional period before the extension is allowed. Example setting value: .myvue, vcc; comp .comp2 would allow myvue, vcc, comp and comp2 as extensions in addition to the standard vue extension.
  2. A new property on VueServerInitializationOptions was added called additionalExtensions. This is an array of filename extensions and is used to pass the custom extensions to the language server.
  3. vue-template.ts in the language service was updated to remove any final filename extension rather than trimming off the length of .vue. This allows extensions other than 3 characters to be used.
  4. In order to pass the extensions to the file-vue.ts plugin, I added a new property called pluginOptions to the VueLanguagePlugin type. This is basically an object whose top-level key is the plugin name and whose value is an unknown - specifically it should match whatever custom options the plugin expects.

I do not like the way I had to implement number 4 above. It doesn't feel clean but I haven't been able to come up with better options. I considered making changes inside file-vue.ts to allow for calling a second function that sets the extensions and then returns the original exported function. But that would, I believe, be a breaking change.

@johnsoncodehk If you have ideas on number 4 and how better to achieve this - or if you are fine with the way it was implemented - please let me know.

Notes

As mentioned in the configuration option description, if you change the new configuration value the Volar service must be restarted for it to take affect.

This PR only touches the VSCode related bits. It does not touch any of the other plugins or entry points.

Work In Progress

I am marking this WIP for two reasons:

  1. I don't like how I had to pass configuration values to plugins/file-vue.ts.
  2. I want to do one final test with a large-scale repo once the above item is figured out. I tested on volar-starter repo and it works fine.

# Conflicts:
#	extensions/vscode-vue-language-features/package.json
#	extensions/vscode-vue-language-features/src/common.ts
@johnsoncodehk
Copy link
Member

Thanks for your exploration! I will try to take over your work.

@johnsoncodehk
Copy link
Member

johnsoncodehk commented Oct 18, 2022

Due to you don't have do anything with additionalExtensions in language client, I think we can remove VueServerInitializationOptions.additionalExtensions and VSCode setting, you just need config extensions in tsconfig like:

{
  "vueCompilerOptions": {
    "extensions": [".vue", ".myvue", ".vcc", ".comp", ".comp2"]
  }
}

What do you think?

@cabal95
Copy link
Contributor Author

cabal95 commented Oct 18, 2022

Interesting. I was completely unaware that we could put custom data is tsconfig without it throwing errors. I suppose I am too used to webpack and rollup being far more strict about their config files.

Yes. I think that is a much cleaner way to do it. Would this also mean the language service does not need to be restarted for the changes to take affect?

@johnsoncodehk
Copy link
Member

johnsoncodehk commented Oct 18, 2022

Yes we don't have limitation to vueCompilerOptions, so that third party plugins can define and pass other options they wanted. (For example Vue Macros define shortVmodelPrefix option for plugin codegen: https://github.com/sxzz/unplugin-vue-macros/blob/fa3b4e6a848360e5a26e611a5257dc5e49723b40/packages/volar/src/short-vmodel.ts#L12)

Would this also mean the language service does not need to be restarted for the changes to take affect?

Yes, language server watching tsconfig change to auto reload project.


But after more dug up I think we still need additionalExtensions, because LanguageServerPlugin.extraFileExtensions depend with it. I will add some change requests and then we can merge this.

@cabal95
Copy link
Contributor Author

cabal95 commented Oct 19, 2022

I did a little testing with the branch after your updates against our main repo this evening. Everything seems to work. At least all the features I normally use seem to work:

  • Intellisense in both script and template tags.
  • Go to definition from template when variable exported by template is selected.
  • Auto import when typing opening tag in template.
  • Auto completion of exported variable names when typing them in template, i.e. :msg="val" will suggest auto-completion variable value.
  • Inline warnings when type does not match in template, i.e. trying to pass a numeric variable to a property that expects a string.

There are probably lots of other use-cases that I haven't test (and probably many more features I don't even know exist), but so far everything seems to work.

@johnsoncodehk
Copy link
Member

We should also add file watch support for additional extensions: https://github.com/johnsoncodehk/volar/blob/ac996cd92592a774a768719f9e810b5694d633cb/extensions/vscode-vue-language-features/src/nodeClientMain.ts#L70

But I will resolve it myself after merged this PR, because it's related to #2037. (But if you want to implement in this PR you can go)

@johnsoncodehk
Copy link
Member

I guess additionalExtensions setting need to working with files.associations. If it is, could you also add some explain to extensions/vscode-vue-language-features/README.md for this feature?

@cabal95
Copy link
Contributor Author

cabal95 commented Oct 19, 2022

Yes. I will hopefully work on the readme and the other items tomorrow.

@cabal95
Copy link
Contributor Author

cabal95 commented Oct 20, 2022

All changes should be in.

  • Updated the Volar extension setting to be an array of strings.
  • Setup instructions for custom file extensions has been added to the README.
  • Added support to the file watcher for the additional extensions - though to be honest I don't know what the file watcher triggers so I wasn't able to test that specific item.

@johnsoncodehk
Copy link
Member

We should standardize the format of volar.vueserver.additionalExtensions, with dot ([".ext1", ".ext2"]) or no dot (["ext1", "ext2"])? I'm check if VSCode have similar setting.

@johnsoncodehk
Copy link
Member

We should standardize the format of volar.vueserver.additionalExtensions, with dot ([".ext1", ".ext2"]) or no dot (["ext1", "ext2"])? I'm check if VSCode have similar setting.

I can't found a similar setting, but I prefer extensions no dot for consistent with ts.FileExtensionInfo. Can we change this?

@cabal95
Copy link
Contributor Author

cabal95 commented Oct 20, 2022

Yes, I will update that.

Along that same thought, the new tsconfig.json vueCompilerOptions setting is "extensions" and currently you must specify the custom extension AND the .vue extension. Should I also update that to be named "additionalExtensions" and not require the .vue extension be specified? This would put it in alignment with the volar.vueserver.additionalExtensions setting.

@johnsoncodehk
Copy link
Member

vueCompilerOptions is fine for now, on the contrary with the extensions option we reduced the implemented code for @volar/vue-language-core.

@johnsoncodehk
Copy link
Member

johnsoncodehk commented Oct 20, 2022

We don't need to make vueCompilerOptions consistent with VSCode settings because one is face to user in language client, and the other face to core compiler in low-level implementation.

@cabal95
Copy link
Contributor Author

cabal95 commented Oct 21, 2022

I have updated the README to remove mention of vueCompilerOptions. You are correct that change is not required. volar.vueserver.additionalExtensions are now provided without a period, so just ext.

@johnsoncodehk
Copy link
Member

johnsoncodehk commented Oct 21, 2022

Everything looks good, thank you!

Since you successfully changed language client and vue language core, can you share how complex the code structure is and what is the main difficulty you encountered to you? If you have any ideas for improvement please let me know.

@johnsoncodehk johnsoncodehk merged commit 5ace38e into vuejs:master Oct 21, 2022
@cabal95 cabal95 changed the title WIP: Add support for custom file extensions Add support for custom file extensions Oct 21, 2022
johnsoncodehk added a commit that referenced this pull request Oct 21, 2022
* Add support for custom file extensions to be treated as Vue files.

* refactor: add `VueLanguagePlugin.extensions` instead of pluginOptions

* Changed vueserver.additionalExtensions setting to be a string array.

* Add setup instructions on custom file extensions to vscode-vue-language-features README.

* Added additional extensions to file system wacher.

* chore: double quotes -> single quotes

* Updated additionalExtensions to be extension without period. Updated README to match.

* chore: remove empty extraPlugins param

* feat: add `extensions` option to vue-tsconfig.schema.json

* feat: show reload VSCode when changed additional extensions

Co-authored-by: johnsoncodehk <johnsoncodehk@gmail.com>
@cabal95
Copy link
Contributor Author

cabal95 commented Oct 24, 2022

@johnsoncodehk Thanks for your help with this. Your feedback made this change much better than if I had stuck with my original idea.

To answer your question, I think the main difficulty was figuring out the process of debugging in VS Code. Specifically, understanding how the language server worked and that I had to run the main extension first and then attach to the language server. It took me a while to figure how to do this. Once I did it a couple times and figured out the magic it was pretty easy.

The second most difficult thing was figuring out how all the packages talk to each other and in what order (so to speak) they talk to each other. Because of the IPC stuff just looking at the call stack didn't always give me the answer of "how I got to this breakpoint". I think this is mostly covered by the "High Level System Overview" image in the main README.md file. But that image didn't really make sense until after I started tinkering and understanding the whole multi-process aspect a bit.

Both of those might very well be documented. I admit I didn't look too deeply beyond just the README file. I assumed just setting some breakpoints and looking at the call stack would answer most of my questions. Bad assumption.

The code structure was pretty easy for me to understand. Maybe some more comments on functions describing what they do and why they do it, but I know that is often difficult when time is limited.

And thank you so much for this extension. You have built an amazing thing that is making a huge impact on the Vue community!

@cabal95 cabal95 deleted the feature-additional-extensions branch March 31, 2024 01:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants