Photo by Markus Spiske on Unsplash

L’evoluzione dello sviluppo web frontend negli ultimi 20 anni è radicalmente cambiato (e non senza contraddizioni).
Ma un aspirante programmatore, come inizia oggi lo sviluppo web all’avanguardia?
Vediamolo insieme creando da zero una piccola ma moderna pagina web.

Immaginate di essere un programmatore web nei primi anni 2000…
Aprite il vostro bel file HTML, scrivete un po’ di tag <table> qua e là, date due martellate al css, aggiungete un bel tag <?php e qualche query SQL direttamente in mezzo all’HTML, proprio lì dove serve.
Il web non ha più segreti per voi!

Poi passano gli anni…
Vi ritrovate nel 2018 senza aver più visto né creato una pagina web e, improvvisamente, volete farlo.
Vorreste farlo…
Basta una breve ricerca su google per capire che tutto è cambiato: Single Page Applications (aka SPA), REST, GraphQL, TypeScript, React, SASS, Yarn, Babel, Webpack…

Ehhhh?????? Ma sono tutti impazziti?

Diventare frontend web developers nel 2018 sembrerebbe una cosa non proprio banale:

Front-end developers

Immagine tratta da https://codeburst.io/the-2018-web-developer-roadmap-826b1b806e8d

Noi programmatori web siamo davvero impazziti?

È la domanda che mi faccio praticamente ogni volta che inizio una nuova applicazione frontend. Ovviamente in quell’occasione decido di provare n nuove tecnologie e, solitamente, dopo un paio d’ore mi scoppia la testa e non sono riuscito a scrivere neanche una riga di codice.
Gli indizi porterebbero quindi a pensare che, sì, forse qualcosa l’abbiamo sbagliata. Eppure non si può negare l’evoluzione della programmazione web negli ultimi anni con, ahinoi, anche il suo immancabile corredo di complessità.

In questo post vorrei aiutare il programmatore descritto nell’introduzione a scrivere il suo file index.html nel 2018. Inevitabilmente descriverò una delle mille possibili opzioni, quella che mi trovo più spesso ad usare.
Ogni altra opzione è sicuramente altrettanto valida e vi invito a scrivere commenti o altri post con il vostro percorso “da zero all’hello world nel browser”.

Per aiutare il lettore ho creato un repository contenente tutto quanto descritto nel post (nei commit ho cercato di seguire lo sviluppo dei vari paragrafi): forkate, condividete, ecc.

Javascript, ovviamente (?!)

Ormai non è più possibile pensare una pagina web senza Javascript. Da chi conosce soltanto il JS di qualche anno fa, mi aspetto un bel “WAT?” JS però si è molto evoluto negli anni anche se, vi confesso, continua ad essere un linguaggio che non mi piace più di tanto.

Ma perchè è così importante oggi?

Il flusso web “tradizionale” (che definirei “legacy”) prevede la generazione di pagine HTML lato server in base alla richiesta effettuata (eventualmente usando template per renderle più dinamiche) e che poi vengono inviate al client (browser) per la renderizzazione.

Le SPA invece prevedono di solito una chiamata iniziale al server per ottenere la scarna pagina HTML che effettuerà poi il caricamento di uno o più file JS e CSS. A quel punto JS entra in scena e tutte le successive chiamate vengono effettuate in modo asincrono, dialogando col server in “background” e ricevendo payload in formato JSON. In ogni momento (magari in base alle risposte ottenute dal server o alle azioni dell’utente) JS può modificare il DOM senza aver necessariamente bisogno di ricaricare dell’HTML dal server.

Un cambio di paradigma piuttosto radicale che ha richiesto lo sviluppo di numerosi nuovi tool.

Webpack e Babel

Tale cambiamento introduce molta dinamicità e viene da sé che il codice client (interpretato ed eseguito dai browser) è molto più corposo e complesso, quindi anche molto più pesante da scaricare. Inoltre l’evoluzione del linguaggio non è stata proprio lineare e il supporto delle varie funzionalità front-end è molto frastagliato tra i browser (per fortuna sempre di meno).

Webpack è un software che prova a rispondere alle moderne necessità del frontend “compilando” moduli javascript in un bundle minimale e generalmente comprensibile alla maggior parte dei browser (o almeno quelli ES5 compliant). Di base comprende soltanto Javascript e JSON, ma è facilmente estensibile con loader e plugin che aggiungono numerose funzionalità e lo rendono in grado di lavorare con vari altri linguaggi (Typescript e SASS sono degli esempi).

Per iniziare la creazione di una piccola app di test, seguendo la traccia della guida iniziale di Webpack, andiamo a creare uno scheletro di progetto come questo:

  my-cool-app
  |- package.json // configurazione del progetto e librerie js necessarie
  |- /dist
    |- index.html // Il file html iniziale
  |- /src
    |- index.js // La logica

Come prerequisito occorre avere node installato sulla macchina, dopodichè si possono installare le dipendenze necessarie con i seguenti comandi:

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

L’opzione -D passata a yarn serve per distinguere le librerie di sviluppo (che quindi non dovranno essere inserite nel file compilato, in quanto inutili all’utente finale) da quelle invece necessarie per far girare l’applicazione (solo lodash in questo esempio).

Il file index.html come già preannunciato sarà semplicissimo, non farà altro che importare il codice Javascript:

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

Ed ecco il “motore”, il file index.js:

import _ from "lodash";

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

document.body.appendChild(component());

