Monday, May 22, 2017

Updating Your Angular Yeoman Repo to ES6 NPM and Webpack

I inherited a project that was quickly put together as a proof of concept/demo that was created using the Yeoman Angular-generator.  While this was the preferred way of setting up projects a few years ago,  front end technologies and patterns have moved on.  Having recently come from a project that abandoned bower, gulp, grunt, and moved to ES6, JSPM, npm, and node scripts I knew I wanted to develop using ES6 and more importantly use a module loader.



Since I was starting the project fresh, I decided that removing grunt and bower would be a good way of understanding the codebase,  a good chance to learn Webpack, and finally to make sure that we were using the best practices in our front end code.  In the end the transition was fairly painless and made the code more in line with current practices.  

I've decided to do this with a website that I developed using the yeomen generator to show you the basic steps of converting such a project.  The website is live here: http://andy-meyers.appspot.com/#/, the yeoman generated repo is here https://github.com/thatguyandy27/Portfolio/tree/angular-yeoman, and the ES6ified repo is here: https://github.com/thatguyandy27/Portfolio/tree/es2016.  

So let's get started.  

1. Install Webpack and Other Loaders


The first thing we are going to do is add what we need to get webpack up and running using npm scripts.  Each one of these can be added using `npm install --save-dev <packagename>`.  Here are a list of the packages and their uses.  You may need more or less depending on your repo, like unit for unit testing, but this is the core stuff to get started.  


2. Create New Config Files


Next, we want to add a webpack.config.js file at our root directory.  Yours may need to be modified for testing, path directories, and other project specific requirements.   

We will also need to add a .babelrc file in our root that we will just populate with `{  "presets":["es2015"] }`.


3. Update Your Bower Dependencies to NPM Dependencies.  


This should be pretty straight forward.  For each bower package you should be able to add an npm package using `npm install --save <packagename>`.    After you are done we can delete the bower.json file and the bower dependencies folder. 


4. Create A Top Module File For the App 


Next we need an entry point for our application that will import your top level dependencies.  Ideally each component would import ONLY the dependencies that they require, but to get up and running quickly we can create a bootstrap file to import everything.  We will also want to create module files for each module in your application.  My application only has one module portfolioApp, but if yours has more you will do this for each module and then import those modules as dependencies to your top level module.

So my app-module.js file looks like this:

 
import angular from 'angular';
import 'angular-animate';
import 'angular-cookies';
import 'angular-resource';
import 'angular-route';
import 'angular-sanitize';
import 'angular-touch';
import appTemplateConfig from './app-templates.js';

const module = angular
  .module('portfolioApp', [
    'ngAnimate',
    'ngCookies',
    'ngResource',
    'ngRoute',
    'ngSanitize',
    'ngTouch'
  ]).run(appTemplateConfig);

export default module;


So a quick review of what is going on here.  First, I am importing the angular npm packages dependencies using the es6 syntax.  We then create our module and export it to be used later to register our controllers, services, components, etc.  I am also importing an appTemplateConfig function that will be run on load of the application.  We will get into this more later.


5.  Change JS Files to Import & Export


We now need to update our components to remove the dependencies on angular.  Ideally we would break the app into components, but I will leave that for a later exercise.  So for now I will have a controller-module.js,  service-module.js, and view-module.js.  All of our components will be imported here and registered as angular controllers, views, etc.  We also then need to update the component files to export the component to be registered.  Here is an example of one:

import THREE from 'three/three.js';
const ThreeJSPlanetCtrl = function($scope, planetService){
    ...
};
ThreeJSPlanetCtrl.$inject = ['$scope', 'planetService'];
export default ThreeJSPlanetCtrl;

The important thing here is that I didn't have to change most of the code. I now import any non-angular dependencies using the import syntax and use it as normal.  Finally at the end of the controller I use `$inject` syntax instead using something like ng-annotate.  We finally then export the function to be registered later on our module that we previously created.   Here is a controller-module.js that I created that will be used to register all of my controllers.

