Tuesday, December 24, 2019

Swagger UI for ExpressJS

Swagger is a tool that allows to describe a service API. One of the reasons for that is creation of documentation for all API functions so make it easy to examine and navigate through. Even further, swagger allows to call the API functions in a simple manner like let's say Postman does. So working with ExpressJS I just discovered the swagger-ui-express library that gives us opportunity to build the swagger UI in literaly few steps. So I created the simplest possible example (Github Link) that will be be taken to pieces below step-by-step.

As usually, we start with installing the package npm install -s swagger-ui-express.

Now let's create a simple ExpressJS HTTP server with several CRUD functions.

const express = require('express');
const app = express();

const uuidv4 = require('uuid/v4');

//stores the books collection
let _books = [];

app.route('/api/book')
    .get(function (req, res) {
        res.json(_books.filter(b => b.id == req.query.id));
    })
    .put(function (req, res) {
        let book = JSON.parse(JSON.stringify(req.query));
        book.id = uuidv4();
        _books.push(book);
        res.json(book);
    })
    .delete(function (req, res) {
        _books = _books.filter(b => b.id != req.query.id);
        res.json(_books);
    })

app.get('/api/books', function (req, res) {
    res.json(_books);
});


// start the server in the port 3000
app.listen(3000, function () {
    console.log('Start app listening on port 3000.');
});

The service exposes functions allow to get/add/delete records (books) and retrieve all the books as well.

Next step is to display that API on UI.

Tuesday, December 3, 2019

Update styles in bulk via JavaScript

Updating an element style using javascript is pretty easy: document.getElementById(id).style.property = new style. But what if we have hundreds/thousands/.. elements to be updated? Calling the property setter above will force page re-rendering every time, so it would take considerable time. That's where bulk update is really helpful. Instead of applying styles after every change we can compose the css sheet with all the styles collected together and appy it at once.

Tuesday, October 29, 2019

Array.prototype.forEach() function does not await..

Recently I discovered that Array.prototype.forEach() function is not suitable for 'awaitable' functions. Let's have a look at an example.

const getAsyncData = (n) => {
   return new Promise((resolve, reject) => {
      setTimeout(() => resolve(n), 500)
   })
};

const arr = [1,2,3,4,5];

//forEach example
(async () => {
   let total = 0;
   arr.forEach(async n => {
      let res = await getAsyncData(n);
      console.log(res);
      total += res;
   });
  
   console.log('total = ' + total);
})();

I expected that forEach will await for every call of the getAsyncData() function so that to calculate total correctly, but surprisingly the result was different.

total = 0
1
2
3
4
5

Obviously, forEach ignores await keyword and quits immediately so total is not calculated.

Sunday, September 15, 2019

React create-react-app edit WebPack DevServer settings (adding SSL certificate options)

I have a React application that has been created with the create-react-app tool and I needed to change WebPack DevServer settings. Three the most popular suggestions I found on the internet were:
  • npm run eject
  • fork the react-scripts and make necessary changes
  • use a library like react-app-rewired
Unfortunately, all of them have various drawbacks (I will not discuss them here) and require too much effort. So finally, I found the simplest possible solution. The config file is here
'./node_modules/react-scripts/config/webpackDevServer.config.js'. Just edit the file here and that's it! For example, my task was to add an SSL certificate (.pfx). So for that I had to do 3 simple steps:
  1. Create a new folder security on the root app level and put the certificate file into it.
  2. Add the string HTTPS=true to the .env file. If you don't have the file, just create it on the root app level.
  3. Add the two options to the config file
Well, if you have another password for your certificate, update the pfxPassphrase field. If you have a different certificate type, the fields must be different. Reference to the official WebPack DevServer documentation, there is the entire option list https://webpack.js.org/configuration/dev-server/

