Category: javascript

Switching from NetBeans to Visual Studio Code (for JavaScript development)

At first, I must say that I was a NetBeans developer for a long time and I still love it. It is the best IDE for Java development. Ok, maybe IntelliJ IDEA could be a competitor in such a contest, but for me, NetBeans would win ๐Ÿ˜‰

However, when it comes to JavaScript development, it’s absolutely different story. Since it has no strict type checking, then the editor must be more free. In fact, that means that the editor does not need to provide anything more than just colorings and at least some code completion (which does not need to be precisely accurate, most of the time just everything could be in there). Also, there is no need for refactoring features because it’s too hard to evaluate current coding style and make such feature really reliable.

There is nothing worse than tools which do some automatic stuff like refactoring and one can not rely on it (in the sense that it will not break your code silently).

So far so good. NetBeans for JS has a really nice coloring (well, I’m just used to it, hence I say it’s nice ;-), it also provides some useful items in code completion, it has a native support for Karma test runner, etc. So why I decided to switch?

That’s simple. The latest version of NetBeans (patched 8.2) suffers from memory leaks (I think that it happens only for JS development due to parser implementation switch, didn’t notice that in other project types) and my 6 years old MacBook Pro is not able to handle that gracefully ๐Ÿ˜‰ Yep, I was forced to restart NetBeans every hour. That was too much and I said ENOUGH! I already had a short term experience with Visual Studio Code editor, so gave it a chance and here are my switcher observations.

Code Coloring

I would never think that code coloring would be the biggest problem for me when switching from one editor to another. But it was. I wasn’t able to get used to new colors. Seriously! VS Code has a lot of native themes provided out of the box. I tried them all, but I was very nervous when coding in them. I wasn’t able to scan the code effectively through my eyes. It was very depressing.

So I tried to find some Custom Theme extension which would provide me same Code Coloring what I was used to from NetBeans. There is one, but it’s too poor. In fact, it doesn’t look like NetBeans coloring…at least for .js files. Yes, it uses the same colors, but it’s not the same. It should use them for same elements, etc.

So I decided to prepare my own NetBeans Light Theme. It is not possible to get 100% same experience, because theming in VS Code does not support semantic colorings, but I would say, that my NetBeans Light Theme is almost the same ans NetBeans one ๐Ÿ˜‰ When I applied that Theme, I was like a newborn child which gets pacifier. Calm and satisfied ๐Ÿ™‚

When you are used to NetBeans Theme colors, try to use NetBeans Light Theme extension for VS Code.

VSCode NetBeans Light Theme

Code Completion (a.k.a. IntelliSense)

Everyone of us is somehow used to it. You know…writing a code and then a small popup with code suggestions appears next to the caret automatically, or by pressing e.g. Ctrl+Space.

Functions and Properties

I use it heavily for Java development in NetBeans but didn’t use it much for JavaScript development. As I wrote before, it’s pretty hard to make a suggestion really usable for some kind of coding styles and most of the time I spent by finding the right item in Code Completion popup by pressing Up and Down back and forth. So the difference between Code Completion in NetBeans and VS Code is actually negligible. But just for me of course, because I actually don’t use it ๐Ÿ™‚ If you are used to it from your editor, you must make your own comparison ๐Ÿ˜‰

RequireJS

The project I work on uses RequireJS for modularization and that is where NetBeans is much further in Code Completion. In suggesting module paths in define() and require() functions. In fact, VS Code does not suggest anything, NetBeans suggests everything. But I think that it is just a matter of time when someone writes an extension for that. I would really appreciate that!

Edit: I found Path Intellisense extension but it doesn’t seem to work well for RequreJS modules. Maybe it could help you in other cases.

Running Tasks

Autodetection

This was a pleasant surprise. Because when you open a project in NetBeans, it tries to find the most common task runners – their config files (grunt, gulp, …) and detect possible runnable tasks what they provide.

VS Code behaves a bit differently but in the end, it detects possible tasks as well. You just need to run Tasks: Configure Task Runner command and that’s it. Then you can just invoke command console, write task and detected tasks are suggested automatically.

Custom Tasks

What is an advantage of VS Code is a possibility of defining your custom tasks for a workspace in a separate tasks.json file. I started to use it for tasks like test file, etc. because in that file you can use some magic variable templates provided by VS Code, like ${fileBasenameNoExtension}, which are replaced by proper values when such task is invoked.

