Sunday, December 31, 2017

Creating libraries with Vue components

Vue.js is great. There is no question about it. It's small, versatile, conscious, easy to learn - you name it. With the addition of POI it is probably also one of the most friendly frameworks to work with. Let's see how we can share single-file components between projects!

Method 1: npm link

npm link is probably one of the least known features if your primary occupation is creation of web application and you have never created an NPM package yourself. It has been there in NPM for ages and is the primary tool for library creators.

To use it when you have created your library and want to test it then what you do is you run

npm link

in the library folder and you run

npm link <library-name>

in the project that you want to use the library in. That gives you practically a hard binding between the library and the project using a symlink which means that if you introduce a change in the library then the project sees those changes immediately. It's a fantastic tool when you're in the process of working on the library. It can be further streamlined when we specify a dependency using the file: protocol like so:

"dependencies": {
  "my-library": "file:path-to-library"
}

This is also a great option if the library itself is part of your project and is being used to simply tear the application code from the reusable components. This is a great idea because if the application code changed often and the components change seldom then the size of your client.js gets smaller as all code from node_modules (this includes libraries referenced with the file: protocol) get pushed into the vendor.js block.

"dependencies": {
  "project-components": "file:../project-components"
}

This will automatically setup a link named project-components inside node_modules. What's even more interesting, when you do the npm install to install dependencies then the project-component's dependencies will be installed in ../project-components/node_modules automatically thus each project that uses that library won't need a copy of the shared dependencies.

Method 2: npm publish

When you want to go for a reusable library that you'd like to share between multiple projects then the right way to go is to use a repository. There is a multitude of options but the one I find really useful in an organization are npmjs.com for all things opensource and verdaccio for all the packages that you would like to keep available only for in-house components. The nice thing about verdaccio is that it automatically acts as a proxy to npmjs.com so all you do in your project is you tell npm that the repository is located where verdaccio is

npm set registry http://localhost:4873/

and you're all set.

Example

To show you how it is done I have created a sample project on GitHub. It consists of 3 parts: the library containing 2 components, a host application using those components and a little bit of automation to start the repository server.

Patterns

When creating a component library there are 2 options that one can use:

  • include the modules that build the library
  • include the built version of the library