But this solution has one drawback - the changes above are not saved when we delete node_modules folder and install everything from scratch with npm install.
I have found the simple fix for that - to make a script that overrides the config file when necessary.
  1. Create a new folder config on the root app level and copy the updated webpackDevServer.config.js file into it.
  2. Create a new script postInstall.js on the root app level and insert the following code inside it:
    const fs = require('fs');
    
    fs.copyFile(
        './config/webpackDevServer.config.js',
        './node_modules/react-scripts/config/webpackDevServer.config.js',
        err => {
            if (err) {
                console.error('Cannot copy webpackDevServer.config');
                console.error(err);
                throw err;
            }
    
            console.log('webpackDevServer.config is copied');
        }
    );
    
  3. Add the following line into the package.json file, scripts section: "post-install": "node ./postInstall.js"

So now, after npm install just run another command npm run post-install and that's it - your webpackDevServer.config file has been copied from the /config folder to the destination. Have a nice day!

Monday, July 8, 2019

jQuery autocomplete table

Jquery allows us to build really beautiful autocomplete box. For example, my task recently was to create a table-view autocomplete. That's what I made:



You can try it on JSFiddler:
https://jsfiddle.net/AndrewBuntsev/8jbqyrv4/

Thursday, June 20, 2019

Array.prototype.map(parseInt) tricky question

When I ran the following JS
['1', '7', '11'].map(parseInt);
I surprisingly saw the result [1, NaN, 3] instead of [1, 7, 11]. But if we try parseFloat
['1', '7', '11'].map(parseFloat);
the result is correct [1, 7, 11]
If we try the extended form of parseInt
['1', '7', '11'].map(i => parseInt(i));
we get the proper outcome as well.

So why is it so messy with the short parseInt?

Sunday, May 26, 2019

JavaScript string memory leak

If you create the following HTML file
<html>
  <body>
    <script>
      function createString() {
        return "0".repeat(25 * 1024 * 1024).substring(0, 12);
      }

      var arr = [];

      setInterval(function() {
         let str = createString();
         arr.push(str);
      }, 500);
    </script>
  </body>
</html>
run it in your browser and open the task manager you could notice that the browser takes some limited amount of memory ~200Mb. But what if we update one single digit in our code
return "0".repeat(25 * 1024 * 1024).substring(0, 13);
i.e. replace 12 with 13, run it into a browser and have a look at the process memory. It grows unstoppable and makes the browser crash in a half a minute! Why does it happen?

Every time we call String.prototype.substring function it returns new string instance that keeps .. a link to the original string! That's how V8 organizes memory for strings for permamance reason. Exception is when a new instance string length is less than 13 - in that case no link to original string preserved. So in our example arr contains no just short strings(13), but actually the huge ones (25 * 1024 * 1024). How to avoid it? Unfortunatelly, there is no documemnted method to 'cut' parents from strings, that's because we can do the following (update line 11):
<html>
  <body>
    <script>
      function createString() {
        return "0".repeat(25 * 1024 * 1024).substring(0, 12);
      }

      var arr = [];

      setInterval(function() {
         let str = createString().split('').join('');
         arr.push(str);
      }, 500);
    </script>
  </body>
</html>
That manoeuvre breaks the link with the original string and prevents memory leak.

Wednesday, May 15, 2019

Install NodeJS onto Ubuntu

The task sounds quite simple, but after I failed to do it several times I discovered that would be good to make a post about it. Just to have a step-by-step guide to save time when I decide to do it next time.

Firstly, let's remove old Node leftovers from previous installations
~$ sudo apt remove node
~$ sudo apt remove nodejs

and remove the node folder as well
~$ rm -rf node_modules/

That's time to download and install it in appropriate way. 

Sunday, May 5, 2019

React Tooltip Component published in NPM

Tooltip could be create with pure CSS, that's the example:
Such an awesome tooltip!

https://jsfiddle.net/AndrewBuntsev/jxk75o6c/

But I decided to go further and create a react component and publish it at NPM so that it could be reusable it other applications. That's the component HOC function implementation:

Saturday, April 20, 2019

React Lazy Routing

React routing is pretty straightforward and well documented feature. The example of usage is here
https://jsfiddle.net/AndrewBuntsev/3n5rmL0o/

If we need to load components only when they are needed we can utilize the code splitting techique with lazy() function and Suspense component

lazy() function loads the component no earlier than it is required
  
const Users = React.lazy(() => import('./Users'));

Suspense displays a loading component
  
