Photo by Markus Spiske on Unsplash

The evolution of frontend web development over the last 20 years has changed radically (and not without contradictions).

But how does an aspiring programmer begin cutting-edge web development today?

Let’s explore it together by creating a small but modern web page from scratch.

Imagine being a web programmer in the early 2000s…
You would open your beautiful HTML file, write a few <table> tags here and there, give the css a couple of taps, add a nice <?php tag and some SQL queries right in the middle of the HTML, exactly where they are needed.
The web no longer has any surprises for you!

Then the years go by …
You find yourself in 2018 without having seen or created a web page and suddenly want to make one.
That’s your aim but…
Just a quick Google search to understand that everything has changed: Single Page Applications (aka SPA), REST, GraphQL, TypeScript, React, SASS, Yarn, Babel, Webpack…

What ?????? Has the world gone mad?

Becoming a frontend web developer in 2018 suddenly seems to be quite a complex issue:

Front-end developers

Image taken from https://codeburst.io/the-2018-web-developer-roadmap-826b1b806e8d

Are we web programmers really mad?

That’s the question I ask myself almost every time I start a new frontend application. Of course at that time I decided to try new technologies and, usually, after a couple of hours I would find my head exploding and not being able to write even a single line of code.

The signs would therefore lead us to think that, yes, perhaps something was wrong. And yet the evolution of web programming in recent years cannot be ignored and, alas, also its inevitable state of complexity.

In this post I am aiming help the programmer described in the introduction to write his index.html file in 2018. Inevitably I will describe out of a thousand possible options the one that I happen most to use.

Any other option is undoubtedly equally valid and I invite you to write comments or other posts with your path “from zero to the hello world in the browser” .

To help the reader I have created a repository containing everything described in the post (in the commits I tried to follow the development of the various paragraphs): forks, shares, etc.

Javascript, of course (?!)

It is no longer possible to consider a web page without Javascript. From those who only know the JS of a few years ago, I expect a resounding “WAT?” JS, however , has evolved quite a lot over the years even though, I confess, it continues to be a language that I’m not particularly keen on.

But why is it so important today?

The “traditional” web stream (which I would call “legacy”) involves the generation of HTML pages on the server side based on the request made (possibly using templates to make them more dynamic) and which are then sent to the client (browser) for rendering.

The SPAs instead usually involve an initial call to the server to obtain the bare HTML page which will then load one or several JS and CSS files. At that point JS enters the scene and all subsequent calls are made asynchronously, talking to the server in the background and receiving payloads in JSON format. At any time (perhaps based on the answers obtained from the server or user actions) JS can modify the DOM without necessarily needing to reload the HTML from the server.

A rather radical paradigm shift that required the development of numerous new tools.

Webpack and Babel

This change introduces a great deal of dynamism and it goes without saying that the client code (interpreted and executed by browsers) is much more substantial and complex, therefore also much heavier to download. Moreover, the evolution of the language has not been particularly linear and the support of the various front-end functionalities is very jagged among the browsers (thankfully less and less).

Webpack is a software that seeks to respond to the modern needs of the frontend by “filling in” javascript modules in a minimal bundle and is generally understandable to most browsers (or at least to the ES5-compliant ones ). Basically it includes only Javascript and JSON but it is easily extendable with loaders and plugins that add numerous features and make it able to work with various other languages (Typescript and SASS are some two examples).

To start creating a small test app, following the initial Webpack guide, let’s create a project skeleton such as this one:

  my-cool-app
  |- package.json // project configuration and necessary js libraries
  |- /dist
    |- index.html // The initial html file
  |- /src
    |- index.js // The logic

As a prerequisite it is necessary to have node installed on the machine, after which the necessary dependencies can be installed with the following commands:

npm install --global yarn # see => https://yarnpkg.com/en/
yarn add -D webpack webpack-cli webpack-dev-server
yarn add lodash