import '../libraries/OrbitControls.js';
import AboutCtrl from './about.js';
import BubblePopperCtrl from './bubblePopper.js';
import CanvasChessCtrl from './canvasChess.js';
import CssSolarSystemCtrl from './csssolarsystem.js';
import RelationshipEditorGOTCtrl from './relationshipEditorGOT.js';
import RelationshipMapGOTCtrl from './relationshipMapGOT.js';
import ThreeJSBubbleCtrl from './threejsBubbles.js';
import ThreeJSDemoCtrl from './threejsDemo.js';
import ThreeJSPlanetCtrl from './threejsPlanet.js';
import ThreeJSSolarSystemCtrl from './threejsSolarSystem.js';
import TransparentImageDemoCtrl from './transparentImageDemo.js';
import appModule from '../../app-module.js';

appModule.controller('threejsPlanetCtrl', ThreeJSPlanetCtrl)
    .controller('threeJsSolarSystemCtrl', ThreeJSSolarSystemCtrl)
    .controller('transparentImageDemoCtrl', TransparentImageDemoCtrl)
    .controller('AboutCtrl', AboutCtrl)
    .controller('bubblePopperCtrl', BubblePopperCtrl)
    .controller('CanvasChessCtrl', CanvasChessCtrl)
    .controller('CssSolarSystemCtrl', CssSolarSystemCtrl)
    .controller('relationshipEditorGOTCtrl', RelationshipEditorGOTCtrl)
    .controller('relationshipMapGOTCtrl', RelationshipMapGOTCtrl)
    .controller('threeJsBubbleCtrl', ThreeJSBubbleCtrl)
    .controller('threeJsDemoCtrl', ThreeJSDemoCtrl); 

This file imports the appModule that we defined in step #4 and then register every controller we have as an angular controller.  We will perform this step as many times as necessary depending on how your app is structured.

6. Create A Template Cache File


This is more of an optional step, so you could still use the native angular templating, but I have grown accustomed to importing templates as strings and attaching them to their components.  This is an intermediate step to that.  We are going to create the `app-templates.js` that was mentioned in step #4.  

import mainTemplate from './views/main.html';
import aboutTemplate from './views/about.html';
import bubblePopperTemplate from './views/bubblePopper.html';
import canvasChessTemplate from './views/canvasChess.html';
import cssSolarSystemTemplate from './views/cssSolarSystem.html';
import relationshipEditorGOTTemplate from './views/relationshipEditorGOT.html';
import relationshipMapGOTTemplate from './views/relationshipMapGOT.html';
import threejsBubblesTemplate from './views/threejsBubbles.html';
import threejsDemoTemplate from './views/threejsDemo.html';
import threejsPlanetTemplate from './views/threejsPlanet.html';
import threeJsSolarSystemTemplate from './views/threeJsSolarSystem.html';
import transparentImageDemoTemplate from './views/transparentImageDemo.html';


function templateConfig($templateCache){
  $templateCache.put('views/about.html', aboutTemplate);
  $templateCache.put('views/main.html', mainTemplate);
  
  $templateCache.put('views/bubblePopper.html', bubblePopperTemplate);
  $templateCache.put('views/canvasChess.html', canvasChessTemplate);
  $templateCache.put('views/cssSolarSystem.html', cssSolarSystemTemplate);
  $templateCache.put('views/relationshipEditorGOT.html', relationshipEditorGOTTemplate);
  $templateCache.put('views/relationshipMapGOT.html', relationshipMapGOTTemplate);
  $templateCache.put('views/threejsBubbles.html', threejsBubblesTemplate);
  $templateCache.put('views/threejsDemo.html', threejsDemoTemplate);
  $templateCache.put('views/threejsPlanet.html', threejsPlanetTemplate);
  $templateCache.put('views/threeJsSolarSystem.html', threeJsSolarSystemTemplate);
  $templateCache.put('views/transparentImageDemo.html', transparentImageDemoTemplate);
}

templateConfig.$inject = ['$templateCache'];

export default templateConfig;

All we are doing in this file is creating a function that has $templateCache injected into it and importing those templates to those paths that we are already using in the app.  We then export the function to be run in when the app loads.  This moves the importing of the templates from runtime to build time as the strings will be in the file already.


7. Create The App Entry File.  


In my webpack.config I have defined an entry point to the application that will bootstrap the entire thing.  Here is the snippet from the config. 

  config.entry = isTest ? {} : {
    ['app']: './app/app-main.js'
  };

