Creating a full-stack web application with Python, NPM, Webpack and React — Beauty and Functionality

If you followed along with the steps in my previous tutorial, you should now have a working, basic full stack application.
If you didn’t, but still want to follow this tutorial, you can catch up by downloading the code from my GitHub page.
For our next magic trick, we will transform a plain, static page showing “Hello World!” into a beautiful, single page application. Our page should be able to talk to the back end, and immediately update when it receives new information, without the user having the refresh the page. The page we will create, returns “Hello” in a random European language every time the button is clicked.
This is our page:

To be able to achieve this, we will need to figure out the following:
- How to return a random European “Hello” every time our /hello end-point is called.
- How to request information from the server on demand.
- How to display the returned information to the user seamlessly, without them needing to refresh the page.
- How to add style to our page, so we can create a large, centred button and text.
- Finally, we will have to figure out how to add a background image.
Returning a Random Hello From The Server
To be able to request a random European “Hello” every time we talk to the /hello end point on the server, we will have to change the function in the server/server.py file. Instead of returning a static “Hello World” every time it is called, it will select a random European “Hello” from a list of European “Hello”s. To make this possible, we will need to make the following changes:
Add the following function to your server.py file:
import randomdef get_hello():
greeting_list = [‘Ciao’, ‘Hei’, ‘Salut’, ‘Hola’, ‘Hallo’, ‘Hej’]
return random.choice(greeting_list)
This function defines a list of European “Hello”s. We then use random.choice() to pick a random item from the list every time the function is called.
Change the hello() function to return get_hello() every time it’s called.
@app.route("/hello")
def hello():
return get_hello()
Having changed /hello to return the information we are interested in, we now need to figure out how to request that information from the front end.
The Importance of Componentisation — Creating a Hello Class in React
Separation of concerns is considered good programming practice. Whenever possible, you should strive to make your functions only do one thing, and do it well. The same applies to classes. You could think of this as each function or class being a separate component.
React was created with componentisation in mind. This means that it is designed for you to construct your web site out of multiple smaller pieces. Think of it like playing with Lego. This makes it really easy to switch out one component for another, to use one component multiple times, and for other developers to understand your code. Understandable code is something we should strive for, as this generally also makes it easier to maintain and extend our application.
With componentisation in mind, let’s create a Hello class to handle the greeting on our webpage. The class will get a “Hello” from the /hello end point on our server, and display it to the user. It should also take a “name” parameter, so we can say hello to someone specific.
Start by changing the render function in your React App class to call the Hello class we will be creating shortly, instead of the old paragraph with the greeting. Pass the name “Rimini” as the name parameter. For the sake of structure, we will place the Hello class in a page header.
import Hello from "./Hello";
import { PageHeader } from "react-bootstrap";[...]render () {
return (
<PageHeader>
<div className='header-contents'>
<Hello name='Rimini' />
</div>
</PageHeader>
);
}
Creating the Hello class
Having changed our App class to call the Hello class, we need to actually create the Hello class. We will create a file called Hello.jsx in the js/ folder, which defines a class called Hello.
export default class Hello extends React.Component {
constructor(props) {
super(props);
this.state = {greeting: 'Hello ' + this.props.name}; // This binding is necessary to make `this` work in the callback
this.getPythonHello = this.getPythonHello.bind(this);
}
}
Components And Props
At this point you probably have a lot of questions about what is going on in our constructor.
React has something called components and props. Props are immutable parameters passed to the constructor at creation time. Props are public, and changing them would violate one of the fundamental principles of react. State is internal, and mutable. Whenever you update state, it gets re-rendered in the UI. If you want to get a better understanding of how this works, I highly recommend reading more about the lifecycle and states in the excellent React documentation.
We will add a function called personaliseGreeting() to the Hello class. This will handle updating of the greeting on our web page whenever we click the button to get a new one. Note here that we use this.setState() with the key “greeting”. You have to use this syntax to have React automatically re-render the “greeting” state on the web page.
personaliseGreeting(greeting) {
this.setState({greeting: greeting + ' ' + this.props.name + '!'}); }
Rendering the greeting
To make our greeting show up on the page, we have to call “{this.state.greeting}” in our render function. We also have to add a button with a callback to a function called getPythonHello(), which we will create shortly. This function will get a new “Hello” from the Python back end every time it is called.
render () {
return (
<h1>{this.state.greeting}</h1>
<hr/>
<Button bsSize="large" bsStyle="danger" onClick={this.getPythonHello}>
Say Hello!
</Button>
)
}
Note that I have placed the headline and button inside a grid in my code, so I can more easily control where it ends up on the page.
Binding “this”
Because class methods in JavaScript aren’t bound by default, we have to create a binding in our constructor when we want to use “this” in a function callback. Otherwise our “this” function will be undefined. This applies whenever you call a function without () in JavaScript. An example of doing this, is the “onClick={this.getPythonHello}” in our render().
Requesting Information From The Server
React does not come with a built-in way of performing HTTP requests. To achieve our goal of requesting information from the server, we will have to pick a library that can do this for us. One of the easiest ways of doing this, is to include the jQuery library. jQuery is a javascript library that simplifies standard javascript functions by providing abbreviated functions behind $ notation.
Start by installing the jQuery dependency:
$ npm i jquery --save-dev
Add a jQuery requirement to the react file where it is going to be used, which is Hello.jsx. You should add this requirement above your Hello class definition.
var $ = require(‘jquery’);
Adding the query requirement to our react file means we can use standard jQuery functions in our react code, as long as they start with the “$” variable we just defined. Let’s use it to get a “Hello” from our server.
We will be using a GET HTTP request to fetch information. Get is essentially the “Read Only” mode for HTTP requests. You can fetch information, but you can’t ask the server to alter it.
Add the following function to the Hello class in Hello.jsx:
getPythonHello() {
$.get(window.location.href + 'hello', (data) => {
console.log(data);
this.personaliseGreeting(data);
});
}
This function performs a jQuery GET request against the server, by connecting to the /hello endpoint. It then takes the information returned from the server, a European “Hello”, prints it to the browser developer console, and finally passes it to another function in the Hello class, called personaliseGreeting().
When you rebuild the front end (npm run watch), and restart your python server. You should see the following:

