Sunday, September 10, 2017

DotNet core and vuejs - a quick recipe

The problem

So you're stuck in .NET world (maybe with Sitecore or some other God forsaken creation) and you need to do some front-end code. How the hell do you get started?

The solution

Use dotnet core 2.0.0. Scaffold your application, install all the required dependencies and start the application in development mode

    $ sudo apt-get install dotnet-sdk-2.0.0
    $ dotnet new --install Microsoft.AspNetCore.SpaTemplates::*
    $ dotnet new vue -n hello-world
    $ cd hello-world
    $ dotnet restore
    $ npm install
    $ ASPNETCORE_ENVIRONMENT="Development" dotnet run

Happy coding

Tuesday, September 5, 2017

Back to the roots: defining a jQuery plugin in TypeScript

The problem

You're so proficient in TypeScript that you decided all your code will be type-safe. All that is left is this damn jQuery plugin that won't bow to your will and you have no idea how to make all the typing information work.

The solution

This is actually quite easy! Let's start with the obvious import:

    import * as $ from 'jquery'

Next you need to decide if your plugin will take configuration options. If that is the case then you need an interface describing those options

    interface FooOptions {
      color?: string
    }

Now we need to tell TypeScript that we're going to extend the global JQuery interface with our method:

    declare global {
      interface JQuery {
        foo(options?: FooOptions): JQuery
      }
    }

The question mark after options means this is an optional parameter and if not defined then an undefined value will be passed on

All that is left is to write the plugin itself

    $.fn.foo = function(this: JQuery, options?: FooOptions) {
      const settings: FooOptions = {
        color: 'blue',
        ...options,
      }
      return this.each(function() {
        $(this).css({ 'background-color': settings.color })
      })
    }

The method signature tells TypeScript that this in this context is a jQuery object and that there can be a FooOptions passed on.

The rest is obvious: using object spread operator we get the actual set of settings and next we just go on with the plugin's body.

Happy coding!

Back to the roots: jQuery plugins and TypeScript

The problem

So you have learned TypeScript but there is no escape from jQuery. It's crawling back over and over again from the dungeons. But you'd like to write your code in TypeScript and this damn thing doesn't know your new cool method? Want to teach it a lesson? Read on!

The stage

TypeScript is great! No question about it. I use it primarily with webpack and it is a wonderful combination. One of the best things it has is the ability to merge interface definitions. That's right! You can literally extend the interface as you wish! This will come very handy when adding new methods to be called in a jQuery chain. First let's define a plugin foo in plain JavaScript.

    import * as $ from 'jquery'

    $.fn.foo = function () {
      return this.each(function() {
        $(this).css({ 'background-color': 'blue' })
      })
    }

Nothing fancy, right? Each element passed on will receive a blue background. I love blue that is why it is blue and not red.

The solution

Now for the tricky part: teaching TypeScript the definitions. I say definitions because we'll teach it first the JQuery interface by installing the @typings/jquery package

    $ npm install --save-dev '@types/jquery'

Now if you're like me and you use jQuery 3 or later with the default TypeScript configuration you will see a message saying something about Iterable. That's easy to fix. In the tsconfig.json make sure you have the lib line containing the es2015.iterable element, like so:

    "compilerOptions": {
        "lib" : [ "es2015", "es2015.iterable", "dom" ]
    }

With that out of the way let's teach TypeScript the new foo

    declare global {
      interface JQuery {
        foo (): JQuery
      }
    }

This is called declaration merging and allows for arbitrary declarations to be added to arbitrary interfaces just like in JavaScript you can add arbitrary fields to arbitrary objects. Cool, ain't it?

Also note that we use the global module. That's because if we're inside of another module then the original JQuery interface is a different one from the one defined in the global scope and things just don't go so well in that case.

Now let's use our new toy:

    $('div').foo()

Don't forget the new way of importing jQuery requires the allowSyntheticDefaultImports compiler option.

Happy coding!