Which one to use depends on the library itself. If you create a library that is to be used in all sorts of projects but you wrote it in some non-standard way (let's say you used CoffeeScript) then to make it useful for the rest of us you need to point the main to the compiled version. However, if you created a library specifically for use within a specific environment it makes sense to create an index.js and point your main entry in package.json to it and to put all your code in the lib folder:

export { default as componentA } from './lib/componentA.vue'
export { default as componentB } from './lib/componentB.vue'
That way, if someone wants to include all of your library they just include it and all is great:

import myLib from 'myLib'

Or using requirejs:

const myLib = require('myLib')

If for whatever reason they want to include only a portion of it, let's say just one or two components and not the whole shebang, then they are free to do so as follows:

import componentA from 'myLib/lib/componentA.vue'

Or using requirejs:

const componentA = require('myLib/lib/componentA.vue')

The latter form allows for the treeshaking algorithm to exclude everything that is not used by the application in the resulting file thus making the final bundle smaller (sometimes a lot smaller - see the use of lodash).

To create a compiled version of your library with POI all you need is to run the following command:

poi build --library index.js

and in the dist folder you'll get a library.js that you point the main in package.json to and you're done!

That's it! It is really simple to create libraries shared between parts of your project and not all that much more complex to create universal applications shared with everyone else in the NPM ecosystem.

Happy coding in 2018!

Thursday, December 14, 2017

Using webfonts-generator with POI

The problem

This might come as a surprise to you (it did to me at least) that POI is not handling generation of webfonts by default. It does so many wonderful things but webfonts generation is not one of them, unfortunately. You might ask what are webfonts and why do we need to generate one in a frontend project? Aren't there enough fonts to choose from already? To answer that we need to understand how browsers work when downloading multiple resources. First of all there is a limit to how many connections can be made at the same time to one server. Secondly there is a limit to how many connections can there be in total at any given time. So if, for example, you'd like to load 30 small black and white images (for use as icons) then the browser would have a lot of work to do and the page would load very, very slowly. To mitigate that problem you could use a custom font that will contain all the images, compressed, and it will take a fraction of the time to load. This is exactly what webfonts-generator does.

The solution

So how do we use it in a POI project if it is not available by default? It's actually not that simple. We need to extend the already impressive webpack configuration to teach it what to do with the font descriptors. Font descriptors are just JavaScript modules ending with .font.js exporting definition of the font, like the one below:

module.exports = {
  fontName: 'icons',
  files: [
    'phone.svg',
  ]
}

Having that in place we can start extending our configuration. As you already know POI contains webpack rules for all the common types of files. Those rules differ from production to test to development configuration. The rule we need to add for it to work properly needs to be just like the one for CSSes, just with the webfonts-loader added at the end of the use list. So first we need to find the css rule:

const isCssRule = rule => rule.test.toString().indexOf('\.css$') >= 0
const findCssRule = rules => rules.find(isCssRule)

Having that rule in hand let's create another rule for webfonts that contains the definition of a loader:

const constructWebfontRuleFromCssRule = rule => ({
  test: /\.font\.js$/,
  use: [
    ...rule.use, 
    {
      loader: 'webfonts-loader', options: {
        fileName: 'assets/fonts/[fontname].[hash:8].[ext]'
      }
    },
  ]
})

Then we can add the rule to webpack configuration in poi.config.js:

module.exports = {
  webpack (config) {
    const rule = findCssRule(config.module.rules)
    config.module.rules.push(constructWebfontRuleFromCssRule(rule))

    return config
  }
}

And finally we need to install the additional loader like so:

npm install --save-dev webfonts-loader

webfonts-generator is a transitive dependency so it will be installed automatically too.

Final thoughts

I know that doesn't seem like much but it took me way too long to figure it out so I figured I'll post it for posterity. In the meanwhile I have created a ticket in the POI project for it to be implemented as part of the default configuration so that we won't have to deal with it ourselves. Will see if that will catch on or not.

Happy building!

Thursday, December 7, 2017

POI and naming classes in CSS Modules

This will be a quick one. If you're trying to use CSS modules with POI in a Vue.js app and you want to exercise some control over what the names of the generated classes are then there is a configuration option in POI for that. It's a little bit hidden so it took mi like 5 minutes to figure it out - hence the post.

module.exports = {
  vue: {
    cssModules: {
      localIdentName: '[hash:base64:5]'
    }
  }
}

That weirdness stems from the fact that POI configures the css-loader indirectly via the vue when setting up the vue-loader. We can take advantage of the fact that it uses the Object.assign method and sneak in our configuration option.

Happy coding!

Saturday, November 25, 2017

Vue.js - the jQuery killer

Vue.js is awesome. It really is. There is however this notion that frameworks such as Angular or React are primarily for full-fledged, single-page frontend applications and that notion carries over to Vue. In this installment I am going to try to share with you a way to treat Vue as a better jQuery and to have more than a few micro-apps on one page.

The jQuery phenomena

There are more than a few reasons why jQuery became so popular. One of them was the need to target multiple browsers with one, coherent codebase. I think that this is exactly why there are so many jQuery developers out there and so few people (by comparison) that can actually use JavaScript and the DOM API. Fortunately enough, the browser wars led to standards being formed and implemented by most major browsers and now things like searching for elements in the DOM tree or toggling a class is not a challenge anymore. Let's face it: even Ajax (the biggest example of fallout from browser wars) is standardized these days! And I am not talking here about the XMLHttpRequest class but about the fetch API which makes jQuery pretty much useless.

Welcome to the 21st century

So where do frameworks like React, Angular or Vue fit in this new, jQuery-free world? Is there even a place for them? Well, as it turns out 2 things have changed over the past decade: not only browsers became more standardized but also the applications became way more demanding. It's not just a few plugins bashed together like it used to be back in the days. Now we see browsers as an operating system / development platform of its own that can target multiple hardware and deliver experiences (not "pages") wherever we go. That's the price to pay for being cool :)

For that reason the size of a codebase that use jQuery alone grows out of proportion trying to synchronize the state of multiple deeply nested components. This is not what jQuery was designed for and it's also where the scaling capabilities of it end. We need something that will match the new requirements. And so along came a long list of failures in the industry trying to solve the misery of big apps. At first it looked like the MVC pattern (so popular in the backend world) would be a good fit. I think the main reason was the overwhelming presence of design patterns in the late 2000s. And MVC was (along with Singleton) among the most recognized ones. Even good frameworks like ExtJS went to the dark side and implemented the MVC pattern. Such a shame!!!

That didn't solve the scaling problem. Apps were growing out of proportion of what was feasible at that time. It wasn't until about 2013 when Facebook's engineer Jordan Walke came up with this idea of shedding MVC in the frontend all together and replacing the ever growing connections between UI and data with mathematical precision and unidirectional data flow that we all now take for granted.

The framework problem