Tasks 2.0.0

Commonly when you invoke a task it runs in a special Output Panel. The problem is that the output is not colored as you would expect – like running the command in terminal. And it’s also insanely slow which is really bad when you need to run thousands of tests many times in a day.

But you can switch to Tasks v2.0.0 by defining a proper "version": "2.0.0" property in tasks.json file (it’s a possibility for early adopters and can change in future versions). The main difference is that then all tasks are run in Terminal Panel. So coloring is much better and performance as well.

The counterpart of this improvement is that autodetection does not work, so you must define all your tasks in tasks.json file manually and in fact duplicate your Gruntfile.js. I already filled an issue for that so we will see what happen.

Git Integration

Git integration in NetBeans is much much further. And is awesome. Really awesome. But VS Code has an integrated support too. It’s not so good, but for basic workflow (commit, pull, push) it could be good enough. If you want more, there is a great extension called GitLens which adds a support for Git Blaming in a gutter, file history and much more. This extension is a must have for everyone who uses git. Basic editor support is just basic.

If using git is your daily bread, install GitLens extension.

Debugger

Well, do you think that we should use something else then Chrome Dev Tools? I don’t think so, but both of them have some integrated debugger. If you really want it. But, you know. CDT is CDT, so I don’t care about integrated debuggers ๐Ÿ˜‰

Extensions

NetBeans has its own Plugin Portal but as I remember I never used any public plugin. Everything what I used worked out of the box, or I wrote my own plugin ๐Ÿ˜‰ That’s not so strange as it could look like if you realize that NetBeans is not just an editor. It’s fully featured, project based IDE.

With VS Code it is an absolutely different story. VS Code is quite light editor with just basic support for some features. And as you could guess from paragraphs above, there is probably an extension for everything on VS Code Marketplace. And if it is not there now, then it will be there probably tomorrow ๐Ÿ™‚ Extensions are your best friend when using VS Code. You will not be able to live without them, trust me and just use them ๐Ÿ˜‰

Issue Reporting

If you find some problem in VS Code, don’t hesitate to file them an issue. It’s an open source hosted on Github so everyone of you certainly knows how to file an issue. The entire team is really flexible and I get answers to my issues in hours! I really want to appreciate their approach.

And that’s all! Thanks for reading and happy coding – in any editor you choose ;-)!

Advertisements

How I started to write JsThis, a Visual Studio Code extension

One day I read a story about how Microsoft open-sourced a great editor based on JavaScript. If you don’t know what’s going on, I’m talking about Visual Studio Code. It’s something what, at least at first glance, looks like another Sublime Text based clone. But it’s from Microsoft ๐Ÿ™‚ And because there is a lack of really good JavaScript editor at the market, I decided to give it a chance. It has a JS debugger, IntelliSense and everything what you need for JS development.

It has a support for other languages as well! Look at the overview.

First impression, first disappointment

I started it, opened a project (folder)…and…it looked quite cool. Simple, clean and what was the biggest surprise, it was quite fast.

Then I started to code…and the first and the biggest problem occured. Even though JS IntelliSense (Code Completion) works well for simple functions, variables, etc., it doesn’t work for this keyword at all. And it was the biggest problem for me, because the project I work on is prototype based. We use RequireJs modules and inside it we use this ES3 object pattern:

var MyConstructor = function () {
    this._myProperty = 'my property value';
};

MyConstructor.prototype.doSomething = function () {
    // do something
    console.log(this._myProperty);
};

return new MyConstructor();

So code completion for this._myProperty in doSomething(); method doesn’t work. I looked at the Extension Market Place whether there is some extension which could enable such IntelliSense, but unfortunatelly there is no such extension.

So I decided to write my own…and call it JsThis.

After few days I found a mention about a support of prototype style in version 0.10.8 notes, but suprisingly it didn’t mean, that it should work in 0.10.8 by default. One must enable it manually. It was clarified in a issue I filled.

Extension implementation process

First steps

It is very easy to start. Just look at the Extension web and follow both of prepared examples. There is one simple Hello World extension and one a bit more complex Word Count extension. They will guide you through the extension creation process and will show you some basics.

