The JavaScript Workshop
上QQ阅读APP看书,第一时间看更新

Frameworks versus Core JavaScript

So far, we've spoken a lot about why, how, and in what situations to use libraries. But we are yet to discuss when and why it would be a better idea not to rely on them.

First of all, all of the things that frameworks and libraries do can be done by ourselves. In a business context, or for the sake of development speed, however, we usually decide to buy them when facing the "make-or-buy" decision. But sometimes, we should keep in mind that adding external sources to our program or even founding it on top of these sources expands the amount of source code we have. Increasing the overall size of the necessary resources is particularly unpleasant for us JavaScript developers who build client-facing applications since we should be optimizing for delivering performance (how fast the app loads on the client). In general, more JavaScript code leads to the following:

  • Longer download times
  • Longer parsing times
  • More delayed execution
  • Potentially blocked rendering or usability of the app

Though we have complex optimization algorithms such as tree shaking or dead code elimination, which help us cope with huge bundle sizes in these cases, often, the better choice is to do the task at hand on our own.

Another aspect to consider is the security of our application. Some libraries or frameworks may open up attack vectors that we cannot control because we do not have full ownership or understanding of the involved code. However, the most popular libraries are concerned with the security of their packages and are also very fast at releasing patches for known vulnerabilities.

To provide an actual use case that spells out the negative impact a library or framework may have on our application, in the following two exercises, we will create a list and render it to the screen. The first one will make use of an external library, whereas the second one will be written in raw JavaScript.

Exercise 4.05: Rendering a List of To-Dos Using React

In this exercise, we're going to display a few list tags as bullet points of an imaginary todo list. To do so, we'll be using a massively popular library called react.js and its complementary react-dom.js. Let's get started:

  1. Create a new empty HTML file with a head and a div tag with the root ID inside the HTML body:

    <html>

      <head></head>

      <body>

        <div id="root"></div>

      </body>

    </html>

  2. Go to cdnjs.com and to get the latest react.js and react-dom.js CDN URLs and load the URLs into a script tag inside the HTML head:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.
    production.min.js" charset="utf-8"></script>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js" charset="utf-8"></script>

  3. Use react.js and react-dom to create three list items and render them to the root div-element:

      <script type="text/javascript">

        const todoListItems = [

          'buy flowers',

          'tidy up',

          'go to the gym'

        ];

        const todoListElements = todoListItems.map(item =>

          React.createElement('li', null, item)

        );

        ReactDOM.render(todoListElements, document.getElementById('root'));

      </script>

  4. Open the HTML page inside your browser and make sure that your todo list items are displayed correctly.
  5. Open the network tab of your browser's dev tools and have a glance at how many kilobytes of JavaScript was loaded:

Figure 4.11: Size of the JavaScript that was loaded into the Network tab

In this exercise, you learned where to find and how to use React.js. Although in this exercise you simply created a small, static list of To-Dos, React.js lets you create complex, dynamic UIs without you having to worry about native browser APIs that you would normally need to create such UIs. However, as we mentioned previously, using a framework also comes at a cost, measured in kilobytes.

Next, you will learn how to do the same task without React. Afterward, you will be able to understand the kilobytes versus complexity trade-off when building applications.

Exercise 4.06: Rendering a List of To-Dos without a Library

In the previous exercise, we used the trendy library known as React.js to load more than 37 KB (in ZIP format) and a couple of hundred bytes for the HTML, including the script tags, to create and render a list of three items. In this exercise, we are going to do the same thing, except we will utilize all the functionality that's already provided by the browser. Let's get started:

  1. Create a new empty HTML file with a div tag with an ID of root inside the HTML body:

    <html>

      <body>

        <div id="root"></div>

      </body>

    </html>

  2. Create a script tag and write some JS to create three list items and render them to the root div element:

    index.html

    4 <script type="text/javascript">

    5  const todoListItems = [

    6    'buy flowers',

    7    'tidy up',

    8    'go to the gym'

    9   ];

    10  const rootElement = document.getElementById('root');

    11  const listFragment = document.createDocumentFragment();

    12  todoListItems.forEach(item => {

    13   const currentItemElement = document.createElement('li');

    14   currentItemElement.innerText = item;

    15   listFragment.appendChild(currentItemElement)

    16   });

  3. Open the HTML page inside your browser and make sure your todoListItems are presented correctly.
  4. Open the network tab of your browser's dev tools and have a glance at how many kilobytes of JavaScript was loaded:

Figure 4.12: Loading the JavaScript's download size without using a library

There's exactly no, that is, 0 KB, additional JavaScript. That gives us 37 KB of downloading, parsing, and execution advantage over the method using react.js, all while achieving the same thing.

Of course, this is a simplified example. In general, real-world applications are more complex than our exercise. Nonetheless, you may often find yourself in an analogous situation where performance is a thing to consider and the task can plausibly be done using vanilla.js.

We have spoken in detail about what libraries and frameworks are and what they can help us to do. In order to really grasp what libraries may look like internally and how easy it actually is to build one, we'll be creating one ourselves in the following exercise.

Exercise 4.07: Creating a Library Yourself

Our library won't be capable of much at first, but you may want to put some effort into it and extend it as you wish.

HeadlineCreator.js is our library's name. It's a good name because it already hints at what it does; that is, it creates headlines. Technically speaking, our library will do the following:

  • Be accessible on the global window object of the current browser tab, just as we've seen with jQuery before: window.headlineCreator.
  • Provide a single method called createHeadline.
  • Allow us (through the createHeadline method) to create a headline with the given text and append it to a given parent element.
  • Take care of error handling for us, for instance, if we forgot to define some text to be displayed or passed an invalid selector for the parent element
  • To verify that our library is working and having an example of its usage, we will create, additional to creating the library itself, an HTML page including script tags using our HeadlineCreator.js library.

    Let's get started:

  1. Create an empty HTML file with a head tag, a body tag, and a div tag with an ID of root inside it:

    <html>

      <head></head>

      <body>

        <div id="root"></div>

      </body>

    </html>

  2. Load a local JS file with the name headlineCreator.js inside a script tag:

    <html>

      <head>

        <script src="./headlineCreator.js"></script>

      </head>

      <body>

        <div id="root"></div>

      </body>

    </html>

  3. Create the headlineCreator.js file inside of the same directory you created the empty HTML file in.
  4. Inside the JavaScript file, create an IIFE and assign it to the headlineCreator variable:

    // headlineCreator.js

    const headlineCreator = (function(){})();

    Note

    IIFE stands for "immediately invoked function expression." This sounds more complicated than it is. IIFEs are functions that are executed at the very same moment they are defined. One use case for them in frameworks or libraries is to prevent name collisions with variables that are used in the source code. This includes the library. For example, using a create function within your library can cause weird side effects since this is a very common and ambiguous name. Hence, the library could be a different function than it was supposed to be.

  5. Within the IIFE, create another function and name it createHeadline. This function takes two parameters, text and parentElementSelector:

    // headlineCreator.js

    const headlineCreator = (() => {

    function createHeadline(text, parentElementSelector = '#root') {}

    })();

  6. Inside the IIFE headlineCreator, add a return statement. This return statement will return an object with a single key named createHeadline that has the value of the same name (just like the function name we created in the previous step):

    {}return {

    createHeadline: createHeadline

      };;

  7. Extend the new function with a DOM query to look for an element with the parentElementSelector that is passed as an argument to the createHeadline function.
  8. Assign the result of the DOM query to a variable called parentElement:

    {{const parentElement = document.querySelector(parentElementSelector);{e;;

  9. Next, create an h1 tag element and set the innerText attribute of this element to the text parameter that is passed to the function:

    {{; const headlineToInsert = document.createElement('h1');

    headlineToInsert.innerText = text;}{e;;

  10. Lastly, append the created headline to the node that we stored in parentElement:

    {{;;;parentElement.appendChild(headlineToInsert);}{e;;

  11. Refresh your HTML page and inside the dev tools console, call the window.headlineCreator.createHeadline function with any parameter you'd like. Then, view the result:

    Figure 4.13: The window.headlineCreator.createHeadline function in the console and its output

  12. If you'd like to, you can add some error handling and return the newly created headline element since that's considered good practice in such a case:

    headlineCreator.js

    1 // headlineCreator.js

    2 window.headlineCreator = (function() {

    3   function createHeadline(text, parentElementSelector = '#root') {

    4     const parentElement = 5 document.querySelector(parentElementSelector);

    5    if (!text) {

    6       throw new Error('You forgot to pass the "text" parameter');

    7     }

    8     if (!parentElement) {

    9       throw new Error(

    10         `There was no node found for the Selector: "${parentElementSelector}"`

    11       );

    12     }

  13. To test the error handling, simply call the headlineCreator function without the text parameter:

    Figure 4.14: Error message in the console

  14. Last but not least, add a script tag to the HTML file and call the headlineCreator library from there so that every time the HTML is loaded, a headline is created:

    <html>

      <head>

        <script src="./headlineCreator.js" charset="utf-8"></script>

      </head>

      <body>

        <div id="root"></div>

        <script type="text/javascript">

          headlineCreator.createHeadline('This is the HeadlineCreator');

        </script>

      </body>

    </html>

    This results in the following output:

Figure 4.15: The HeadlineCreator.js library created

Going through this exercise has taught you that the inner workings of a library don't have to be complex and hard to understand. The headlineCreator library lets the user create and append a headline to a given parent element. Even though this is a simplified and almost trivial use case, it demonstrates the basic process of building and using a library – that is, having a programmatic problem, finding a solution to it, abstracting the complexity, and providing it to others through a library.

Activity 4.01: Adding an Animation to the To-Do List Application

In this activity, you have been asked to animate the todo list application that you have been building in the activities from the preceding chapters. Do so using one of the following three libraries:

  • jQuery
  • Velocity.js
  • Anime.js

The resulting todo list should animate the to-dos whenever you click the Shuffle button. It's up to you what exact animation you use, but nonetheless, I advise you to start with something simple, such as fading the to-dos.

The high-level steps for the activity are as follows:

Choose one of the frameworks. To gain a better understanding of how to use them, search for them online and have a look at their documentation (https://jquery.com, http://velocityjs.org, https://animejs.com):

  1. Go to cdnjs.com and get the jQuery CDN URL.
  2. Load the library into the head tag of your existing Todo-List-HTML using a script tag. This will enable you to use jQuery within your code.
  3. Inside activity.js, you need to change the todoEle variable. Change it to a jQuery element.
  4. Inside the replaceListElements function, you can now use functions on the todoEle element that jQuery provides to you.
  5. Hide and clear what's inside the element using the jQuery functions.
  6. Inside the for loop, create the liEle list item element, set the text contest, and append it to the listEle list element.
  7. Finally, slowly fade in the new sorted todo list, that is, listEle.
  8. Now, open the HTML in your browser and click the Shuffle button. The to-do list should fade out, shuffle, and fade in again. You will see the expected output.
  9. Now, we'll use the Velocity.js method. Go to cdnjs.com and get the velocity.js CDN URL.
  10. Load the library into the head tag of your existing Todo-List-HTML using a script tag. This will allow you to use velocity.js within your code.
  11. Inside the replaceListElements function, you can now use Velocity.js to hide (by setting opacity to 0) the list element, listEle, and then empty the elements inside of it.
  12. To fade the list element back in, animate listEle using Velocity.js and set the opacity to 1. Set the code after the for loop.
  13. Now, open the HTML in your browser and click the Shuffle button. The to-do list should fade out, shuffle, and fade in again.
  14. Finally, using the Animae method, go to cdnjs.com and get the Anime.js CDN URL.
  15. Load the library into the head tag of your existing Todo-List-HTML using a script tag. This will allow you to use Anime.js within your code.
  16. Inside the replaceListElements function, you can now use Anime.js to move (by using translateX = -1000) the list element, listEle, out of view and then empty the elements inside of it.
  17. To show the newly shuffled to-do list, use Anime.js to animate the listEle list element back into view (translateX = 0). Do so inside a timeout to ensure that the shuffling has been done already.

    Now, open the HTML in your browser and click the Shuffle button. The to-do list should fade out, shuffle, and fade in again. It should appear as follows:

Figure 4.16: Animated to-do list on click

Note

The solution to this activity can be found on page 719.