As it turns out the problem with frameworks is that they take control from you and let you react only when something happens. This is mostly great but sometimes it means global state needs to be maintained to gain access to the underlying data. React does away with this by embedding the state directly in components. This was, in my opinion, the biggest step forward after the definition of unidirectional data flow. However, with React came JSX (to make our life easier) and that came with Babel pre-processor or TypeScript and other goodness like webpack, gulp, grunt to be the main driver for the build process. In short: the build process became mandatory. Something you have never had to talk about when doing just jQuery. To make matter even more interesting now that we had the app it was usually so heavy (take angular 2 hello app built with the daemonic spin-off form Ember CLI) that having more than one app was virtually technically impossible.

To even approach the level of reusability jQuery provides we would need to get into the realm of tens or hundreds of apps on one page! That feels right down insane but if you come to think of it, it really opens up possibilities where previously only jQuery would fit.

The Vue

Such is the case with Vue.js. It is a small library (not necessarily a framework) that doesn't require any build steps, runs directly from the browser but if required it can grow to gigantic proportions by the share virtue of composition of components. Yes, that is right, if used with the component mindset it will easily grow beyond what was possible with jQuery (or plain old JavaScript for that matter). But it can do small bits as well! And it does it with such a grace it is absolutely stunning!

Let's see the simplest app that would run in the browser:

    new Vue({
      el: '#app',
      render: h => h({ template: '<h1>Hello, world!</h1>' })
    })

Assuming there is an element with id '#app' the app will replace that element with an H1 with the text Hello, world!. The el element doesn't need to be a CSS selector (if it would be it needs to point to one and only one element or the rest will be discarded). It can, however, be a DOM object, like so:

    new Vue({
      el: document.querySelector('#app'),
      render: h => h({ template: '<h1>Hello, world!</h1>' })
    })

Now assuming we would like to instantiate this application in every container with the class app applied we would need to do something that resembles this:

    [ ...document.querySelectorAll('.app') ].forEach(el => {
      new Vue({
        el,
        render: h => h({ template: '<h1>Hello, world!</h1>' })
      })
    })

Easy, right? Because the querySelectorApp returns an array-like object that doesn't provide the forEach method we're spreading that list over an array literal effectively creating a proper array from the list of found elements. Next, we apply the Vue application on each of the found placeholders. This is very much what jQuery was doing to us for all these years! Applying a transformation to all selected elements! Sure, it's true jQuery was less invasive (if there is anything present in the <div class="app">...</dic> Vue will go and nuke that content with its own content). But is it not like we would like to have less and less HTML managed by the backend (preferably just a placeholder for what is an app that is fully managed by the browser?

Of course the other question on the horizon is passing on information to those small apps. There is a few ways to do it (Ajax being one of them) that can help you here. My favorite is for the backend to use either a JavaScript object somewhere on the page that can be easily matched with the container. Other example (especially useful if there are just a few parameters you need to pass in) is to use the data-* attributes. Just don't go overboard with it!

Post mortem

I think that jQuery is one of the few frontend utilities that profoundly changed the way we think about software development. However the time is, finally, almost up because of the requirements new Internet applications. There is an obvious need for tools that solve problems that are not yet natively solved in the browsers in such a way that would be appropriate for the broad Internet developers audience. React and Vue are fitting nicely in that niche and do a fantastic job in being lean, focused. That gives the opportunity to do a lot more with Vue than was previously possible and to use those new tools in ways that would previously not even cross one's mind.

Happy coding

Wednesday, November 22, 2017

Writing unit tests with Vuejs and Poi

Poi is great. It's fantastic! It's one of the tools that were very much missing from the landscape. Now that we already have it let's explore what we can do with it. Let's get serious!

This time we're going to create a POI-based project that will support both Vue and unit testing.

First we need to have a project. A simple npm init will do. When asked to give the test command write poi test and you're done.

$ npm init
...
test command: poi test
...

Is this ok? (yes)

That was easy. Now let's install the required dependencies (there are quite a few of them but we'll go through the list and I will explain what each one does):

$ npm install --save-dev poi poi-preset-karma \
    webpack karma mocha chai karma-webpack karma-mocha karma-chai \
    vue vue-test-utils

poi is our build system so it is obvious it needs to be installed. poi-preset-karma is a preset for poi for it to know what to do when you execute poi test. It will use karma to run the tests.

webpack and karma-webpack allow to use webpack to bundle all the files

mocha is the testing framework giving you BDD-like tests with describe and it. karma-mocha is a package that allows easy integration of Karma and Mocha.

chai is a fantastic library for writing expectations. Similarly to Mocha, karma-chai makes it easy to integrate Karma with Chai.

And last but not least we top it with some Vue sauce. vue is our beloved frontend framework and vue-test-utils is a library that aids testing.

Let's write some tests

The default folder structure assumes unit tests to be located in test/unit folder and the files to be named like something.test.js. So let's create one:

test/unit/example.test.js

it('will pass', () => {
  expect(1).to.equal(1)
})