After reading these examples I was able to implement a basic CompletionItemProvider which was called in .js files when one invoked IntelliSense. I played with the API a bit and after few hours I had a prototype of my custom extension which collected this usages and suggested them in proper places.

IntelliSense - Code Completion

Why it swallows an errors?

What really annoyed me during the whole implementation was the fact that VSCode swallowed all the errors and exceptions which occured e.g. in third party libraries! Errors were just caught somewhere and the code execution continued like nothing happened. It wasn’t even logged to console! Why? Really don’t know…

Yes, there is a possibility to set the debugger to stop on Uncaught exceptions and All exceptions, but…you know. I don’t wanna stop. I just want to know that something went wrong. I want VSCode to just log it for me.

Didn’t find a suitable solution.

Travis integration should be simple, documentation says…

I wanted to try how difficult would it be to enable running tests on Travis. I followed the documentation and it seemed that it will be pretty simple. But actually it wasn’t.

Even though I followed the documentation properly and properly did everything what was described there, my jobs were failing. The problem was, that my project was not written in TypeScript, but in plain JavaScript.

The instructions assume, that the extension is written in TypeScript and that your code will be compiled before the test run. It automatically sets some paths to “compilation output folder” and it really can’t work. Plain JS code will not magically appear in that “output folder”, so then the test run fail.

What I had to do was to remove - npm run vscode:prepublish section from .travis.yml. That was the part which did the compilation and it ended up with a “Missing TypeScript” error.

The second thing I had to do was to add this part to .travis.yml:

env:
  - CODE_TESTS_PATH="$TRAVIS_BUILD_DIR/test"

which says where your test files are. Otherwise VSCode appends /test/out instead of just /test.

I filled an issue because I thing that it really needs to be documented somewhere.

The another problem was with defined VSCode engine version. That’s the version of API which is downloaded before tests start. The documentation says that you should use ^0.10.7. But I couldn’t. Why? To be honest, I really don’t know. When I set it then Travis started to complain and builds failed.

So I looked at some alredy existing extensions (written by Microsoft itself) and…they use 0.10.x! Ok, so I tried it…and it worked. Ok, it worked, but only on a Linux machine. Even though the documentation says that you can use:

os:
  - osx
  - linux

it didn’t work for me on OS X. So I temporarily commented that out and filled another issue. And, yes, it worked locally on my Mac ๐Ÿ˜‰

After these changes tests were passing on Travis in Linux.

Conclusion

Here I described what I bumped into when I tried to work with and on the Visual Studo Code editor. I don’t think that it’s the best solution what you can find on Internet, it’s just in beta, but it’s definitely worth trying. It’s still under heavy developement, if you look at its GitHub issues, you can see how devs are working on it.

And what about my extension? I will keep working on it. Yes, it can happen that VSCode will have a native support for such features (I don’t know anything about this support, but prototype should work in 0.10.10), but at least I will learn something new ๐Ÿ™‚

Thanks for reading!

Use native HTML5 Drag and Drop support! Seriously?! No, thanks!

I would like to write you my observations what I did when I tried to implement native HTML5 drag and drop support for an existing app. And just to be precise, today is February, 2016.

At work we work on quite complex web app which uses drag and drop based UI for building some page content. Doesn’t matter what’s exactly going on. It’s in development process for almost 3 years and from the beginning we use jQueryUI draggable and droppable support. It was very pragmatic solution, because when the project started, we needed to support really old and obscure browsers, so we benefit from jQuery abstraction. So far, so good.

We used jQueryUI just for handling drag-and-drop events, we didn’t use a UI components. We used one of our company’s internal UI component framework. It looked quite good, it used knockout and jQuery and everything was cool.

But one day, that internal framework added a feature to their Table component. One was able add columns to a table by dragging and dropping a page element to it. Cool!!! We need to support such an awesome feature! It looked really easy to implement, documentation said that you just need to add draggable="true" attribute to that draggable element.

So I did it. And that was just the beginning…

jQueryUI and native HTML5? Hehe, sorry, just kidding…

I had one element on a page, which could be dropped either to Table component (which used HTML5 native Drop support), or directly to the page (where we used jQueryUI droppable). And that was a problem. My naive solution was just to add draggable="true" to such an element and I hoped that it will work. That jQuery will handle that. That it uses HTML5 native DaD support internally if possible. But I was soooo wrong. It didn’t work. Really not. I also tried to fire dragstart event manually. Nothing. End.

