Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Wednesday, 1 May 2019

React: overkill with Redux and where Portals save the day



Recently I encountered a situation where I needed to overlay a div on top of another div. The standard way to do this is to use CSS and absolute or fixed positioning (https://stackoverflow.com/questions/2941189/how-to-overlay-one-div-over-another-div).

Sounds simple enough, however I need to do this from within a deep hierarchy of elements:

-> Detail Component
  -> Action Bar Component
  -> Items Component: Loop through and display expandable content divs
       -> On Click : overlay a component which is a div containing "expandable content"

The "items" component uses a standard bootstrap table to align the elements like so:
item 1 item 2
item 3 item 4

This layout means that when you select the onClick() for "item 1" and you render the expandable component which is essentially just a div, and it is positioned relatively the the content will appear in place of item one in the table.
item 1
(expandable content)
item 2
item 3item 4


Cut a long story short, every which way I tried to style the popup unwanted styles would be inherited from the table and other components above it. I also found that I had to place it absolutely to get the effect I was looking for which created a raft of further problems. Finally, it was suggested that this might be a good use case for React Portals which did indeed save the day.

I also learned on this project how much Redux can be over utilized. "When you have a hammer, everything starts to look like a nail". This was said a lot, and it should be, because when you are deep into the detail of a project it can be hard to see that it has been over-engineered.

Wednesday, 12 April 2017

Checking Out React

I started my journey at the React Tutorial Page. While reading the introduction and checking out the code example on Codepen, I then had the notion that seeing as it was a Tic-Tac-Toe game, it might be nice to do it more properly and include it on my website.

Once down this road I then decided it would be good to turn it into a mini project to find out more about yarn and webpack, as these compliment the React world and are the shiny new toys in front-end web development.

This first blog in the series is about the setup.

Notes on Yarn and WebPack
I have heard that Yarn is better than NPM as a package manager, it is faster and more reliable. Webpack is more complex/flexible than Grunt or Gulp as a builder tool but, like my personal favourite JSPM (through systemJS) it is an excellent JavaScript module loader out of the box. Webpack is much more popular than JSPM within the React community.

Back to Tick-Tac-Toe
So I used npm to install yarn, ran yarn init and then used it to bring down my dependencies React and React DOM. I was pleased to find that there is no difference in where the modules are stored - it is still in a folder called "node_modules". I was also aware that I needed to "transpile" the ES2015 React code into ES5 so I installed babel using the "webpack" option on the babel installation page.
npm install --save-dev babel-loader babel-core
Notice that this is based on npm, but this was no problem, you can just replace "npm install" with "yarn add" and the command "--save-dev" with "-D". This was all easy to find here.

Using Webpack to transpile ES2015 back down to ES5
After some research I have found that the best way to use Webpack with babel, karma and react is to use the following packages:



With this setup I was able to setup a simple "hello world" example. I will get into more detail with my next post.

Saturday, 19 November 2016

Isomorphic or Universal Javascript

Why I have decided to learn about this?
I first truly took note of the term "Isomorphic JavaScript" when a recruiter sent me through a job which I thought looked extremely interesting. At the time I was not looking for a job, but it reminded me about the long standing problem with decent SEO and Single Page Applications (SPAs). I had heard a lot about React and Angular 2 providing some way to solve the problem, so I was curious.

Notably, the company in question were listing some other design patterns and technologies which were new to me and were also of interest: 12 factor app, Mesos and Marathon, CircleCI.

Godammit man, what does Isomorphic mean!
Isomorphic means "corresponding or similar in form". So essentially we are describing some sort of server side rendering to support the client side application.

Or as the AngularJS Universal Repository puts it: "A JavaScript Application that runs in more environments than just the browser".

The advantages?
  • The application does not need to rely on JavaScript being turned on in the browser for it to function
  • The application does not need to have a loading gif to explain to the user that patience is required
  • THE BIG ONE - The application can be more easily crawled by search engines because the page is also available from a static URL.
Some disadvantages and limitations
  • "Uncanny valley" - this is a term used to describe the time between the application appearing to be functioning and available and the time before it is actually responding to the users demands. This can be confusing for the user.
  • Loss of separation between back-end and front-end application code. However, I would say, in this API/ Micro-service architecture world, that this actually makes quite a bit of sense. The User Interface will still be separated from Business Logic, we are just blurring the line between server-side "Get" request responses and view rendering.
  • This is still just a bootstrapping technique and some SEO issues do still remain.
For a more thorough discussion on why Isomorphic JavaScript is "not the answer" take a look at this discussion on ycombinator (at your own risk of course!).

Sunday, 24 July 2016

Karma Error: You need to include some adapter that implements __karma__.start method






An error message which means very little. Something has gone wrong with Karma and it is affecting mine!

It looks like some breaking changes made in Karma-Runner 1.0.0 have really screwed over all the plugin projects such as Karma-Jasmine which I very much rely upon.

The only way around it at the moment is to downgrade Karma to 0.13.22 until Karma-Jasmine is compatible with v1.x.x versions of Karma.



v1.0.0

@dignifiedquire dignifiedquire released this on Jun 23

BREAKING CHANGES

  • context: Our context.html and debug.html structures have changed to lean on context.js anddebug.js. This is in preparation for deeper context.js changes in #1984.
As a result, all customContextFile and customDebugFile options much update their format
to match this new format.



Hmm clear as mud huh?

Certainly I will be keeping a close eye on this issue to see when I can upgrade safely.

UPDATE: It looks as though this has been fixed - all the errors related to this were consolidated in issue 2194 and released just days after I wrote this post.

Friday, 1 April 2016

Setting up Karma to play nice with JSPM

The TL;DR version

I was getting quite frustrated with unit testing today because when I was attempting to use ES6 features like Array.find I was greeted with errors like this one.

TypeError: undefined is not a constructor (evaluating 'categories.find(function (cat) {
                                return cat._id === id;
                            })') (line 19)