Easy, right? For Poi to know what to do when we run poi test we need to use a preset. To do that we'll create a poi.config.js file like so:

module.exports = {
  presets: [
    require('poi-preset-karma')({
      frameworks: [ 'mocha', 'chai' ]
    })
  ]
}

As you can see there we use Chai asserts. For Mocha to know about Chai we need to tell the Karma preset that both Mocha and Chai are to be used.

Now all that remains is to run the tests. There are 2 options for running:

  • Run just once and finish
  • Run continuously in the background and re-run tests when files change

To just run the tests and finish you issue the command

$ npm test

This works because test is a top-level npm command.

To run tests continuously with automatic re-running do this:

$ npm test -- --watch

Let's decipher the bits. npm test is pretty much obvious at this point. The double-dash is a way to tell npm hey, when you run the command specified in the scripts section then add all the parameters that follow to the execution. In our case the --watch parameter enables watching changes on files and automatic re-running of all the tests.

Poi and continuous integration server

Running tests in a real browser is great because they will be testing components in their natural habitat. It poses however a difficult problem when running them on a headless continuous integration server. This is a common problem and to address that Poi has a switch that uses ChromeHeadless instead of the regular Chrome:

$ npm test -- --headless

Of course you can combine them and run headless tests in watch mode on a remote machine via SSH using Vim or Emacs as your text editor - especially if your primary work computer is running Windows and you want things to go fast(er). The possibilities are endless.

Debugging

By default tests are being executed on Google Chrome. The page you'll see contains a little DEBUG button. When you click it a new tab will open where you can set breakpoints and examine your code. One thing to note is that by default there is a limit to how long one unit test can take (2s) and you will most likely exceed that limit if you pause in a test method. Don't be alarmed by that - just re-run your tests without breakpoints and you'll see if it works or not.

Please note that the tests in debug mode won't re-run by themselves when you change things in the sources. You need to refresh the page to start a new test run. This is done so that hot-module reloading doesn't kick in in the middle of your debug session. Very convenient!

Let's go Vueing

The time has come to make a real test that uses Vuejs. So let's create one in test/unit/components/Clicker.js that will check if upon clicking on the component a custom event will be emitted:

import Vue from 'vue'
import { mount } from 'vue-test-utils'

import Clicker from '@/components/Clicker.vue'

describe('Component: Clicker', () => {
  it('will emit "clicked" event when interacted with', () => {
    // given
    const wrapper = mount(Clicker)

    // when
    wrapper.vm.$el.click()

    // then
    expect(wrapper.emitted().clicked).to.deep.equal([ [ 'Here!' ] ])
  })
})

Now in the root folder let's create src/components and inside that let's create our component as a single-file component Clicker.vue:

<template>
  <h1 @click="$emit('clicked', 'Here!')">Hello!</h1>
</tempalte>

That's it! It is really that simple!

Post scriptum

This barely scratches the surface of what is possible with Poi but at the same time it does cover a lot of configuration that you don't need to write yourself. Just looking at the starter template for webpack-simple shows how much is being done behind the scenes.

Happy testing!

Tuesday, November 14, 2017

Making xdg-open use Chrome instead of Firefox

One of the more annoying things in Linux Mint that I came across is the fanatic persistence of using Firefox to open links after making Chrome the default browser. I know, I know... Google spying, I'm giving up privacy to some corpo that will do evil things with my sexual preferences, yadda, yadda, yadda - I don't care. I want my links to open in Chrome. Period.

Recently I came across a post on askubuntu.com that explains what needs to happen. Basically all URL opening mechanisms are using xdg-open underneath the covers so all it takes is to teach it the lesson it needs:

$ xdg-mime default google-chrome.desktop text/html
$ xdg-mime default google-chrome.desktop x-scheme-handler/http
$ xdg-mime default google-chrome.desktop x-scheme-handler/https
$ xdg-mime default google-chrome.desktop x-scheme-handler/about

Done. Now ctrl-click any links in the console and you'll have that opened in Chrome.

Happy clicking!

Saturday, October 28, 2017

Poi that!

You might already be familiar with Webpack. It's a great tool and a bastard when it comes to configuration. It's a beast! It's a daemon! It's one of those sons of bitches that you can't loose and that will hunt you down everywhere you go. Like a woman! Just look at the amount of configuration code that the vue-cli produces when used in combination with the webpack template. That is right down INSANE!!!

Although there's not much that can be done with woman, Webpack has received a shell that is finally making some sense! That shell is called POI and is created by a gentleman who goes by the name of Egoist. Let's take a closer look at what it does.

At first glance it is a simplified build tool. One that you would probably never look upon knowing what kind of power Webpack brings to the table. But if you look a bit closer it turns out it is just (easier said than done) a box around webpack configuring it to some standards using a set of predefined presets for the most common tasks. However, knowing what kind of a daemon sits in the guts of it, you'll be pleased to know that poking around that dragon is very much possible and easy at the same time.