render(
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <Users />
      </Suspense>
    </div>
  );

Tuesday, March 12, 2019

Upload Video in chunks with preview and progress bar using JavaScript

So, we have 3 following goals here:
  1. Preview video before it is uploaded
  2. Upload video file in small chunks
  3. Display a progress bar
All these tasks are achievable with JS and jQuery without any other libraries.
For choosing a video file we will use the standard input element
<input type="file" id="uploadVideoFile" accept="video/*" />
So to access the chosen file we will call
var fileInput = document.getElementById("uploadVideoFile");
To display video we need a video element
div id="videoSourceWrapper">
   <video style="width: 100%;" controls>
      <source id="videoSource"/>
   </video>
</div>
The following snippet displays the video after it is chosen in the video element for preview
$('#uploadVideoFile').on('change',
    function() {
        var fileInput = document.getElementById("uploadVideoFile");
        console.log('Trying to upload the video file: %O', fileInput);

        if ('files' in fileInput) {
            if (fileInput.files.length === 0) {
                alert("Select a file to upload");
            } else {
                var $source = $('#videoSource');
                $source[0].src = URL.createObjectURL(this.files[0]);
                $source.parent()[0].load();
                $("#videoSourceWrapper").show();
            }
        } else {
            console.log('No found "files" property');
        }
    }
);


As you can see, you can watch any video file having all necessary controls in the video player. Now let's have a look how to upload the video on your server.

Saturday, February 16, 2019

Sweet Alert Dynamic Content

Sweet Alert is really beautiful alternative for the boring javascript alert. And it is not just beautiful, it is very powerful popup that allows to do lots of awesome things. But in this post I will show just one feature how to change the popup content dynamically without opening a new popup or creating a popup queue. So let's start with the demo:



Let's have a look at the implementation.

Saturday, January 26, 2019

CSS Heart beating

We can make a heart with just css even having the only div.
  
<div id="heart"></div>

The most tricky part is to draw a heart. Luckily, it is pretty simple - it can be composed of 3 shapes - square and 2 circles. Square will be described with main css class, and 2 circles with ::before and ::after pseudo classes

And beating will be implemented with css @keyframe animation



Now let's have a look at the whole css.

Wednesday, January 23, 2019

JavaScript private fields

There is no private keyword in ES5 and ES6, so to create a private field we need to make up a workaround
  
function MyObj(val){
   let _val = val;
  
   return{
      getVal: function() { return _val; },
      setVal: function(newVal) { _val = newVal; }
  };
}

The MyObj(..) function is a factory that returns a new object every time we call it, so no necessary to use a new keyword. The object has 2 methods - getter and setter so that we can manipulate with the _val value
  
var o = MyObj(5);
console.log(o.getVal()); //5
o.setVal(8);
console.log(o.getVal()); //8

As long as _val is declared with the let keyword, it's impossible to access it directly from a different context
  
o._val = 10;
console.log(o.getVal()); //_val is still 8

o._val = 10 creates a completely separate property _val inside the object o, you can update it independently from our private field.

If for some reason you cannot use ES6, there is another solution:

Tuesday, January 15, 2019

JavaScript Array groupBy method

Array.prototype doesn't have any grouping functionality, so let's add the groupBy() method. Let's say we have the following array example:
  
var movies = [
                 {  
                   "Title": "Inception",
                   "Year": "2010",
                   "Director": "Christopher Nolan"
                },
                {  
                   "Title": "Interstellar",
                   "Year": "2014",
                   "Director": "Christopher Nolan"
                },
                {
                   "Title": "Avatar",
                   "Year": "2009",
                   "Director": "James Cameron"
                },
                {
                   "Title": "The Dark Knight",
                   "Year": "2008",
                   "Director": "Christopher Nolan"
                },
                {  
                   "Title": "Batman Begins",
                   "Year": "2005",
                   "Director": "Christopher Nolan"
                }
];

console.table(movies.groupBy('Director'));
The groupBy('Director') method should return 2 groups - 1st "Christopher Nolan" group and 2nd "James Cameron" group. Every group should contain the list of associated movies.

Now let's have a look at the method implementation.