Friday, September 1, 2017

Back to the roots: jQuery plugin authoring

The problem

The code you're writing using jQuery becomes unmaintainable and hard to read

The solution

Short of stop using jQuery (if that is an option you can use then go for it and use Vue.js instead) start by extracting reusable components/plugins from your code. Writing such a plugin is nothing hard - just a frame where you put your code in:

    (function($) {
      $.fn.myPlugin = function(options) {
        const defaults = {
          // TODO: add default values for options here
        }
        const settings = $.extend(defaults, options)
        // Either process each element in a loop
        return this.each(function() {
          // TODO: add the body of what the plugin should do
          // 'this' is the current element when iterating
        })
        // or operate on all elements at once using other functions
        // return this.css({ ... })
      }
    })(jQuery)

More on authoring jQuery plugins here.

With that in place you're ready to create whatever is used in multiple places like the grownups do and enjoy the pleasure of using method chaining even more!

    $('.my-component').myPlugin({ color: red });

Going Webpack!

It is said that once you go Webpack you never go back. If that's your case then you might want to create your plugins as separate modules and let Webpack put it all together nice and easy. To do that you define your plugin as a module that imports jQuery and exports nothing, then you import that module in your main application file.

    import $ from 'jquery'

    $.fn.myPlugin = function(options) {
      const defaults = {
        // TODO: add default values for options here
      }
      const settings = $.extend(defaults, options)
      // Either process each element in a loop
      return this.each(function() {
        // TODO: add the body of what the plugin should do
        // 'this' is the current element when iterating
      })
      // or operate on all elements at once using other functions
      // return this.css({ ... })
    }

In main.js

    import $ from 'jquery'
    import './my-plugin'

    $(document).ready(function() {
      // use your plugin here
      $('.my-component').myPlugin({ color: red });
    })

The easiest Webpack configuration that will work in this case is

    module.exports = {
      entry: __dirname + '/index.js',
      output: {
        path: __dirname + '/dist',
        filename: 'index.js'
      },
      devtool: 'source-map'
    }

In this case you can include the dist/index.js and you'll have all you need in one place. And that's it! Easy as a lion :)

And last but not least: don't name your plugin myPlugin. It's lame to do in anything else than a tutorial. Be explicit, use good names, be a good programmer!

Happy coding!

PS

Please be mindful that the function assigned to $.fn.myPlugin as well as the one that iterates over elements that have been passed on can't be arrow functions because jQuery sets the this element. Just remember that.

Friday, July 28, 2017

Getting started with Quasar on Android with Linux

The problem

As usual the problem is setting up the development environment for a project. This time it's going to be project using the Quasar framework and building the app for Android. This guide assumes a clean environment that does not contain anything (no Java, no Node no nothing).

Solution

First we need to have NodeJS installed. I install mine using the Node Version Manager (or nvm for short). Follow the instructions on https://github.com/creationix/nvm or simply enter the following commands:

$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash

At this stage you need to close the current terminal and open a new one for the installation to finish and then install the latest stable NodeJS like so:

$ nvm install stable

We'll need two more things: JDK and Gradle. I install mine using the SdkMan:

$ curl -s "https://get.sdkman.io" | bash

At this stage you need to close the current terminal and open a new one for the installation to finish and then install Java and Gradle like so:

$ sdk install java
$ sdk install gradle 2.14.1

The version of Gradle is important. Cordova works with specific versions so you might want to stick to 2.14.1 to avoid any issues

Next we need to have some basic tooling for NodeJS installed. This includes obviously the Quasar CLI but also Yarn and Cordova

$ npm install -g yarn quasar-cli cordova

Having all that installed we can now instantiate and build our first project

$ quasar init hello-world
$ cd hello-world
$ yarn
$ yarn build

At this stage we have have the hello-world type quasar application built. We can work on it as if it would be any other VueJS application by running

$ yarn dev

More on it in the official documentation for Quasar