So what does it look like to use it? First you need to know that Poi stems from the ashes of a slimming treatment of vue-cli. This means it will out-of-the-fricken-box work just perfect with Vue.js! All you need is a file that will bootstrap your application. Let's see the content of an index.js that does it.

import Vue from 'vue'
import App from './App.vue'

new Vue({
  el: '#app',
  render: h => h(App)
})

And then the single-file-component App.vue

<template>
  <h1>Hello, world!</h1>
</template>

You can obviously put everything else in there (the <script> and <style> sections for example).

Now let's see how do we actually use Poi with that nice application. First of all you need to install Poi. For the sake of this oversimplified and butt-ugly example we'll perform the worst voodoo magic ever and install Poi globally. But please, beyond demonstration purposes NEVER EVER EVER EVER DO THAT. EVER. Poi is your build system so it must be part of your project. You have been warned!

npm install -g poi

Now having index.js and App.vue in that same directory run the following command:

$ poi index.js

# some useless output here

                               Asset       Size  Chunks                    Chunk Names
abf8058814c81f7a160b.hot-update.json   44 bytes          [emitted]         
                           vendor.js     1.5 MB       0             [big]  vendor
                           client.js    13.6 kB       1                    client
                         manifest.js    31.2 kB       2  [emitted]         manifest
ff42074b3ef0f4f41971.hot-update.json   35 bytes          [emitted]         
                          index.html  578 bytes          [emitted]         

> Open http://localhost:4000
> On Your Network: http://127.0.0.1:4000

 DONE  Build 664748 finished in 141 ms!

That is it! Nothing more, nothing less! You have access to everything that you would expected: Hot module reloading, bundling app in separate files so that the part that actually changes is not the whole package, an index.html that is automatically generated for you to host your application - you name it!

There is much more to poi than just running the project. For example to be able to run unit tests you need to start using poi presets. That's not very hard - requires a few more packages though.

$ npm install poi-preset-karma karma-webpack karma-mocha karma-chai webpack mocha chai

With those packages installed we need to make Poi aware how to run tests. We do that by creating a poi.config.js like so:

module.exports = {
  presets: [
    require('poi-preset-karma')({
      frameworks: [ 'mocha', 'chai' ]
    })
  ]
}

That's really it! Nothing more! Just basically 4 lines telling that we would like to use karma with mocha and chai. Jeez! That is truly magnificent! Totally Vue.js-style! Now let's have the simplest test possible. All unit tests are to be stored in test/unit folder. This location can obviously be further configured but for now it will do just fine. So let's create test/unit/example.test.js like so:

import { expect } from 'chai'

it('will work', () => {
  expect(1).to.equal(1)
})

Having that in place let's run the tests!

$ poi test

# some useless output here

                    Asset    Size  Chunks                    Chunk Names
test/unit/example.test.js  925 kB       0  [emitted]  [big]  test/unit/example.test.js

 DONE  Build 78afa9 finished in 526 ms!

28 10 2017 13:22:30.310:INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:5001/
28 10 2017 13:22:30.310:INFO [launcher]: Launching browser Chrome with unlimited concurrency
28 10 2017 13:22:30.314:INFO [launcher]: Starting browser Chrome
28 10 2017 13:22:30.892:INFO [Chrome 62.0.3202 (Linux 0.0.0)]: Connected on socket BUV....
  ✔ will work

Finished in 0.002 secs / 0 secs @ 13:22:31 GMT+0200 (CEST)

SUMMARY:
✔ 1 test completed

Now ain't that a pretty! I myself was looking to simplify the use of webpack for quite some time and it is only my bad luck that I didn't run into poi sooner. I would have saved a whole lot of time! Tumbling down the rabbit hole if you would like to run those tests in headless mode you can specify the browser to use. I like headless Chrome:

$ poi test --browsers ChromeHeadless

Boooom! Your tests can now be executed in headless environments like CI! That is so easy and soooo exciting!

Want to do some code coverage?

$ poi test --coverage

# some useless output here

                    Asset    Size  Chunks                    Chunk Names
test/unit/example.test.js  925 kB       0  [emitted]  [big]  test/unit/example.test.js

 DONE  Build 78afa9 finished in 508 ms!

28 10 2017 13:46:33.489:INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:5001/
28 10 2017 13:46:33.489:INFO [launcher]: Launching browser ChromeHeadless with unlimited concurrency
28 10 2017 13:46:33.493:INFO [launcher]: Starting browser ChromeHeadless
28 10 2017 13:46:33.747:INFO [HeadlessChrome 0.0.0 (Linux 0.0.0)]: Connected on socket 9Xjcc...
  ✔ will work

