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
- Adding multiple JavaScript files to HTML
- Re-organizing JavaScript files and libraries using Webpack for bundling
- Allowing cross-browser JavaScript feature support using Babel
- Creating a webpack-dev server for hosting files on the server
- Converting our html-js based app to React using webpack and Babel
- Hosting our app on Github
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 idtimeSpent
that will be used to show time we have spent inindex.js
. To importindex.js
into this HTML page we have usedscript
tag - Then we have
updateTotalTimeSpent
method inindex.js
which calculates total from startTime and updated the div usingquerySelector
. - We
updateTimeSpentRecursively
method to callupdateTotalTimeSpent
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.
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
withid=date
to display the current date. The date will be updated from theshowDate
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
usingyarn
to our app like below
yarn add moment
-
Now, we need to add a
script
tag to importmoment
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.
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
orbuild
.
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
insrc/index.js
which will includeshowDate()
in finalbundle.js
. - Import
moment
in files that need to use it instead of placing it in thescript
tag which mademoment
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.
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
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 insrc
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
withrules
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
- It is defined inside
-
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 insidewebpack.config.js
from lines 9 to 11.
Once that is done you should see the output as attached in this commit.
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
andexport
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 alldiv
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 thatbundle.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 withid="app"
.
Following code connects React with our HTML code and all our components are rendered inside div withid=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 writeJavaScriptX
orhtml 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 toindex.html
div withid="app"
.
Here we have rendered two components:
-
<TimeSpent />
: which displays time spent on-page. -
<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.
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 usedevelopment
modebuild
: This command will create a production optimizedbundle.js
which will not only b smaller but also faster as compared todevelopment
mode.predeploy
: This is npm command that runs beforedeploy
command. We use to create build so every time we deploy newbundle.js
gets created.deploy
: We usegh-pages
command to deploydist
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.