What we need next is the Android SDK. This is the most troublesome part of all, but if scripted it doesn't seem to be all that hard. First you need to download and extract the Android SDK. To do that we'll use the unzip tool that understands the .zip archive format. Be patient. It takes forever to download and install all the components. On my connection it took almost 10 minutes!!!

$ sudo apt install -y unzip
$ mkdir -p ~/Android/Sdk
$ cd ~/Android/Sdk
$ wget -c https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
$ unzip -q sdk-tools-linux-3859397.zip
$ cd tools/bin
$ ./sdkmanager --update
$ ./sdkmanager emulator platform-tools
$ ./sdkmanager "build-tools;25.0.3"
$ ./sdkmanager "platforms;android-25"
$ ./sdkmanager "system-images;android-25;google_apis;x86"
$ ./avdmanager create avd --force \
               --name test \
               --package "system-images;android-25;google_apis;x86" \
               --tag google_apis \
               --device 'Nexus 4'

Starting the emulator takes some time - be patient!

$ ~/Android/Sdk/tools/emulator -avd test -skin 768x1280

After it is up we have a platform to run our Quasar application on. Let's use it to run our new and shiny app.

$ cd [your_project_folder]
$ quasar wrap cordova
$ cd cordova
$ ANDROID_HOME=~/Android/Sdk cordova platform add android
$ ANDROID_HOME=~/Android/Sdk cordova build
$ ANDROID_HOME=~/Android/Sdk cordova run

That's it! The application should be running on your virtual Android device. Of course you should make the ANDROID_HOME variable more permanent by adding it to your .profile or .bashrc startup files but I'll leave it up to you.

Have fun!

Sunday, May 28, 2017

Vue.js cheatsheet

If you ever wondered why Vue.js is so easy take a look at this cheatsheet!

Vue/Vuex - a natural way forward

For a few days I have been creating an application to help with retrospection meetings in our distributed team. Obviously, as one might have guessed, the backend is in Node.js and, obviously, the frontend is in Vue.js. After a trial and error of a few approaches I decided that the state management is basically killing me so I went for Vuex to do its job. I knew little to nothing about Vuex but obviously I have had a lot of experience with Redux and since both do the same thing I thought things won't be too difficult. And I was right!

I followed this great article by Matt Bradford on how to get started with Vue+Vuex and I need to say that he hit the nail in the head with that article. Easy to follow, clear in message - just perfect. Then I went on to the official docs and, as usual with all things related to Vue.js, the guide was just perfect. It took me about 2 hours while creating the app to get used to it, learn the API, understand the difference between actions and mutations - basically a walk in the park!

The key takeaway from this experience for me is that documentation matters, a lot! It has to be good, easy to understand and fun to follow. Like a well written book that you can't take your eyes off late in the evening. Of course it helps if the thing the documentation describes is easy and fun but that is just about 30% - the rest is the craftsmanship of the author of the documentation. To underline that I have been reading some very ugly specs at work, written like someone didn't want to read what he wrote. That was just crazy! After that getting my hands on the Vuex guide helped me keep up the hopes for humanity :P

The bottom line is: if you feel like you're struggling with managing the state, even just a little bit - you need Vuex!

The next thing I desperately wanted to try was to make a system that through websockets to distribute the changes to other connected clients. This means that when you add a card on one browser that information is then posted via the websocket and the server broadcasts that information back to other browsers. I must say I am extremely surprised how well that worked! One thing to note is that when working on the store full page reloads do happen a lot. Each full reload causes the socket to be closed and reopened - which isn't all that bad. However restarting the server is a whole other story because websockets don't reconnect automagically. In this case, after trying out what I thought would work I ended up using reconnecting-websocket module. And it works absolutely great!

The server side uses the no database approach with a simple on-line events store and commands that mirror the mutations in Vuex. Easy and very, very fast! It looks like event sourcing is actually a good thing :)

You can find the sources for the project on Github.

Happy coding!