The -D option passed to yarn is used to distinguish the development libraries (which should not therefore be inserted in the compiled file, as they are useless to the end user) from those instead necessary to run the application ( lodash only in this example ).

The index.html file as already announced will be very simple, it will do nothing but import the Javascript code:

<!doctype html>
<html>
  <head>
    <title>Getting Started</title>
  </head>
  <body>
    <script src="main.js"></script>
  </body>
</html>

And here is the “engine”, the index.js file:

import _ from "lodash";

const component = () => {
    let element = document.createElement('div');
    element.innerHTML = _.join(['Hello', 'World!'], ', ');
    return element;
}

document.body.appendChild(component());

The use of lodash was certainly not necessary, but is used to introduce the import of the modules, a very important feature in the modern js. The more attentive of you will also have noticed the use of an arrow function () => and the keyword let, both syntaxes introduced in ECMAScript 6, and syntaxes not supported by all browsers. Now we are going to introduce Babel, a compiler able to “translate” modern Javascript code into a version that is understandable to all browsers. Babel can also be used standalone, but in our set-up it will be integrated into Webpack. It is first necessary to install the packages:

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

At this point all that remains is to create the webpack configuration, contained in the webpack.config.js file:

const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    'loader': 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            },
        ]
    },
};

This configuration does nothing but read an entrypoint src/index.js and compile it in the output file in dist/main.js. It also uses the loader babel with preset-env preset to support the new JavaScript features.

Now the app is ready to be filled, just do it with npx webpack (the result will be saved in the dist/ directory).

I suggested also installing webpack-dev-server in order to be able to quickly compile the files (even with hot reloads) and to immediately display them in browsers. Simply launch npx webpack-dev-server and the app will be available in a few seconds at the address http://localhost:8080/, automatically reloaded each time the files are updated (you will only need to restart the server if you change the configurations of webpack).

What has been done so far is enough to write everything that comes to mind using javascript. In the following paragraphs, I will introduce a few new features to make it all more interesting.

CSS and SASS

Now we need some style for our text and to add the necessary loaders to the dependencies, to create a style file and to import it into the js file:

yarn add -D style-loader css-loader
echo "* {\n\tcolor: red;\n}" > src/style.css
echo "import './style.css';" | cat - src/index.js | tee src/index.js

Last step, the webpack configuration (webpack.config.js) to use the style loaders:

...
module.exports = {
    ...
    module: {
        rules: [
            { test: /\.css$/, use: ['style-loader', 'css-loader'] }
        ]
    }
};

Restart webpack-dev-server as we have changed the webpack configuration and the hello world should be coloured red.

As a further evolution we can try and use SASS (for now only renaming the file, I won’t add new syntax):

yarn add -D sass-loader node-sass
mv ./src/style.css ./src/style.scss

We add the rule to the webpack configuration:

{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },

and finally we modify the index.js file to import the new scss file instead of the css.

We relaunch webpack-dev-server to appreciate the hello world, identical to before but now compiled with SASS 🙂.

TypeScript

TypeScript is a typed open source language developed by Microsoft. It is a Javascript superset, meaning it adds new features but is completely compatible with it. Typescript is then compiled into Javascript to be used on browsers. It has many interesting features, but what I find most useful is the typing.

We modify the project to support it:

yarn add -D typescript awesome-typescript-loader @types/lodash
mv src/index.js src/index.ts

Typescript requires a configuration in the tsconfig.json file:

{
    "compilerOptions": {
        "outDir": "./dist/",
        "sourceMap": false,
        "noImplicitAny": true,
        "module": "commonjs",
        "target": "es5",
        "jsx": "react"
    },
    "include": [
        "./src/**/*"
    ]
}

The webpack.config.js configuration file must also be modified:

module.exports = {
    entry: './src/index.ts',
    ...
    resolve: {
        extensions: [".ts", ".js"]
    },
    module: {
        rules: [
            { test: /\.ts$/, loader: "awesome-typescript-loader" },
            ...
        ]
    }
};

