JavaScript looks quite simple as compared to React. There are many advanced JavaScript features not even supported by many browsers yet. But they are being used in React.

Despite having so many differences, how does React work?

In this article, we will dive deeper to understand how does React configurations work. We will also see how do things come to action in React which are usually not possible in plain JavaScript?

When we start learning React, we don't have to worry about many things happening behind the scenes. In this article, we will understand how this works. And it will help us in troubleshooting issues when our project grows and scales.

We will be able to answer the following questions along the way

  • How do many new JavaScript features not supported by browsers work in React?
  • How do our JavaScript files get associated without HTML?
  • Despite having so many packages installed, how does the final React code executed on the browser is small?

Content

Creating simple HTML and JavaScript code with Github

Lets first start with a simple HTML file that uses some javascript files to show time spent on the webpage and current date.

We will be creating a folder and initializing git so we could push our code to Github and initialize npm so we could use it install dependencies later and also to host our files on the server later. Check this commit on how this can be done

  • We created index.html which has a simple div with id timeSpent that will be used to show time we have spent in index.js. To import index.js into this HTML page we have used script tag
  • Then we have updateTotalTimeSpent method in index.js which calculates total from startTime and updated the div using querySelector.
  • We updateTimeSpentRecursively method to call updateTotalTimeSpent method recursively after every half a second(i.e 500 ms) so values stay updated according time.

Now, if you copy your index.html file path and paste it in the browser you must see output attached in this commit.

Jump to Top

Adding multiple JavaScript files to HTML

Now we will see how another JavaScript file can be added to our HTML, and why it's not a feasible way of doing it when we need to add more and more JavaScript files, in this commit

  • Here, we added another div with id=date to display the current date. The date will be updated from the showDate method.
  • Every file that we add needs to have its own script tag in HTML and the overall load time of the HTML page will keep increasing.

We will also add an external dependency Moment.js now to see how it can be used in our HTML file.

  • We could directly use the Moment.js cdn link in a script tag like below
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.3/moment.min.js"></script>
  • But we will install moment using yarn to our app like below
yarn add moment
  • Now, we need to add a script tag to import moment functions into our js files and later re-use this library in our JavaScript file directly.

  • Now we will use moment to make the time formatting better in both our JavaScript files. Like below:

...
document.querySelector('#timeSpent').innerHTML = moment(startTime).fromNow(true);
...

...
document.querySelector('#date').innerHTML = moment().format("dddd, MMMM Do YYYY");
...

Check this commit to see all the file changes and output of our code.

Also, don't forget to keep trying Curious? Give this a try! code in these commits.

  • In React, we have everything in JavaScript files, so if we need to add a new HTML div as we did above, we create a new component in a new file so if we use this approach, the HTML file will keep growing. That's how it was done in the old days but now we have better ways.

Jump to Top

Re-organizing javascript files and libraries using Webpack for bundling

Let's organize our files a bit by moving our index.html to dist folder, why? Because it will be the file we will be least touching and will be directly consumed by the browser to render the webpage.

  • dist here stands for distribution and as a convention, it mostly contains compiled code/library which is meant to be used by the browser.
  • It is also named as public or build.

Code at this point looks like this and the output remains the same.

Now lets first add Webpack using yarn:

yarn add webpack webpack-cli
  • webpack here is the original package that will make all the above features available for us.
  • webpack-cli could be used to work with the Webpack from the cli.

After adding this package, our package.json will look like below:

 "devDependencies": {
    "webpack": "^4.41.2",
    "webpack-cli": "^3.3.10"
 }

There are many other advantages of using a Webpack which make overall code base optimized as per the development or production environment. We will learn more about them in the next commits with some code.

Webpack will help us solve many of the problems that we have been having in our project so far, few of them are:

  • Remove the need to add multiple script tags for every file we create.
  • Allow the file specific libraries to be imported in the file itself.
  • Import only those library files to be loaded which are needed in the file or our project.
  • Allow JavaScript files to be imported.
  • Compile all the JavaScript files into a single file which will be used by index.html