Finished in 0.006 secs / 0.001 secs @ 13:46:33 GMT+0200 (CEST)

SUMMARY:
✔ 1 test completed
----------|----------|----------|----------|----------|----------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines |Uncovered Lines |
----------|----------|----------|----------|----------|----------------|
----------|----------|----------|----------|----------|----------------|
All files |      100 |      100 |      100 |      100 |                |
----------|----------|----------|----------|----------|----------------|

So one last thing that we need is to deliver our super duper app to some hosting. scp-ing files is not the task for Poi but building those files is and Poi does it very well:

$ poi build index.js

You will end up with the dist folder containing everything. One property of the created files is that they use absolute paths for resources like scripts and styles. It's great when it comes to hosting but trying it out using the file:// protocol (simply opening the index.html file in the browser) won't work. But it is very easy to fix. In poi.config.js add the webpack method like so:

module.exports = {
  // ...
  webpack(config) {
    config.output.publicPath = ''
    return config
  }
}

Now run the build again and open the resulting index.html file in the browser. Boom! It works!

There is way more to Poi than that. Check out the official documentation at http://poi.js.org and the GitHub page at http://github.com/egoist/poi. You will be amazed what's in store!

Happy... poi'ing!

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!

Thursday, May 18, 2017

Vue, Vue CLI, Webpack template, Nightwatch and page obect pattern

Today I tried to use the page object pattern with Nightwatch.js that is created when using the webpack template in vue-cli. It turns out they are not configured by default. This means you need to add

page_objects_path: ['test/e2e/pages'],
to your tests/e2e/nightwatch.conf.js file to start using it.

The usage scenario is quite simple

  1. Create a file describing the page
  2. Use it in a test

Everything you need to know about page object pattern and Nightwatch is here so don't hesitate to check it out. Here's a basic example, the initial e2e test created when the app was scaffolded, but this time rewritten using page object patter.

// For authoring Nightwatch tests, see
// http://nightwatchjs.org/guide#usage

module.exports = {
  'default e2e tests': function (browser) {
    // automatically uses dev Server port from /config.index.js
    // default: http://localhost:8080
    // see nightwatch.conf.js
    const devServer = browser.globals.devServerURL

    browser.page.home()
      .open(devServer)
      .assertMainContentPresent()
      .assertHeaderText('Welcome to Your Vue.js App')
      .assertMainLogoPresent()

    browser.end()
  }
}

And now the page definition in tests/pages/home.js:

module.exports = {
  elements: {
    container: {
      selector: "#app"
    },
    hello: {
      selector: ".hello"
    },
    title: {
      selector: "h1"
    },
    logo: {
      selector: "#app > img"
    },
  },
  commands: [ {
    open(url) {
      return this
        .navigate(url)
        .waitForElementVisible('@container', 5000)
    },
    assertHeaderText(content) {
      return this.assert.containsText('@title', content)
    },
    assertMainContentPresent() {
      return this.assert.elementPresent('@hello')
    },
    assertMainLogoPresent() {
      return this.assert.elementCount('@logo', 1)
    },
  } ]
}

Basically a page object is what a module exports. It is divided into 3 sections

  • elements - definition how to find certain elements
  • commands - pieces of work the page does
  • sections - (absent in this example)grouping mechanism for definitions

That's it

Wednesday, May 17, 2017

Performance of frontend frameworks

This is going to be just a quick note to myself

Don't base your choice on performance only. Currently pretty much all frameworks yield similar results (yes, even Ember is catching up with Glimmer, even though it is still slower than the other ones from the big 4). Use common sense, which is not so common, and let the simplicity and flexibility of use be your guiding star. If however the performance is not acceptable from the start and the framework doesn't have you on your knees begging to use it then just don't go for it.

Even though Ember is getting faster (I just threw up in my mouth a little bit) it doesn't mean it is sane to use it in any project of any size with Vue, Angular and React being out there

Happy coding

Monday, May 1, 2017

Vue directive NAME/V

Have you ever tried to remember the elements of a Vue's directive? But there are so many of them! Don't worry - they are very easy to remember!

Name - the part that comes right after "v-"

Argument - the part that comes right after the colon

Modifiers - the part that comes after dot

Expression / Value - the expression put inside the parameter value and the evaluated value

NAME / V - for short

Happy coding!

Tuesday, April 4, 2017

Recording screencast with Atom and Firefox

The need

I have recently started work on a video course about VueJS. The major part of it are screen recordings. I went through the original documentation my editor provided and it was just for Win/Mac (no surprise there) so I needed to go and figure it out for myself.

The how