The last change concerns the import of lodash. As you may have noticed, I also installed the @types/lodash package which contains the library definitions. This package, like many other @types/<lib>, derive from the DefinitelyTyped project which distributes high-quality definitions for TypeScript, definitions that are used to declare the types of variables and functions.

Completing the project now, you will obtain this error:

ERROR in [at-loader] ./src/index.ts:3:8
    TS1192: Module '"./node_modules/@types/lodash/index"' has no default export.

In ES6 the import of a module has a slightly different syntax , so we will have to modify it in import * as _ from "lodash";

Now rush off and learn TypeScript and you won’t have to deal with JavaScript any more!

React

React is a javascript UI library developed by Facebook. Using this it is possible to build complex applications, clearly separating the graphic components from one another. Without needing to explain here how it works in detail, let’s simply modify our little app by inserting a React component, so that with each click on the phrase “Hello, World!” The latter changes colour.

Here’s how to start using React in our set-up:

yarn add react react-dom
yarn add -D @types/react @types/react-dom

We therefore modify webpack.config.js to also support JSX files (syntactic extension to include html-like tags in js) which, in the case of Typescript, have a .tsx extension:

...
module.exports = {
    entry: './src/index.tsx',
    ...
    resolve: {
        extensions: [".ts", ".tsx", ".js"]
    },
    module: {
        rules: [
            // Modify existing rule to check the optional "x" at the end
            { test: /\.tsx?$/, loader: "awesome-typescript-loader" },
            ...
        ]
    }
};

In the index.html file we are going to add the entry point to which React will attach to render the app:

...
<body>
    <div id="app"></div>
    ...
</body>
...

Delete the current index.ts file and replace it with the new index.tsx:

import * as React from "react";
import * as ReactDOM from "react-dom";

import './style.scss';

import MainComponent from "./components/MainComponent";

ReactDOM.render(
    <MainComponent />,
    document.getElementById("app")
);

As you can see ReactDom will go on attaching to the <div id="app"> the component <MainComponent /> which is contained in the ./components/MainComponent file:

import * as _ from "lodash";
import * as React from "react";

interface IState {
    selectedColor: string;
}

export default class extends React.Component<{}, IState> {
    // list of colors to pick from
    private colors: string[] = ['#80BF17', '#590F7F', '#FF3725', '#F2AC3F', '#1D66E5'];

    constructor(props: any) {
        super(props);
        this.setColor = this.setColor.bind(this);
        this.state = { selectedColor: this.pickColor() };
    }

    // Render the component
    public render(): JSX.Element {
        return (
            // Return some JSX
            <div className="hello-world" style={{color: this.getColor()}}>
                <a onClick={this.setColor}>Hello, World!</a>
            </div>
        );
    }

    // Set a color in the state
    private setColor(e: any): void {
        e.preventDefault();
        this.setState({ selectedColor: this.pickColor() });
    }

    // Get a random color from the list
    private pickColor(): string {
        return _.shuffle(this.colors)[0];
    }

    // Get the color saved in the state
    private getColor(): string {
        return this.state.selectedColor;
    }
}

render is the function that is called when React renders a component. As you can guess even without knowing it in detail, the click sets a colour in the state taking a random element from the list. The color is then used to color the text within the <div>

Finally it is necessary to modify the style file, otherwise the writing will always be red:

a {
    cursor: pointer;
    font-size: 40px * 2; // Let's use some Sass :)
    // color: red; <-- deleted or it will always be red!
}

And here is the result:

Hello world

Conclusions

At this point, the 2000 web developer will probably have quite a headache 🙂.

We have only scratched the surface layer of the various software seen, in particular webpack and react, and it will be necessary to learn more about it before writing other code, but we also have a working set-up ready for the big step into the modern web.

To use the words of the great Buzz Lightyear:

Buzz Lightyear

If you are not ready to jump to infinity immediately, you could start with the official React tutorial, which will teach you how to make the inevitable todo app.

Have fun!