I noticed I was also getting a message like this in my stack trace:

tryCatchReject (http://localhost:9876/base/jspm_packages/system-polyfills.src.js

Why couldn't SystemJS load polyfills? It was managing it fine in my browser, at least that is what I assumed.

I made a mistake and thought that I must need to pre-process my unit tests so that they become babelified or ES6 ified or JS2015 ified etc...

I started looking at this...
https://github.com/babel/karma-babel-preprocessor
This made it worse because I was trying to re-implement using a different tool the same task which is being undertaken by JSPM and SystemJS.

In the end the answer was rather than keep adding configuration, strip out configuration and then add just one extra line.

I actually found this tip/clue from the karma-babel-preprocessor configuration page.

Polyfill

If you need polyfill, make sure to include it in files.
npm install babel-polyfill --save-dev
module.exports = function (config) {
  config.set({
    files: [
      'node_modules/babel-polyfill/dist/polyfill.js',
      // ...
    ],
    // ...
  });
});
I added the line above to the files array and "hey presto" all my unit tests were working fine with array.find. To prove that "karma-babel-preprocessor" was not needed I uninstalled it and re-ran my tests.

I later found that I also needed to reference babels polyfill.js in the client-side code that was using the find method.

The only reason I had not noticed was because Chrome has a native implementation. However MS Edge and all other IE browsers do not, so nothing worked on those browsers - a dead giveaway. I added this line to the files in question:
import "babel-polyfill";
See: https://babeljs.io/docs/usage/polyfill/

I found later that sometimes the unit tests would still crash PhantomJS. The final solution to this was to split the specification files from the implementation files using the following from karm-jspm:

jspm: {
    loadFiles: ['test/**/*.js'],
    serveFiles: ['src/**/*.js']
}

The theory being that you don't need to load the actual files to be tested until you have initially loaded the tests themselves.

I think it is fair to say that sometimes Karma does not like to play nicely with JSPM, although this does seem to depend on your project structure as well. I hope these little tips either help to resolve an issue or go someway to alleviate some confusion.

Monday, 12 October 2015

ES6 or JS2015 is finally here!

Short post this time. I have been away from the Javascripot space for a little while, but now I have started a new NodeJS project.

I am incredibly excited about the wide spread adoption of ES6 this year and I have to say that VS Code has just made me incredibly happy. Not only does VS Code give ES6 intellisense but by telling the IDE that you wish to compile in ES6 you can stop it giving red squiggly lines as well. Fantastic stuff. Just add a jsconfig.json file with the following:

{
    "compilerOptions": {
        "target": "ES6"
    }
}

The only bad news is that surely I have to remember which features have actually been implemented by the V8 engine.

Well again I was very happy to discover that there is not a great deal left. The only proviso is that you have to run node --harmony which something you can alias in you command line runner of choice.

