Louis' Blog

All about software development for the web

Support TypeScript with Vue SFC in Sublime Text

I recently discovered it’s possible to use language servers to enable typescript linting in Vue Single File Components using Sublime Text. This always worked out of the box with .js files, but never for .vue files. The purpose of this post is to document the steps I took to get everything working.

First, you’re going to need to install Sublime Text, and install the LSP plugin.

Then, install vue-language-server:

npm install -g vue-language-server

To enable vue language server in Sublime Text, go to Preferences -> Package Settings -> LSP -> Settings. In the LSP.sublime-settings – User, enter the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
{
"clients":
{
"vue-ls":
{
"command":
[
"vls"
],
"enabled": true,
"languageId": "vue",
"scopes":
[
"text.html.vue"
],
"syntaxes":
[
"Packages/Vue Syntax Highlight/Vue Component.sublime-syntax"
],
"initializationOptions": {
"config": {
"vetur": {
"useWorkspaceDependencies": false,
"completion": {
"autoImport": false,
"useScaffoldSnippets": true,
"tagCasing": "kebab"
},
"grammar": {
"customBlocks": {
"docs": "md",
"i18n": "json"
}
},
"validation": {
"template": true,
"style": true,
"script": true
},
"format": {
"enable": true,
"options": {
"tabSize": 2,
"useTabs": false
},
"defaultFormatter": {
"css": "prettier",
"postcss": "prettier",
"scss": "prettier",
"less": "prettier",
"stylus": "prettier",
"js": "prettier",
"ts": "prettier"
},
"defaultFormatterOptions": {
"js-beautify-html": {
"wrap_attributes": "force-expand-multiline"
},
"prettyhtml": {
"printWidth": 100,
"singleQuote": false,
"wrapAttributes": false,
"sortAttributes": false
}
},
"styleInitialIndent": false,
"scriptInitialIndent": false,
},
"trace": {
"server": "off"
},
"experimental": {
"templateInterpolationService": true
}
},
"html": {
"suggest": true
}
}
}
}
}
}

Vue Language Server expects certain configurations to be present, so you have to specify initializationOptions. The above are the default values.

You may need to change the command value to the full path of your vls executable, if you did not install it to a location that is available from your $PATH.

To get the value for syntaxes, open a .vue file and in the SublimeText console, run: view.settings().get('syntax')

You may need to setup the language server, to do that, in Sublime Text, press Ctrl+P, then type LSP. From the list, select “LSP: Setup Language Server” and press Enter.

Setup Language Server

Now you can have auto complete suggestions of the template:

Autocomplete suggestions in template

Definitions of Vue attributes:

Vue attribute definitions

TypeScript error checking:

TypeScript error checking TypeScript errors summary in console

Animated CSS Label

A simple example of an input field with placeholder text which moves out of the way when text is entered:



How it’s done

HTML

1
2
3
4
<form>
<input name="myInput" id="myInput" class="animated-input" type="text">
<label for="myInput">Placeholder</label>
</form>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
input[type="text"] {
box-sizing: border-box;
height: calc(2em + 1px);
padding: 0.5em;
border: 1px solid #999;
background: #fff;
resize: none;
outline: none;
display: block;
line-height: 1em;
}
input[type="text"]:focus {
border-color: #00bafa;
}
input[type="text"]:focus + label {
color: #00bafa;
}
input[type="text"]:focus + label,
input[type="text"].filled-in + label {
transition-duration: .2s;
transform: translate(0, -3em) scale(0.9, 0.9);
background-color: #fff;
}
input[type="text"] + label {
display: inline-block;
margin: 0 calc(1em + 2px);
padding: 0 2px;
color: #999;
white-space: nowrap;
transition: 0.3s ease;
transform: translate(0, -1.6em)
}

JavaScript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Add listener for when input is blurred
var matches = document.querySelectorAll('.animated-input');
for (var i=0; i<matches.length; i++){
addEvent(matches[i],'blur',onAnimatedInputBlur);
}
// when input is blurred, check if the value is empty
function onAnimatedInputBlur(event){
if(event.target.value){
//if input is non-empty, keep placeholder out of the way
addClass(event.target,'filled-in');
}else{
removeClass(event.target,'filled-in');
}
}
// helper functions
function hasClass(el, className) {
return el.classList ? el.classList.contains(className) : new RegExp('\\b'+ className+'\\b').test(el.className);
}
function addClass(el, className) {
if (el.classList) el.classList.add(className);
else if (!hasClass(el, className)) el.className += ' ' + className;
}
function removeClass(el, className) {
if (el.classList) el.classList.remove(className);
else el.className = el.className.replace(new RegExp('\\b'+ className+'\\b', 'g'), '');
}
function addEvent(el, type, handler) {
if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler);
}

Hello World

Welcome to my first blog post. In this blog I hope to write about the things that interest me with a focus on web development and programming.

I’m a minimalist in everything I do. I prefer simple solutions over complexity. Recently, I setup a web server on a Raspberry Pi with Wordpress. I played around with it for a while. It’s a great product with amazing plugins. Easy to use and write great posts. Yet, the complexity was bugging me. Pages were a little slow to load, even over my home network. The default theme had way too much CSS and JavaScript for my liking. The admin interface has so many features, I felt the constant urge to tweak settings.

I decided instead to go with a static blog. Hexo looked like it had a nice balance of functionality and simplicity. It lets me create new posts using MarkDown with minimal friction and generates an RSS feed. All posts are just files in a folder, making backups a breeze and moving to a new platform should be effortless.