L’uso di lodash non era certo necessario, ma serve per introdurre l’import dei moduli, una caratteristica molto importante nel js moderno. I più attenti avranno notato anche l’utilizzo di una arrow function () => e la keyword let, entrambe sintassi introdotte in ECMAScript 6, sintassi non supportate da tutti i browser. Andremo quindi ad introdurre Babel, un compilatore in grado di “tradurre” codice Javascript moderno in una versione comprensibile a tutti i browser. Babel può essere usato anche standalone, ma nel nostro setup verrà integrato in Webpack. È necessario innanzitutto installare i pacchetti:

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

A questo punto non resta che creare la configurazione di webpack, contenuta nel file webpack.config.js:

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']
                    }
                }
            },
        ]
    },
};

Questa configurazione non fa altro che leggere un entrypoint src/index.js e compilarlo nel file di output in dist/main.js. Utilizza inoltre il loader babel con il preset preset-env per supportare le nuove feature JavaScript.

Adesso l’app è pronta per essere compilata, sarà sufficiente farlo con npx webpack (il risultato sarà salvato nella directory dist/).
Ho suggerito di installare anche webpack-dev-server così da poter compilare al volo i file (anche con hot reload) e poterli subito visualizzare a browser. Basta quindi lanciare npx webpack-dev-server e l’app sarà disponibile in pochi secondi all’indirizzo http://localhost:8080/, automaticamente ricaricata ad ogni aggiornamento dei file (sarà necessario riavviare il server solo se si cambiano le configurazioni di webpack).

Quanto fatto finora è già sufficiente a scrivere tutto ciò che ci passa per la mente utilizzando javascript. Nei paragrafi seguenti introdurrò un po’ di nuove feature per rendere il tutto più interessante.

CSS e SASS

Serve adesso un po’ di stile al nostro testo, aggiungiamo alle dipendenze i loader necessari, creiamo un file di stile e importiamolo nel file js:

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

Ultimo passaggio, la configurazione di webpack (webpack.config.js) per utilizzare i loader di stile:

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

Riavviate webpack-dev-server dato che abbiamo cambiato la configurazione di webpack e l’hello world dovrebbe essere colorato di rosso.

Come ulteriore evoluzione proviamo ad utilizzare SASS (per ora solo rinominando il file, non aggiungo nuova sintassi): :

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

Aggiungiamo la regola alla configurazione di webpack:

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

e infine modifichiamo il file index.js per importare il nuovo file scss invece del css.
Rilanciamo webpack-dev-server per apprezzare l’hello world, identico a prima ma adesso stilato con SASS 🙂

TypeScript

TypeScript è un linguaggio open source tipizzato sviluppato da Microsoft. È un superset di Javascript, ovvero vi aggiunge nuove funzionalità ma è completamente compatibile con esso. Typescript viene poi compilato in Javascript per essere utilizzato sui browser. Ha molte caratteristiche interessanti, ma quella che senza dubbio trovo più utile è la tipizzazione.

Modifichiamo il progetto per supportarlo:

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

Typescript richiede una configurazione nel file tsconfig.json:

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

Anche il file di configurazione webpack.config.js va modificato:

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

Ultima modifica riguarda l’import di lodash. Come avrete notato ho installato anche il pacchetto @types/lodash che contiene le definizioni della libreria. Questo pacchetto, come molti altri @types/<lib>, derivano dal progetto DefinitelyTyped che distribuisce definizioni di alta qualità per TypeScript, definizioni che servono per dichiarare i tipi di variabili e funzioni.

Compilando adesso il progetto otterrete però questo errore:

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

In ES6 l’import di un modulo ha una sintassi leggermente diversa, quindi dovremo modificarlo in import * as _ from "lodash";

Adesso correte ad imparare TypeScript e non dovrete più avere a che fare con JavaScript!

React

React è una libreria UI javascript sviluppata da Facebook. Con essa è possibile costruire applicazioni complesse separando in maniera netta le componenti grafiche tra loro. Senza voler spiegare qui il suo funzionamento nel dettagli, limitiamoci a modificare la nostra piccola app inserendo un componente React, in modo che ad ogni click sulla frase “Hello, World!” quest’ultima cambi colore.

Ecco come iniziare ad usare React nel nostro setup:

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

Modifichiamo quindi webpack.config.js per supportare anche i file JSX (estensione sintattica per includere tag simil-html nel js), che nel caso di Typescript, hanno estensione .tsx:

...
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" },
            ...
        ]
    }
};

Nel file index.html andiamo ad aggiungere l’entry point a cui React si aggancerà per renderizzare l’app:

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

Eliminiamo l’attuale file index.ts e sostituiamolo con il nuovo 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")
);

Come si può vedere ReactDom andrà ad agganciare al <div id="app"> il componente <MainComponent /> che è contenuto nel file ./components/MainComponent:

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 è la funzione che viene chiamata quando React renderizza un componente. Come si può intuire anche senza conoscerlo nel dettaglio, al click viene settato un colore nello stato prendendo un elemento casuale dalla lista. Il colore viene poi utilizzato per colorare il testo all’interno del <div>

Infine è necessario modificare il file di stile, altrimenti la scritta sarà sempre rossa:

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

Ed ecco il risultato:

Hello world

Conclusioni

Arrivati a questo punto lo sviluppatore web del 2000 avrà probabilmente un bel mal di testa 🙂
Abbiamo soltanto scalfito lo strato superficiale dei vari software visti, in particolare webpack e react, e sarà necessario approfondirne la conoscenza prima di scrivere altro codice, ma abbiamo anche un setup funzionante e pronto al grande passo nel web moderno.

Per dirla con le parole del grande Buzz Lightyear:

Buzz Lightyear

Se non siete pronti subito al salto nell’infinito, potreste iniziare con il tutorial ufficiale di React, che vi insegnerà come realizzare l’immancabile todo app.

Buon divertimento!