As it turns out recording screen on Linux is quite easy. There are lots of good applications for it. I went with the good old ffmpeg

$ Xephyr :1 -ac -screen 1280x720 -br -reset &
$ sleep 2
$ setxkbmap -display :0 -print | xkbcomp - :1 &> /dev/null
$ DISPLAY=:1 evilwm -snap 50 &
$ DISPLAY=:1 atom &
$ DISPLAY=:1 firefox &

Now that we have all the apps running in a nice enclosure let's record the action:

$ ffmpeg \
    -f pulse -ac 2 -i default \
    -f x11grab -r 25 -s 1270x720 -i :1 -c:v libx264 \
    "./$(date).mp4"
This will create a new file with human readable timestamp each time you run this command encoding the 720p video in h.264 format and audio in AAC putting it all into an MPEG4 container.

Making Atom captures easy to edit

When editing the video in post production, for example using Blender's NLE, it is hard to fit the blinking intervals when cutting parts of the video. For that reason I recommend disabling the blink cursor in Atom. Select "Open your stylesheet" menu item and enter the following snippet

atom-text-editor.editor .is-focused .cursors .cursor {
  opacity: 1
}

That's it. Now the cursor is solid and editing is easy again

Happy recording!

Saturday, March 4, 2017

Sending logs from NodeMCU/Lua to Graylog2

Graylog2 is a great product. It might not be the most sophisticated one when it comes to log aggregation and interrogation, but it does its job very well. After employing Graylog2 to collect logs from all my Docker containers I thought that it would be absolutely fantastic to be able to manage logs from the IoT devices as well.

Installing the right input plugin

Before we can push stuff into Graylog2 we need to teach it the protocol of IoT devices - MQTT. Luckily enough there is a ready-made and supported input plugin just for that. To install it simply download it to the plugin folder in your Graylog2 installation and restart Graylog2. Done.

The next thing is to add an input for MQTT. Select System/Inputs and then create an input by selecting MQTT TCP (GEFL) from the drop-down list of available connectors. You need to specify the MQTT server and queue which the connector will subscribe to. In the example below I used system/logs so if you would go for a different name you need to adjust the code accordingly. And last but not least you need to start the input by pressing the Start input button. Done.

Programming in Lua

Lua and the NodeMCU environment is a beautiful thing. It is simple, powerful and it just rocks. For our little project we'll need to build ourselves a version with bmp085, cjson, wifi and mqtt modules. Then we need to download it to the module and we're all set to start coding in Lua.