So, let's configure webpack using webpack.config.js file which will have the input code that Webpack needs to process and output path where the processed file needs to be stored.

We want to compile all our JavaScript code into a single file called bundle.js which will be created in the dist folder.

Please copy the webpack.config.js code from this commit

Since we have asked webpack to create a bundle.js of all our js files, let's tell index.html that we no longer have many script tags, instead only bundle.js will be enough to make sure all JavaScript code is available for index.html

Remove all script tags from index.html and place this tag

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

Now all the JavaScript code will come to index.html via bundle.js.

Also since we mentioned in webpack.config.js that index.js will be our entry point, we need to make sure all our JavaScript files are imported and invoked from index.js

  • Import showDate.js in src/index.js which will include showDate() in final bundle.js.
  • Import moment in files that need to use it instead of placing it in the script tag which made moment globally available in scope.
  • Also, add /dist/bundle.js in .gitignore so it's not pushed Github as we need to generate it every time we make any change.

We will need to run the following command to generate bundle.js for our js files.

./node_modules/.bin/webpack

Then paste the path of index.html in the browser and the web page should render.

Make the changes mentioned in this commit and also notice the correction to make this commit work.

Jump to Top

Allow cross-browser javascript feature support using Babel

In the last commit, we added Webpack which allowed us to use some modern ES6 JavaScript but that was because our browser already supported it, older browsers would not understand that syntax and would complain throwing an error.

We need to ensure that the browser supports the syntax we are using. Unsupported syntax should be gracefully handled and converted to syntax which is supported by all browsers, since it is not possible to test all browsers compatibility and this thing cannot be manual.

That's exactly what babel does, so to make sure our code in the last commit works on all browser we will install Babel with following commands and generate above code:

yarn add @babel/core @babel/preset-env babel-loader --dev

Now that we have understood Babel, our next job is to make it work with our code.

Our code at this point looks like this commit

Jump to Top

Creating a webpack-dev server for hosting files on the server

Until now we have had to run -

./node_modules/.bin/webpack

and then paste the file path in the browser to make the webpage work.

Now is the time to host index.html on a server so we don't have to paste the file path and also don't need to run the Webpack command every time.

So we will create a webserver using Webpack and run the whole setup so far on that server.

We will now see how Babel is configured to work with Webpack and also set up a Webpack dev server so we don't have to manually run the HTML file in the browser and refresh it again and again to see our changes.

First, we will understand how Babel works with Webpack.

  • As we already know that Webpack creates a bundle.js from all our js files in src folder, before generating the final bundle.js, Webpack can run some loaders for us to modify the files and influence the outcome for optimization and performance.

  • In our case, Babel needs to first go through all the files to make sure it transpiles the syntax as per the browser compatibility before final bundle.js gets created.

  • We need to ask Webpack to do that in webpack.config.js file.

    • It is defined inside modules with rules array.
    • rules array has all list of the loaders and its corresponding rule.
    • First, Webpack executes the test expression to find the appropriate files and then applies the mentioned loader to update the files before generating bundle.js
  • Then we also need to tell babel which type of presets we need to apply for transpiling our code, we have used @babel/preset-env, here's what it means:

@babel/preset-env is a smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms (and optionally, browser polyfills) are needed by your target environment(s). This both makes your life easier and JavaScript bundles smaller!

Now that we know how we added Babel, its time to know some more cool stuff i.e creating a server which will reload the webpage each time we make any change,

  • Webpack provides us with a package called webpack-dev-server, which can not only create a server which will serve our file but also do live reload for us when we make any changes to our files.
  • That is done by the following command:
yarn add webpack-dev-server --dev
  • Then we need to tell webpack which folder to serve on our server, i.e src folder inside webpack.config.js from lines 9 to 11.

Once that is done you should see the output as attached in this commit.

Jump to Top