This tells the app to use this file to bootstrap everything.  It will pull in the top level dependencies which will then pull in their dependencies all the way down the tree.

This file is pretty simple.  Here is what it looks like:

import './styles/about.scss';
import './styles/cssSolarSystem.scss';
import './styles/main.scss';
import './styles/relationshipEditorGOT.scss';
import './styles/relationshipMapGOT.scss';
import './styles/threejsPlanet.scss';
import './styles/transparentImageDemo.scss';


import './scripts/app.js';
import './scripts/services/service-module.js';
import './scripts/controllers/controller-module.js';
import './scripts/root.js';
import './scripts/libraries/OrbitControls.js';


It is just an import of the css styles and the top level application files.  If you have things that need to be run in order for some reason you can change that order here as well.  


8. Create Some NPM Scripts


We are going to add some basic npm scripts that can be run in place of grunt, gulp, etc.  These will all live in your package.js and can be run using npm run <command>.  Here are the scripts that I've added:

"scripts": {
    "build": "rimraf dist && webpack --bail --progress --profile",
    "server": "webpack-dev-server  -d  --history-api-fallback --inline --progress --port 9000",
    "test": "karma start test/karma.conf.js",
    "start": "npm run server"
}

We now have the following commands:

  • build: removes the dist directory and then tells webpack to build
  • server: runs webpack locally in dev mode
  • test: runs the karma tests
  • start: shorthand for server
You may need to add other commands as your setup may be different.  The important thing to note is you can use these commands to execute others.  So if your process has 4 steps you can have 4 indvidual commands and then one to call them in order.


9. Enjoy


Finally enjoy using your es6 syntax and start componentizing.


Sunday, October 2, 2016

Creating A Fancy CSS Button

I was in a meeting at work the other day where we were discussing our interview process for front-end developers.  We were taking a step back and trying to decide what exactly we were going to look for in our interview process and if we were finding those skills in the developers we were interviewing.  During the process the thought of interviewing for CSS was brought up and we started looking into some possible interview questions and stumbled across this website.
The first one is a simple question, but was really interesting.  People in the room seemed to think it was way too hard and I wasn't 100% sure how I would do it without internet access.  Here is the question:  Using CSS properties alone, recreate this button:

So I decided to take this as a personal challenge and ended up coming pretty close to it by just eyeballing the colors, spacings, etc.  It also took me way less time than I thought it would have and I learned a few things in the process.  Here is the end result:

Breaking it down, I started with the easies things first to get me going.  So I tackled the actual text of the button as my first thing.  To get the text to appear correctly, I knew the font-family needed to be a Sans-Serif, the font weight to be a bit on the bold size, to update the text color to a dark grey instead of black, and finally to just make sure whatever text in the button is uppercase.  Here is the css to do those things:

.button {

  text-transform:uppercase;

  color:#444444;

  font-family:sans-serif;

  font-weight:bold;

  font-size: 14px;

}



The next thing I decided to tackle was the stars.  The solution to this is to use a font-family, svg, or something else with before and after selectors.  If you haven't used them before check out the article about using after and before selectors.  I decided to use font-awesome in my solution because it had a star icon and I could just reference the CDN in my jsfiddle.   If you haven't used font icons before I wrote about it previously here.  I messed with the colors a bit and ended up with some pretty simple before and after selectors.

.button::before{

   font-family: FontAwesome;

   color:#999999;

   content: "\f005";

}




.button::after{

   font-family: FontAwesome;

   color:#999999;

   content: "\f005";

}


So now that the content is correct, the next thing was to take a stab at the background and the the first border.  So I added some padding to get the spacing of the button correct, and then went to work on the background.  I knew you could have gradients in css, but I hadn't used them in a while so I didn't quite remember the syntax.  I found some examples online like this and then created a gradient to the bottom with my 2 shades of gray.  Finally I added a simple boarder and some border radius and we are starting to look pretty good now.