Beauty through CSS — Styling Our Page
We finally have a product that interacts with the user. If we wanted to, we could leave it here, and say we’re happy with our achievements so far. Personally, I prefer adding a bit of design to my web applications, so they look a bit nicer. To this end, we will use CSS to make our header cover the entire screen, instead of just the top of the page. If you are unfamiliar with CSS, this is just a styling language for HTML. It’s similar to changing font size, style and positioning in your Word document.
Making Webpack Understand CSS
To be able to use CSS in our application, we have to install a few loaders and plugins, and add them to our Webpack config. This is because Webpack only understands JavaScript.
Install the following plugins:
- css-loader
- style-loader
- extract-text-webpack-plugin
The css-loader and the style-loader are required to make Webpack understand CSS. By adding these loaders, Webpack will be able to bundle any CSS we require into our bundle.js. The issue with this, is that the JavaScript and the CSS will not load separately on your page, which can lead to UI components not showing up until your JavaScript has loaded. This isn’t great, as on bad networks our design might load very slowly.
We can get around this issue by adding the extract-text-webpack-plugin. This plugin splits out our CSS into a separate bundle, which we can attach to our HTML. This makes our CSS load independently of our JavaScript again.
Add the following css rule to your webpack.config.js, in the modules.rules section:
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader',
})
},
Add the ExtractTextPlugin plugin to the webpack.config.js (have a look at my webpack file if you are confused). Note that we pass the filename of our bundled CSS file to this plugin on creation. We will call our file ‘styles.css’.
plugins: [ new ExtractTextPlugin('styles.css') ]
Finally, we need to add the styles.css bundle to our index.html, to make sure our styles are loaded. Add the following line to the header section of your index.html file (For reference, here is mine):
<link rel="stylesheet" href="dist/styles.css">
Adding CSS Rules
Now that we have made sure that our setup can handle CSS correctly, we are going to create a file called fullstack.css in the css folder. I have added a few different rules to mine, to ensure that the text and button end up in the right location, and the text is big and thin.
This is one of the rules in my fullstack.css file. It makes the “Hello Rimini” text large and thin:
.header-contents h1 {
font-size: 120px;
font-weight: 300;
}
After creating the fullstack.css file, we need to add it to the react component where the rules are being used, for them to have any effect. As the header is defined in App.jsx, add the following requirement, below the other requirements and imports in that file:
require('../css/fullstack.css');
The header styles from our fullstack.css file will now be picked up by Webpack, and bundled into the styles.css file. When we refresh our page, it should look like the below image. Note that if you are not using Chrome, the font might look a bit different to the one in this photo:

Finishing Touches — Adding a Background Image
Webpack does not natively understand the concept of images. We therefore need to add a loader to be able to use them in our application. The loader we need to install is called “file-loader”.
Install the file-loader.
$ npm i file-loader --save-dev
Add the file-loader rule to your webpack.config.js file, in the modules.rules section:
{
test: /\.(png|svg|jpg|gif)$/,
use: 'file-loader'
}
Add the image you want to use to the images/ folder. Name it “header.jpg”.
To be able to use an image as a background image for the header section of the web page, we need to add it as a background image in the page-header section of the fullstack.css file.
.page-header {
background-image: url('../images/header.jpg');
background-repeat: no-repeat;
background-position: center;
background-size: cover;
}
The next thing we need to do, is to load the image in the React file where it is used. If you don’t explicitly load the image in React, Webpack won’t bundle it, and it won’t show up on your page. This behaviour is not very intuitive at first, and I got caught out by this the first time I wanted to add a background image to my application.
In App.jsx, make the following changes:
import HeaderBackgroundImage from '../images/header.jpg';
Add this function to you App class:
addHeaderImg() {
let headerBg = new Image();
headerBg.src = HeaderBackgroundImage;
}
This function creates a new image object and sets the source to be your header image.
The last thing we need to do, is to ensure the image is loaded when we render the page. This means that we have to call the addHeaderImg() function in the render() function.
Add the following line to your render() function:
{this.addHeaderImg()}
When you refresh your browser window, you should now see the following:

Congratulations! You’ve successfully created a full stack web application!