The other option is to run babel. In the end I have settled on doing the following :

  • npm install babel  
  • Add require(("babel/register") to the server.js file
The advantage of this approach is that I do not have to remember to write a custom build script with the correct parameters.


Monday, 3 August 2015

A Basic Gulp Gotcha

Recently I have been incorporating gulp into my personal website project. For those completely unfamiliar with Gulp, it is a tool which can be used to primarily to amalgamate your css or javascript into a single file to reduce the number of web requests required to satisfy your various dependencies. Checkout this highly amusing slideshow comparing Gulp with Grunt, it also gives further detail as to why these sort of build tools are such a good idea. It is worth noting that minifying may not be necessary if utilising  HTTP/2 "server push" technology. However there are many plugins and use cases for Grunt which you may still find useful.

I configured my gulpfile.js to do just three things:
  1. Concatenate all files from a set directory into one file and put it in the build folder
  2. Minify the resulting JavasScript
  3. Rename the file, changing the extension to .min.js









Everything was working great. By simply running 'gulp app-build' from the command line I could produce a nice small file, perfect for a snappy web experience.

However, I came across some serious issues when trying to deploy the project to production. I tried adding Gulp to my Kudu deployment script like I had done to load my npm modules. I was frustrated when despite my insistent hacking (which went further into the early hours of the night than I would like to admit!) I kept getting the following error or similar:

When I came back to revisit this problem during a sensible time of day, I discovered my mistake.
This issue on Github was a particular givaway. My thanks to Matheiu Swiip. I had incorrectly assumed that gulp was a tool that I could make a part of my build.

UPDATE:
Having spoken to a colleague about this, it turns out that you can in fact use gulp as part of the build. But any dependencies marked as "dev-dependencies" in the npm package file. So all I need to do is move the ones I need for my build into the main "dependencies" area.

I don't think that anybody doubts the reasons for minfying JS files. But in case anybody is interested, this is the difference it made to my AngularJS app:

We start with:


And after minfication:

At 938KB and 123KB we can see that AngularJS itself is the biggest file.

When finally I got gulp working properly in my production environment and I had concatenated and minified my dependencies things started looking really peachy:




Wednesday, 5 November 2014

Asynchronous JavaScript programming in Node

I want to be able to read an atom feed!! This is NodeJS, so of course there is this great library for doing just that (feed-read), the feed function is asynchronous. I also want to use a Node abstraction in the form using Express modules.
Ok, no problem, I thought. I tried putting the feed directly in my server.js file. There was a simple problem - I don't have the blog data because feed-read has made an asynchronous call to gather the feed information leaving me with nothing.
Once I understood the problem I started searching for solutions. What generally comes up are yet more helpful libraries to help you 'deal with' the async 'problem'.
I am sure there are more complicated problems which may merit a complex library but I happen to know that this is something that JavaScript is great at. JQuery introduced the idea of a promise in version 1.5 and this is basically the same problem, with a similar solution. So the answer?

In my case chain callbacks. Yes, if you are using a function from an abstracted module, pass in a function which will then pass a function etc... When the function at the bottom of the chain passes us some data back we will be ready!! Use an API call to do this perhaps so we can give our users a spinner while they are waiting.
     var blogReader = { 
      GetMostRecentBlog : function(callback) {  
        feed('http://bloglocation.com/feeds', function(articles) {  
         var mostRecentBlogPost = articles[0];  
         var blog = {  
            Title: mostRecentBlogPost.title,  
            Content: mostRecentBlogPost.content  
         };  
         callback(blog);  
       }); 
    };  
    module.exports = blogReader;
    
    You then can use it like :
     blogReader.GetMostRecentBlog(function(blog) {  
       //use Blog object here for display  
     });  
    
I found this exact pattern in Mixu's Node book chapter 7 - http://book.mixu.net/node/ch7.html. He also talks about two other useful patterns to deal with asynchronous calls which may be useful on larger scale projects - Parallel and Limited Parallel patterns.

 As always, the code for my solution can be found on github.

Sunday, 14 September 2014

NodeJS progress and the mighty Bootstrap

Since writing my last post I have spent some more time with NodeJS.
Things I have done:

  • I created an API using Express using this article to create some bears - http://scotch.io/tutorials/javascript/build-a-restful-api-using-node-and-express-4) 
  • I added a favicon using this - https://github.com/expressjs/serve-favicon
  • I pondered Jade as my view engine and then quickly decided that Handlebars would be much easier as I was already very familiar - https://github.com/ericf/express-handlebars
As you can see progress is good. 

Unfortunately, next came the bit I always dread, trying to set out an effective design for the website. I struggle as a designer. At university I got familiar Photoshop and Illustrator, and while I really liked doing it at the time, sadly I have not kept up with the evolution of the software since. Luckily I can just prototype and see where it...

...Mild panic began to build.... oh god what about phones and tablets! As if deciding on a design isn't hard enough, I have to think responsive! Anyway - thank god for the kind people/companies of open source. Luckily we have Zurb Foundation and Bootstrap. Zurb Foundation is fantastic, but as I am already familiar with Zurb I thought I would use Bootstrap.

I am not going to bore you with all the details but provide you with my gotcha's list:

  • By default Node does not permit the public directory to be accessed. I wanted to do this so I could access the bootstrap files which were stored in public/libs. If you would like to store your bower packages in a custom directory rather than the default like me, create a .bowerrc file in your route directory with no file name, if unsure check this. Then add the following: 
    {
          "directory": "public/libs"
    }
  • To access the public directory for styles and scripts:
    app.use(express.static(__dirname + '/public'));
  • To use in your views:
    <script src="libs/bootstrap/dist/js/bootstrap.min.js"></script>
  • Use navbar-static-top rather than navbar-fixed-top. This is a new class as of Bootstrap 3.0, it addresses the problem wherein the navbar sits over the content of the page.