Converting our html-js based app to React using Webpack and Babel

So far we have learned,

  • How to create simple javascript-html based webpage and run it using file path in the browser
  • But as we moved ahead, we needed to add more files and external packages, so we had to add a new <script> tag for each dependency.
  • We then figured how to use webpack to bundle all the assets into a single file and also use import and export statements for dependency management.
  • We also learned about Babel which will help us transpile new JavaScript syntax to the browser compatible Javascript.

Now is to take this one level further by converting this to React and create React components.
You could learn React from its official docs, but I am not going to use any complex React code that will go over your head.

  • First, we install React
yarn add react react-dom
  • Then we need to ask Babel to transpile our React code by using:
yarn add @babel/preset-react --dev

In React we don't write actual HTML, we write JavaScriptX, which is nothing but React's way of handling HTML tags in JavaScript files. These files could have .js or .jsx extensions.

Now we need to include this in .babelrc file so Babel knows how to transpile React syntax found in our JavaScript files.

 ...
 "@babel/preset-react"
 ...

Now let's start with dist/index.html,

  • dist/index.html:
    We have removed all div tags and created a new <div id="app"></div> tag which will be used by React to render all the components we will be creating.
    Note that bundle.js script tag remains here, as it will help the browsers access all JavaScript code.

  • src/index.js:
    We need to create React DOM using react-dom package so
    our components get rendered into the HTML div with id="app".
    Following code connects React with our HTML code and all our components are rendered inside div with id=app

ReactDOM.render(
  <div>
    <h4>This page shows total time you have spent on this page</h4>
    <TimeSpent />
    <ShowDate />
  </div>,
  document.getElementById('app')
);
  • Importing React allows us to write JavaScriptX or html in Javascript code in the JavaScript file and make sure it gets rendered correctly on the final HTML page.
  • Importing ReactDOM allows us to attach our React components to index.html div with id="app".

Here we have rendered two components:

  1. <TimeSpent />: which displays time spent on-page.

  2. <ShowDate />: which displays the current date on-page.

Next, we create the above components.

  • TimeSpent.js:
    In this component we create the following states:
    • startTime: Used to store the initial time when the page was rendered for the first time.
    • timeSpent: Stores total time spent on the page since the page was rendered.

We use React component lifecycle method componentDidMount to update the state continuously so the timeSpent state keeps getting updated.
Render method has divs to display timeSpent value

  • ShowDate.js:
    This component is pretty straight forward and just gets the current date and renders its value.

To check our current code status check this commit.

Jump to Top

Hosting our app on Github

No matter how simple it is, an app is incomplete without deployment and hosting. Let's see how we can deploy this tiny app on github.io.

In this last section of this tutorial, we see how to deploy this tiny app on github.io.
To do that we first need to install this node package gh-pages using the command:

yarn add gh-pages

Once that is done, we update our package.json to include build and deploy commands:

...
    "start": "webpack-dev-server --mode=development --config ./webpack.config.js",
    "build": "webpack --mode=production --config ./webpack.config.js",
    "predeploy": "yarn run build",
    "deploy": "gh-pages -d dist",
...
  • start: We use webpack dev server to start our app so our file changes get detected and app reloads after that. Since we will be using this command to test the app on local, we use development mode
  • build: This command will create a production optimized bundle.js which will not only b smaller but also faster as compared to development mode.
  • predeploy: This is npm command that runs before deploy command. We use to create build so every time we deploy new bundle.js gets created.
  • deploy: We use gh-pages command to deploy dist folder

Once this is done, we need to run following commands to see it running

yarn deploy

This creates a production mode bundle.js and then creates a gh-pages branch on GitHub which will be used to deploy our code on github.io.

To check our current code status check this commit

Now our app is live on https://trojanh.github.io/react-config-demo.

Final code for this app can be found here to try.

I hope you enjoyed this blog and got to learn how bare-bones html-js can be converted to React using Webpack.

Jump to Top