The code here initializes WiFi connection, once the connection is established connects to the MQTT server, initializes the BMP085 sensor (here we're using pins D2-sda and D1-scl as per the documentation) and sets up a recurring alarm every second to read the sensor and send GEFL-formatted logs if MQTT has been connected. Easy.

Transferring files to NodeMCU

There are many great ways to send Lua files to the module. I like to use the one written in NodeJS called nodemcu-tool

$ npm install -g nodemcu-tool
$ nodemcu-tool upload init.lua
$ nodemcu-tool terminal

Now press the reset button and your NodeMCU should inform you of 3 things:

  1. That it connected to WiFi network and has an IP address
  2. That it has connected to the MQTT server
  3. That it is sending logs to MQTT server
There is not much more to it. Give it a try and if you stumble upon any challenges getting it to work feel free to leave a comment.

Happy logging!

Spring Boot application with Graylog2

I have been looking for an alternative to Splunk for a while and recently I have stumbled upon Graylog2. It is a very advanced tool well worth looking at. I decided to do a minimalist Spring Boot project to test its capabilities

The configuration

There are 2 steps required in order to get the logs to Graylog2:

  • Adding an artifact with GEFL appender
  • Adding the GEFL appender
I have tried 2 different GEFL appenders: Logback-gelf v0.10p1 which did work but didn't give me all the necessary details into Graylog2, and logback-gelf that worked for me very well.

I added the dependency to my pom.xml as follows

<dependency>
    <groupId>de.siegmar</groupId>
    <artifactId>logback-gelf</artifactId>
    <version>1.0.3</version>
</dependency>

And then added a logback configuration file to my resources

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml" />

    <appender name="GELF" class="de.siegmar.logbackgelf.GelfUdpAppender">
        <graylogHost>localhost</graylogHost>
        <graylogPort>12201</graylogPort>
        <layout class="de.siegmar.logbackgelf.GelfLayout">
            <originHost>localhost</originHost>
            <includeRawMessage>false</includeRawMessage>
            <includeMarker>true</includeMarker>
            <includeMdcData>true</includeMdcData>
            <includeCallerData>true</includeCallerData>
            <includeRootCauseData>true</includeRootCauseData>
            <includeLevelName>true</includeLevelName>
            <shortPatternLayout class="ch.qos.logback.classic.PatternLayout">
                <pattern>%m%nopex</pattern>
            </shortPatternLayout>
            <fullPatternLayout class="ch.qos.logback.classic.PatternLayout">
                <pattern>%m</pattern>
            </fullPatternLayout>
            <staticField>app_name:backend</staticField>
            <staticField>os_arch:${os.arch}</staticField>
            <staticField>os_name:${os.name}</staticField>
            <staticField>os_version:${os.version}</staticField>
        </layout>
    </appender>

    <root level="trace">
        <appender-ref ref="GELF" />  
        <appender-ref ref="CONSOLE" />
    </root>
</configuration>

This gave me all the logs into a local instance of Graylog2 running on Docker.

version: '2'
services:
  mongo:
    image: "mongo:3"
  elasticsearch:
    image: "elasticsearch:2"
    command: "elasticsearch -Des.cluster.name='graylog'"
  graylog:
    image: graylog2/server:2.2.2-1
    environment:
      GRAYLOG_PASSWORD_SECRET: somepasswordpepper
      GRAYLOG_ROOT_PASSWORD_SHA2: 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
      GRAYLOG_WEB_ENDPOINT_URI: http://127.0.0.1:9000/api
    depends_on:
      - mongo
      - elasticsearch
    ports:
      - "9000:9000"
      - "12201/udp:12201/udp"
      - "1514/udp:1514/udp"

Happy logging!

Monday, January 23, 2017

Creating an LTSP Server on Linux Mint

I wanted to try this out for ages but somehow I have never done it. Last weekend I decided to give it a go and to create an LTSP server and a thin client that'll start over PXE with no disk, floppy, USB stick or CD/DVD. It turned out to be quite simple but a few quirks made me wonder for a bit what the hell is going on. Here's a log of those things.

DHCP starts, TFTP from a live CD works but TFTP from PXE times out

That happens when using NAT network in VirtualBox. They are broken. Use 2 cards on the server, one in whatever mode you want, that will connect to the internet (I use bridged or NAT - both work fine) and for the second card use an internal network.

The server needs to have them properly configured. Leave the first one that's bridged to get its config using DHCP and the second one configure to have a static IP address (e.g. 192.168.67.2), netmask of 255.255.255.0 and NOTHING ELSE. For the client setup just one network card connected to internal network (same as for the server) and leave everything else be.

By the way, I used 2 different types of virtual network cards: Intel for the bridged one and AMD for internal network. The AMD card starts faster over DHCP :)

The /etc/ltsp/dhcpd.conf file needs to be updated accordingly. For the 192.168.67.0 network I have configured mine as follows:

authoritative;

subnet 192.168.67.0 netmask 255.255.255.0 {
    range 192.168.67.20 192.168.67.250;
    option domain-name "example.org";
    option domain-name-servers 8.8.8.8;
    option broadcast-address 192.168.67.255;
    option subnet-mask 255.255.255.0;
    option root-path "/opt/ltsp/i386";
    if substring( option vendor-class-identifier, 0, 9 ) = "PXEClient" {
        filename "/ltsp/i386/pxelinux.0";
    } else {
        filename "/ltsp/i386/nbi.img";
    }
}
I have removed option routers ... and next-server [...] options because they are not necessary as I am not connecting the client to Internet (everything runs on the server) and I am running TFTP on the same host with DHCP server.

On Linux Mint "Reached target Graphical Interface." but nothing happens

This one is easy but not obvious if you have done LTSP on Ubuntu. After the initial creation of image (ltsp-build-client [...]) install virtualbox' X11 guest driver like so:

$ sudo ltsp-chroot -p -d apt-get install virtualbox-guest-x11
And then update the image as usual:
$ sudo ltsp-update-image
On Ubuntu-based servers those drivers get installed automatically. Very weird...

Fucked up client display

If you will see a display that is sort of hacked in half horizontally and then vertically with things looking like it's Picasso's fantasy then your client has either too much graphical memory, 3D acceleration enabled or too few MBs of RAM. I set my client VM to have 1GB RAM, 128MB video RAM and 3D acceleration enabled but your mileage might vary. Before you do anything just add RAM - that should help

The client started - what's the username and password?

This one is really tricky if you don't know what LTSP is all about. Essentially LTSP client is Linux with X11 and SSH client bound to your server. So whenever you are logging in use the same account as on server. If you need more users - add them to the server. And remember: all apps are not running on the client - they run on the server! This is why a Raspberry Pi works great as an LTSP client. I love it!

I have checked Linux Mint XFCE, Ubuntu 16.04.1, LUbuntu, Ubuntu Mate - they all work great. If you're a RedHat/Fedora fan you're on your own.

Happy LTSPing!