So I ended up at the very beginning. That wasn’t a good day.

I realized that the only working solution would be to rewrite our entire app to use native HTML5 Drag and Drop instead of jQueryUI draggable and droppable support.

Well, ok. We have a year 2016, we don’t need to support IE < 11, it can't be so hard to rewrite it! Another wrong assumption…

Common problem with too many events

Everybody who tried to work with HTML5 native Drag and Drop support bumped into it. 8 events and you must implement some of them just because you need to call event.preventDefault(); or to return false;? Uff. The most knows example is that you must implement dragover and call event.preventDefault(); because without it drop event doesn't work. Strange, isn't it?

So I fixed that and then tried to handle some actions which should be triggered when dragged element is dragged over or out of the droppable element. It seemed to be a very simple thing. Just implement dragenter event and dragleave event. Ok so I did it…and it didn't work. I was getting tens of events even though I was still over the droppable zone! Wtf? I googled a bit and found that these events have a problem with child elements of a droppable zone. Every child fires dragenter and dragleave even though you didn't put an event listener on them.

Ok, someone surely solved that issue before me, so I googled again. I found and tried a lot of examples how to solve it. It included counters of dragenters, or remembering of first dragentered element, comparing various event targets with the element on which I added a listener.

Nothing worked properly.

The one problem was that my child elements were generated dynamically during the drag event and put under the cursor. The another problem was that my child elements were stretched over the droppable element, so there was no space (also no border) of the droppable element visible.

The only working solution was to set CSS property pointer-events: none; to that child elements.

Firefox intermezzo

All my fight took place in Chrome browser. I like it and its dev tools are the best. But a little devil sitting on my left shoulder whispered me "Try it in a Firefox! Just for fun!". So I tried it. And nothing worked. Even things that worked in Chrome didn't work in Firefox. So when I tried to drag an element, it wasn't dragged at all. That was a really baaad day.

After some attempts to get it to work, which were absolutely out of place, I saw somewhere that people are setting event.dataTransfer.setData('text', null); in dragstart event. I didn't do that, because I didn't want to transfer any data, so. But, do you see it? null! So I tried it and it worked like a charm!

In Firefox, you must set at least nothing to dataTransfer object, otherwise it doesn't work. Holy crap!

Closed that Devil's tool and switched back to Chrome.

Ghosting should be easy…

Yes, it should. In a normal world, one should just provide an html element which should be positioned automatically and absolutely alongside with the dragging cursor.

It looks like that it works this way, but it doesn't. Ideally you should provide some image, or canvas to some event.dataTransfer.setDropImage(); method. Image?? Omg…ok, someone wrote somewhere that an html element can be passed to that method as well. Great, we won! But just a bit. What the browser actually does is that it takes that element and renders an image from it, which is then used as a ghost. Yep, image again.

But who cares, you say. I say that everyone cares. I can make my element, style it, attach somewhere to body…and that's it. But not when that element's position is hidden by another element or is out of a viewport. That element must be visible. But ok, we can live with it. Until you wanna style that "element" during the drag. You absolutely can't. Oh, sorry…you can. You can style that element, but not its image which is actually beeing dragged. Sorry…

…as well as getting better cursor feedback

The only way how to at least somehow modify a dragging cursor, is by event.dataTransfer.allowedEffect and event.dataTransfer.dropEffect properties.

The first one must be set in dragstart event and tries to say what kind of opperation this draggable supports. E.g. copyMove which means that the dragged element can be copied and moved.

The second is used in dragenter and dragover event. Yes, in that strange dragover event. If you don't use it there, it is possible that the cursor will not change at all (or will use some defaults). And you can set it to one of 4 predefined strings: none, move, copy and link.

There aren't used common well known css cursor property values neither in allowedEffect, nor in dropEffect. There are just some predefined strings which are represented somehow by the browser itself. So yes, you can't set a cursor to no-drop! The only possible/similar-like value is none, but it shows a common drag cursor. That's really bad, because you can not set no-drop by default and just change it to e.g. move in dragenter event! That's sooooo crappy.

My conclusion?

I didn't end up with struggling yet, but I already know, that I will not use it anymore in any other project. If possible.

So if possible, save your nerves and do not try to use it. You will have a very bad day and it is not worth it…

Bye!