.button{

  margin-left:10px;

  text-transform:uppercase;

  color:#444444;

  font-family:sans-serif;

  font-weight:bold;

  font-size: 14px;

  border-radius: 5px;

  border:.5px solid #aaaaaa;

  background: linear-gradient(180deg, #eeeeee, #aaaaaa);

  padding: 10px;

}


The last thing that was needed also the thing I was least certain about.  I was sure it could be done, cause otherwise why would the ask the question?  So I looked into box-shadow to see how that could be used and found something amazing.  It can be used N number of times!  So I finally had my solution.  I just needed a few different levels of box-shadow.  I needed one really dark layer around the border, followed by the larger light gray area.  Next I added a white gap followed by the final border.  Here is the final css for the .button class.

 
.button{

  margin-left:10px;

  text-transform:uppercase;

  color:#444444;

  font-family:sans-serif;

  font-weight:bold;

  font-size: 14px;

  border-radius: 5px;

  border:.5px solid #aaaaaa;

  background: linear-gradient(180deg, #eeeeee, #aaaaaa);

  box-shadow:  0 0 1px 1px #666666,

            0 0 0 6px #dddddd,

            0 0 0 8px #ffffff,

            0 0 0 10px #888888;

  padding: 10px;

}


Cheers!




Friday, September 30, 2016

Using Enzyme To Test React Components

With new frameworks comes new ways of testing things.  With Angular 1.x there were tools such as angular-mocks that were designed to try and make your life easier and test your components and directives efficiently and effectively.  For unit testing any front end ui code the ideal scenario would be to only render that specific component, but still be able to test that the correct properties are being passed onto any children components.  The inner workings, rendering, etc. of those children components are not the concern of the parent.  The true unit test concern is making sure that all needs of the children are being through the exposed properties.  Any actual rendering of multiple components and interaction is outside the scope of an actual unit and falls into a different category of testing.  This is something that the angular-mocks framework failed to do properly and is one of the major reasons we ended up abandoning use of it.

For react there is an amazing tool called enzyme.  My favorite feature is that you can test the component without rendering the children components!  It is called shallow rendering.  I'll walk through some quick samples of why this is great and how you use it.


So to get started, let's use the CustomList object that I had in my previous post.  Here is a link to the fiddle.  The code for the CustomList is as follows, and add a click function for each template to test a function.

class CustomList extends React.Component {

    render() {

        const ItemTemplate = this.props.itemTemplate || DefaultRow;

        return (
            <ul className="list-container">
            {this.props.items.map((item) => <ItemTemplate item={item} onClick={() => this.props.onRowClick(item)} />)}

            </ul>

         );

    }

}


So what do we want to test here?  One obvious thing is to make sure that there is an item row for each item passed into the list template.  So for each item passed in there should be an item for each one.

A simple test using jasmine might look like this:

it('should have an item template for each item', () => {
    const items = [ {id: 'id1'}, {id: 'id2'}, {id: 'id3'} ];

    const onRowSelect = jasmine.createSpy('onRowSelect');

    const component = shallow(<CustomList items={items} onRowSelect={onRowSelect} />);

    expect(component.find(ItemTemplate).length).toBe(3);

});

To break it down we are creating a shallow rendering of the component using JSX and pass in whatever properties that we might have if we were using with another component.

Now we want to test the properties of a component.  So let's use the same example and say each ItemTemplate should have an appropriate item.

it('should have a corresponding item property on each ItemTemplate', () => {
    const items = [ {id: 'id1'}, {id: 'id2'}, {id: 'id3'} ];

    const onRowSelect = jasmine.createSpy('onRowSelect');

    const component = shallow(<CustomList items={items} onRowSelect={onRowSelect} />);

    component.find(ItemTemplate).forEach( (itemTemplate, index) => {

        expect(itemTemplate.prop('item')).toBe(items[index]);

    });

});


Now that we have that, we might want to test the click events of each one and make sure they are correct.  For that we can 'simulate' a DOM event that would cause the onClick event to be fired.

it('should fire an onClick event for each row with the appropriate item' , () => {
    const items = [ {id: 'id1'}, {id: 'id2'}, {id: 'id3'} ];

    const onRowSelect = jasmine.createSpy('onRowSelect');

    const component = shallow(<CustomList items={items} onRowSelect={onRowSelect} />);

    component.find(ItemTemplate).forEach( (itemTemplate, index) => {

        itemTemplate.simulate('click');

        expect(onRowSelect).toHaveBeenCalledWith(items[index]);

    });

});


And there you have some simple tests using shallow rendering.
Cheers!

Friday, September 23, 2016

React Item Templates

With the future of Angular 1.x development coming to a head, our team started looking at other front end technologies that could potentially live side by side with angular 1.x and eventually (a long time down the road) replace our angular 1.x app completely.  We considered a few frameworks and ended up settling on React.js.

Shamelessly stolen picture from work HipChat room. 

One of the problems I recently worked on required a multi selectable list of items.  The catch was that I wanted to allow the template of the item to customizable while allowing for most of the functionality to be the same.  I realized that you could pass in a function as a property, and wondered why not a react component class.  It is essentially a function.  I tried it out and it ended up working.  Here is a JSFiddle with using that idea:




So in the container class, CustomList, I accept an optional parameter called itemTemplate.  It should be a function.  I then set a variable called ItemTemplate to be either the itemTemplate passed in or the DefaultRow class.  The key thing here to note is that you must make your ItemTemplate variable name capitalized.  React has a convention that you custom elements need to be capitalized.  I can then just pass whatever properties to each item instantiation and each one can format however they like.  Super Easy!

Monday, September 21, 2015

Learning ECMA Script 6: Arrow Functions

If you are familiar with a language other than JavaScript, there is a good chance that language already supports something similar to => functions.  In ES6 they are called arrow functions (or FAT arrow functions) and 9 times out of 10 they replace anonymous functions.  There is one major case where they differ, and I will get to that in my last point.




The first way to use an arrow function is the same any way you would use function (param1, param2, ...) { ... }.  Instead of that you would write the following:

   
(param1, param2, ...) => { ... }; 

It is pretty straight forward and it is shown in the example below:

var closureVariable = 'foo';
var test1 = () => {
    var innerVariable = 'bar';
    // look ma!  Closure still works.
    return closureVariable + innerVariable;
};

document.getElementById('test1').innerHTML = 'Test 1: ' + test1();


As you can see, no magic there.  It is simply replacing function (param...) with (param...) =>.  Most places you have anonymous functions are in callbacks and promises.  While it was super weird at first using them I found my code to be easier to read now (especially jasmine unit tests) and rarely write the word function anymore.

Now if you have a function that is one line and returns something, you can make the arrow function one line.  Imagine you were using the lodash function map that will "map" your current array into another one.  You just need to supply the function to transform each object.  Imagine you just wanted a property out of that array like name.  Before you would need something like this:

    
_.map(list, function(item){ return item.name;});


Now you can write this:

    
_.map(list, item => item.name);


item.name is implicitly returned since it is not surrounded with curly braces.



So you might ask, that's fine, but what if I want to return an object?  I need curly braces for that!  The answer is, Yes you do!  So to do this you would wrap your object in parenthesis and the above will still work.

So you would write the following:

    
_.map(list, (item) => ({ id: item.id, name: item.name}));





There one major difference between anonymous functions and arrow functions is how this is defined in the functionArrow functions now have Lexical this

What does this mean?  The easiest way would be to show you the difference in these two examples:

Suppose I have the following object.
  
var solarSystem = {
        planets: ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto'],
        star: 'Sun'
    };


Now I want to add some function to that object that does something to the array, and references some other property on the object.

    solarSystem.performOperation = function(){
        this.message = '';
        this.planets.forEach(function(p, i) {
            this.message += p + ' is planet number ' + (i + 1) + ' from the ' + this.star + '.  ';
        });
    };


What happens if you run this code? You will get the following:  

solarSystem.message === ''; //true

Why? This is because in the forEach function 'this' is defined as the window object. So the window object will have a message property on it that contains the following:  

window.message = 'undefinedMercury is planet number 1 from the undefined. Venus is planet number 2 from the undefined. Earth is planet number 3 from the undefined. Mars is planet number 4 from the undefined. Jupiter is planet number 5 from the undefined. Saturn is planet number 6 from the undefined. Uranus is planet number 7 from the undefined. Neptune is planet number 8 from the undefined. Pluto is planet number 9 from the undefined. ' 

 
However if you write the same code using arrow functions like in the fiddle below you will get the desired result.


Cheers!

Part 1 - Math & Numbers
Part 2 - New Parameter Features 

Tuesday, July 28, 2015

Learning ECMA Script 6: New Parameter Features

ES6 has a few new features when it comes to working with parameters.  To get these examples working, you most likely will have to use Firefox.

Pluto Hearts ES 6 Features

Default Parameters

Allowing for default parameters is a new feature being added into ES6, and are really simple to use.  When defining a function & specifying the parameters just add an equal sign and the value and you want to default it to and BAM! DONE!  So you would write your function like this: 
function defaultParam(foo = "bar"){};   
Now if the first parameter passed for foo is undefined then it will default to "bar".  However if it is null then it will be passed in as null!  Note that you can actually explicitly send in undefined it WILL use the default value.  You can also call functions to get the default value for a parameter, but be aware that the function will NOT be called unless undefined is passed in for that parameter.  

Rest Operator


The rest operator “…”is used when you define a function and works similarly to something like ‘varargs’ in Java or the ‘params’ in c#.  If placed before the last parameter in a function definition it turns it into an array and places all arguments that aren’t accounted for into the array.  You would write your function like this:
function restParam(foo, ...bar ){};  // bar is now an array



Spread Operator

The spread operator "..." is the same as the rest operator syntax wise, but used differently.  While the rest operator brings parameters together, the spread operator blasts arrays apart.  So the spread operator can be used to “spread” and array into individual arguments for a function call, or it can be used to “spread” an array out for use in another array definition.  It would be used like this:
function spreadParam(foo, bar){}; spreadParam(...["foo","bar"]);
One thing to note is that also works on strings as well.




Cheers!

Friday, July 10, 2015

Learning ECMA Script 6: Math and Number Features

At work we are currently preparing setting up our environment using tools such as babel to allow us to work with the newest JavaScript features without worrying about browser support.  So I am going to start taking a look at some of these new features and hopefully start incorporating them into my daily repertoire.

In this post I am going to take a look at the Number and Math features which are pretty easy, and mostly already implemented by modern browsers.


While Math can be scary, using these new features don't have to be.  We will start with the Number features and then move into the Math ones.

Numbers:

1. Support for octal and binary notation.  You can now specify numbers as octal (0o###), or binary (0b###);   So 8 (0o10) + 2 (0b10) + 10 + 16 (0x10) = 36



2. Support for octal and binary strings.  Since octal and binary formats are now supported you can pass those formats into the Number() function and it will convert it into an integer.  In the fiddle below the variables are converted to numbers using the Number function and we obtain the same result.


3. Number.EPSILON is a new constant that represents the difference between the smallest possible number greater than 1 and 1.  So essentially the smallest possible number that can exist greater than zero.  It represents 2.2204460492503130808472633361816E-16.  From what I can tell it is most useful in testing equality of decimals.  So instead of doing .3 - .2 - .1 === 0 (false) you can do Math.abs(.3 - .2 - .1) <= Number.EPSILON


4. Number.isInteger is a new function that lets you know if a number being passed in is an integer.  If it is not an integer or not a number then it will return false.


5. Number.isSafeInteger is similar to the function above, but also checks to see if the number is "safe".  Due to the way that numbers are represented in JS, there are max and minimum numbers that are "safe", and any numbers beyond that are potentially off.  What do I mean by "off"?  Essentially two or more integers beyond the max or minimum are represented by the same JavaScript integer.  Check out the third line in the fiddle below for wtf I am talking about.


6. Math.sign will return -1, 1, 0 (or -0....), or NaN based on the value passed in. 

7. Math.trunc will turn the number into an integer which will essentially round down if greater than 0 or round up if less than 0.



8. There are new trig methods such as Math.sinh, Math.cosh, Math.tanh, Math.asinh, Math.acosh, Math.atanh.  There is also a new Math.hypot function that calculates the square root of the sum of the objects. 

9.  There are also some new exponential and root functions available.  Math.cbrt returns the cube root of the number passed in.  Math.expm1 and Math.logp1 are similar to the Math.exp and Math.log, but from what I can tell by reading online they are more accurate when it comes to numbers close to 1. 

I believe that covers most if not all of the major changes in ECMA Script 6.  If I forgot something let me know and I will make sure to update the post.

Cheers!