├── .gitignore ├── .travis.yml ├── README.md ├── how-to-translate.md ├── img ├── chai.png ├── eslint.png ├── flow.png ├── gulp.png ├── js.png ├── mocha.png ├── npm.png ├── react.png ├── redux.png ├── webpack.png └── yarn.png ├── mdlint.js ├── package.json ├── tutorial ├── 1-node-npm-yarn-package-json │ ├── README.md │ ├── index.js │ └── package.json ├── 10-immutable-redux-improvements │ ├── .gitignore │ ├── README.md │ ├── dist │ │ └── index.html │ ├── gulpfile.babel.js │ ├── package.json │ ├── src │ │ ├── client │ │ │ ├── actions │ │ │ │ └── dog-actions.js │ │ │ ├── app.jsx │ │ │ ├── components │ │ │ │ ├── button.jsx │ │ │ │ └── message.jsx │ │ │ ├── containers │ │ │ │ ├── bark-button.js │ │ │ │ └── bark-message.js │ │ │ └── reducers │ │ │ │ └── dog-reducer.js │ │ ├── server │ │ │ └── index.js │ │ └── shared │ │ │ └── dog.js │ ├── webpack.config.babel.js │ └── yarn.lock ├── 11-testing-mocha-chai-sinon │ ├── .gitignore │ ├── README.md │ ├── dist │ │ └── index.html │ ├── gulpfile.babel.js │ ├── package.json │ ├── src │ │ ├── client │ │ │ ├── actions │ │ │ │ └── dog-actions.js │ │ │ ├── app.jsx │ │ │ ├── components │ │ │ │ ├── button.jsx │ │ │ │ └── message.jsx │ │ │ ├── containers │ │ │ │ ├── bark-button.js │ │ │ │ └── bark-message.js │ │ │ └── reducers │ │ │ │ └── dog-reducer.js │ │ ├── server │ │ │ └── index.js │ │ ├── shared │ │ │ └── dog.js │ │ └── test │ │ │ ├── client │ │ │ └── state-test.js │ │ │ └── shared │ │ │ └── dog-test.js │ ├── webpack.config.babel.js │ └── yarn.lock ├── 12-flow │ ├── .flowconfig │ ├── .gitignore │ ├── README.md │ ├── dist │ │ ├── client-bundle.js.map │ │ └── index.html │ ├── gulpfile.babel.js │ ├── package.json │ ├── src │ │ ├── client │ │ │ ├── actions │ │ │ │ └── dog-actions.js │ │ │ ├── app.jsx │ │ │ ├── components │ │ │ │ ├── button.jsx │ │ │ │ └── message.jsx │ │ │ ├── containers │ │ │ │ ├── bark-button.js │ │ │ │ └── bark-message.js │ │ │ └── reducers │ │ │ │ └── dog-reducer.js │ │ ├── server │ │ │ └── index.js │ │ ├── shared │ │ │ └── dog.js │ │ └── test │ │ │ ├── client │ │ │ └── state-test.js │ │ │ └── shared │ │ │ └── dog-test.js │ ├── webpack.config.babel.js │ └── yarn.lock ├── 2-packages │ ├── .gitignore │ ├── README.md │ ├── index.js │ ├── package.json │ └── yarn.lock ├── 3-es6-babel-gulp │ ├── .gitignore │ ├── README.md │ ├── gulpfile.js │ ├── package.json │ ├── src │ │ └── index.js │ └── yarn.lock ├── 4-es6-syntax-class │ ├── .gitignore │ ├── README.md │ ├── gulpfile.js │ ├── package.json │ ├── src │ │ ├── dog.js │ │ └── index.js │ └── yarn.lock ├── 5-es6-modules-syntax │ ├── .gitignore │ ├── README.md │ ├── gulpfile.babel.js │ ├── package.json │ ├── src │ │ ├── dog.js │ │ └── index.js │ └── yarn.lock ├── 6-eslint │ ├── .gitignore │ ├── README.md │ ├── gulpfile.babel.js │ ├── package.json │ ├── src │ │ ├── dog.js │ │ └── index.js │ └── yarn.lock ├── 7-client-webpack │ ├── .gitignore │ ├── README.md │ ├── dist │ │ └── index.html │ ├── gulpfile.babel.js │ ├── package.json │ ├── src │ │ ├── client │ │ │ └── app.js │ │ ├── server │ │ │ └── index.js │ │ └── shared │ │ │ └── dog.js │ ├── webpack.config.babel.js │ └── yarn.lock ├── 8-react │ ├── .gitignore │ ├── README.md │ ├── dist │ │ └── index.html │ ├── gulpfile.babel.js │ ├── package.json │ ├── src │ │ ├── client │ │ │ └── app.jsx │ │ ├── server │ │ │ └── index.js │ │ └── shared │ │ │ └── dog.js │ ├── webpack.config.babel.js │ └── yarn.lock └── 9-redux │ ├── .gitignore │ ├── README.md │ ├── dist │ └── index.html │ ├── gulpfile.babel.js │ ├── package.json │ ├── src │ ├── client │ │ ├── actions │ │ │ └── dog-actions.js │ │ ├── app.jsx │ │ ├── components │ │ │ ├── button.jsx │ │ │ └── message.jsx │ │ ├── containers │ │ │ ├── bark-button.js │ │ │ └── bark-message.js │ │ └── reducers │ │ │ └── dog-reducer.js │ ├── server │ │ └── index.js │ └── shared │ │ └── dog.js │ ├── webpack.config.babel.js │ └── yarn.lock └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | "6" 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | **ATTENZIONE: QUESTO REPOSITORY NON È AGGIORNATO!!!** 3 | 4 | **NUOVA VERSIONE AGGIORNATA QUI: https://github.com/fbertone/guida-javascript-moderno** 5 | 6 | # Stack JavaScript da Zero 7 | 8 | [](https://travis-ci.org/verekia/js-stack-from-scratch) [](https://gitter.im/js-stack-from-scratch/Lobby) 9 | 10 | [](https://yarnpkg.com/) 11 | [](https://facebook.github.io/react/) 12 | [](http://gulpjs.com/) 13 | [](http://redux.js.org/) 14 | [](http://eslint.org/) 15 | [](https://webpack.github.io/) 16 | [](https://mochajs.org/) 17 | [](http://chaijs.com/) 18 | [](https://flowtype.org/) 19 | 20 | Benvenuto a questa guida sul Javascript moderno: **Stack Javascript da zero**. 21 | 22 | **ATTENZIONE: QUESTO REPOSITORY NON È AGGIORNATO!!!** 23 | 24 | **NUOVA VERSIONE AGGIORNATA QUI: https://github.com/fbertone/guida-javascript-moderno** 25 | 26 | Puoi trovare la versione originale della guida, in inglese, qua: [**JavaScript Stack from Scratch**](https://github.com/verekia/js-stack-from-scratch). 27 | 28 | Questa è una guida rapida per la creazione da zero di uno stack Javascript. Per seguire questa guida dovresti avere già qulche fondamento di programmazione generica e alcune basi di Javascript. Questa guida é focalizzata su come **collegare assieme vari tool di sviluppo** e fornesce un esempio il piú semplice possibile per ogni strumento trattato. Puoi vedere questa guida come un modo per *costruirti da zero il tuo boilerplate personalizzato*. 29 | 30 | 31 | Non avrai bisogno di utilizzare interamente questo stack se vuoi realizzare una semplice pagina web con alcune interazioni JS (una combinazione di Browserify/Webpack + Babel + jQuery é sufficiente per scrivere codice ES6 in diversi file con compilazione da linea di comando), ma se vuoi realizzare una web app scalabile questo tutorial sará perfetto. 32 | 33 | Siccome lo scopo di questa guida è di utilizzare vari strumenti in sequenza, non entrerò nei dettagli di ciascuno strumento. Se ti interessano dei dettagli maggiori o vuoi imparare più a fondo il funzionamento di un tool specifico puoi fare riferimento alla sua documentazione ufficiale o puoi cercare altri tutorial più specifici. 34 | 35 | Una parte sostanziosa di questa guida fa riferimento a React. Se stai iniziando adesso e vuoi solo imparare React, [create-react-app](https://github.com/facebookincubator/create-react-app) ti preparerá molto rapidamente con un ambiente React preconfigurato. Consiglierei questo approccio ad esempio a qualcuno che entra in un team che sta giá utilizzando React e deve mettersi al passo utilizzando un ambiente per fare delle prove. In questa guida non ti faró utilizzare una configurazione prefabbricata, perché voglio che tu comprenda realmente quello che sta succedendo. 36 | 37 | Esempi di codice sono disponibili in ogni capitolo e puoi avviarli utilizzando il comando `yarn && yarn start` oppure `npm install && npm start`. Ti suggerisco di riscrivere tu tutto da zero seguendo le **istruzioni passo a passo** di ogni capitolo. 38 | 39 | **Ogni capitolo contiene il codice dei capitoli precedenti**, se ti interessa unicamente creare un progetto di base contenente tutto puoi semplicemente clonare l'ultimo capitolo e sarai pronto per iniziare. 40 | 41 | Nota: l'ordine dei capitoli non è necessariamente il più didattico. Ad esempio, i test potrebbero essere stati spiegati prima di introdurre React. È abbastanza complicato riordinare i capitoli o modificare quelli passati perchè devo replicare ogni modifica sui capitoli successivi. Quando il tutto sarà più stabile potrei riorganizzare la guida in modo migliore. 42 | 43 | Il codice presentato in questa guida funziona in Linux, macOS e Windows. 44 | 45 | ## Indice 46 | 47 | [1 - Node, NPM, Yarn, e package.json](/tutorial/1-node-npm-yarn-package-json) 48 | 49 | [2 - Installare e utilizzare un pacchetto](/tutorial/2-packages) 50 | 51 | [3 - Configurare ES6 con Babel e Gulp](/tutorial/3-es6-babel-gulp) 52 | 53 | [4 - Usare la sintassi di ES6 con una classe](/tutorial/4-es6-syntax-class) 54 | 55 | [5 - La sintassi di ES6 per i moduli](/tutorial/5-es6-modules-syntax) 56 | 57 | [6 - ESLint](/tutorial/6-eslint) 58 | 59 | [7 - App client con Webpack](/tutorial/7-client-webpack) 60 | 61 | [8 - React](/tutorial/8-react) 62 | 63 | [9 - Redux](/tutorial/9-redux) 64 | 65 | [10 - Immutable JS e Migliorie di Redux](/tutorial/10-immutable-redux-improvements) 66 | 67 | [11 - Testare con Mocha, Chai, e Sinon](/tutorial/11-testing-mocha-chai-sinon) 68 | 69 | [12 - Type Checking con Flow](/tutorial/12-flow) 70 | 71 | ## Prossimamente 72 | 73 | Ambienti di sviluppo e produzione, Express, React Router, Server-Side Rendering, Styling, Enzyme, Git Hooks. 74 | 75 | ## Traduzioni 76 | 77 | - [English](https://github.com/verekia/js-stack-from-scratch) by [@verekia](https://twitter.com/verekia) 78 | - [中文](https://github.com/pd4d10/js-stack-from-scratch) by [@pd4d10](http://github.com/pd4d10) 79 | - [Italiano](https://github.com/fbertone/js-stack-from-scratch) by [Fabrizio Bertone](https://github.com/fbertone) 80 | - [日本語](https://github.com/takahashim/js-stack-from-scratch) by [@takahashim](https://github.com/takahashim) 81 | 82 | Se vuoi aggiungere una traduzione fai riferimento a [translation recommendations](https://github.com/verekia/js-stack-from-scratch/how-to-translate.md) per cominciare! 83 | 84 | ## Credits 85 | 86 | Creato da [@verekia](https://twitter.com/verekia) – [verekia.com](http://verekia.com/). 87 | Tradotto da Fabrizio Bertone 88 | 89 | Licenza: MIT 90 | -------------------------------------------------------------------------------- /how-to-translate.md: -------------------------------------------------------------------------------- 1 | # How to translate this tutorial 2 | 3 | Thank you for your interest in translating my tutorial! Here are a few recommendations to get started. 4 | 5 | This tutorial is in constant evolution to provide the best learning experience to readers. Both the code and `README.md` files will change over time. It is great if you do a one-shot translation that won't evolve, but it would be even better if you could try to keep up with the original English version as it changes! 6 | 7 | Here is what I think is a good workflow: 8 | 9 | - Check if there is already a translation issue open for your language. If that's the case, get in touch with the folks who opened it and consider collaborating. All maintainers will be mentioned on the English repo, so team work is encouraged! You can open issues on their translation fork project to offer your help on certain chapters for instance. 10 | 11 | - Join the [Translations Gitter room](https://gitter.im/js-stack-from-scratch/Translations) if you're feeling chatty. 12 | 13 | - Fork the main [English repository](https://github.com/verekia/js-stack-from-scratch). 14 | 15 | - Open an issue on the English repo to show you're currently working on a translation. 16 | 17 | - Translate the `README.md` files. 18 | 19 | - Add a note somewhere explaining on the main `README.md` that this is a translation, with a link to the English repository. If you don't plan to make the translation evolve over time, you can maybe add a little note saying to refer to the English one for an up-to-date version of the tutorial. I'll leave that up to your preference. 20 | 21 | - Submit a Pull Request to the English repo to add a link to your forked repository under the Translations section of the main `README.md`. It could look like this: 22 | 23 | ```md 24 | ## Translations 25 | 26 | - [Language](http://github.com/yourprofile/your-fork) by [You](http://yourwebsite.com) 27 | or 28 | - [Language](http://github.com/yourprofile/your-fork) by [@You](http://twitter.com/yourprofile) 29 | or 30 | - [Language](http://github.com/yourprofile/your-fork) by [@You](http://github.com/yourprofile) 31 | ``` 32 | 33 | Since I want to reward you for your good work as much as possible, you can put any link you like on your name (to your personal website, Twitter profile, or Github profile for instance). 34 | 35 | - After your original one-shot translation, if you want to update your repo with the latest change from the main English repo, [sync your fork](https://help.github.com/articles/syncing-a-fork/) with my repo. To make it easy to see what changed since your initial translation, you can use Github's feature to [compare commits](https://help.github.com/articles/comparing-commits-across-time/#comparing-commits). Set the **base** to the last commit from the English repo you used to translate, and compare it to **master**, like so: 36 | 37 | 38 | https://github.com/verekia/js-stack-from-scratch/compare/dfab78b581a3da800daeb3686b900dd9ea972da0...master 39 | 40 | 41 | That should give you a easy-to-read diff to see exactly what changed in `README.md` files since your translation! 42 | -------------------------------------------------------------------------------- /img/chai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/js-stack-from-scratch/b67673bcb69b04abb91f9d4946a527dee8667c50/img/chai.png -------------------------------------------------------------------------------- /img/eslint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/js-stack-from-scratch/b67673bcb69b04abb91f9d4946a527dee8667c50/img/eslint.png -------------------------------------------------------------------------------- /img/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/js-stack-from-scratch/b67673bcb69b04abb91f9d4946a527dee8667c50/img/flow.png -------------------------------------------------------------------------------- /img/gulp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/js-stack-from-scratch/b67673bcb69b04abb91f9d4946a527dee8667c50/img/gulp.png -------------------------------------------------------------------------------- /img/js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/js-stack-from-scratch/b67673bcb69b04abb91f9d4946a527dee8667c50/img/js.png -------------------------------------------------------------------------------- /img/mocha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/js-stack-from-scratch/b67673bcb69b04abb91f9d4946a527dee8667c50/img/mocha.png -------------------------------------------------------------------------------- /img/npm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/js-stack-from-scratch/b67673bcb69b04abb91f9d4946a527dee8667c50/img/npm.png -------------------------------------------------------------------------------- /img/react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/js-stack-from-scratch/b67673bcb69b04abb91f9d4946a527dee8667c50/img/react.png -------------------------------------------------------------------------------- /img/redux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/js-stack-from-scratch/b67673bcb69b04abb91f9d4946a527dee8667c50/img/redux.png -------------------------------------------------------------------------------- /img/webpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/js-stack-from-scratch/b67673bcb69b04abb91f9d4946a527dee8667c50/img/webpack.png -------------------------------------------------------------------------------- /img/yarn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/js-stack-from-scratch/b67673bcb69b04abb91f9d4946a527dee8667c50/img/yarn.png -------------------------------------------------------------------------------- /mdlint.js: -------------------------------------------------------------------------------- 1 | const glob = require('glob'); 2 | const markdownlint = require('markdownlint'); 3 | 4 | const config = { 5 | 'default': true, 6 | 'line_length': false, 7 | 'no-emphasis-as-header': false 8 | } 9 | 10 | const files = glob.sync('**/*.md', { ignore: '**/node_modules/**' }); 11 | 12 | markdownlint({ files, config }, (err, result) => { 13 | if (!err) { 14 | const resultString = result.toString(); 15 | console.log('== Linting Markdown Files...'); 16 | if (resultString) { 17 | console.log(resultString); 18 | process.exit(1); 19 | } else { 20 | console.log('== OK!'); 21 | } 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-stack-from-scratch", 3 | "version": "1.0.0", 4 | "description": "JavaScript Stack from Scratch - Step-by-step tutorial to build a modern JavaScript stack", 5 | "scripts": { 6 | "test": "yarn run mdlint && cd tutorial/1-node-npm-yarn-package-json && yarn && yarn run tutorial-test && cd ../2-packages && yarn && yarn run tutorial-test && cd ../3-es6-babel-gulp && yarn && yarn run tutorial-test && cd ../4-es6-syntax-class && yarn && yarn run tutorial-test && cd ../5-es6-modules-syntax && yarn && yarn run tutorial-test && cd ../6-eslint && yarn && yarn run tutorial-test && cd ../7-client-webpack && yarn && yarn run tutorial-test && cd ../8-react && yarn && yarn run tutorial-test && cd ../9-redux && yarn && yarn run tutorial-test && cd ../10-immutable-redux-improvements && yarn && yarn run tutorial-test && cd ../11-testing-mocha-chai-sinon && yarn && yarn run tutorial-test && cd ../12-flow && yarn && yarn run tutorial-test", 7 | "mdlint": "node mdlint.js" 8 | }, 9 | "devDependencies": { 10 | "glob": "^7.1.1", 11 | "markdownlint": "^0.3.0", 12 | "yarn": "^0.16.1" 13 | }, 14 | "repository": "verekia/js-stack-from-scratch", 15 | "author": "Jonathan Verrecchia - @verekia", 16 | "license": "MIT" 17 | } 18 | -------------------------------------------------------------------------------- /tutorial/1-node-npm-yarn-package-json/README.md: -------------------------------------------------------------------------------- 1 | # 1 - Node, NPM, Yarn, e package.json 2 | 3 | In questa sezione configureremo Node, NPM, Yarn e un file `package.json` di base. 4 | 5 | Prima di tutto dobbiamo installare Node, che non è utilizzato solo per il back-end ma è la base di tutti gli strumenti necessari per creare uno stack Javascript moderno lato Front-End. 6 | 7 | Vai alla [pagina di download](https://nodejs.org/en/download/current/) per installare su Windows o mac oppure segui le istruzioni sulla [pagina di installazione](https://nodejs.org/en/download/package-manager/) per le distribuzioni Linux. 8 | 9 | 10 | Ad esempio, su **Ubuntu / Debian**, devi eseguire i seguenti comandi per installare Node: 11 | 12 | ```bash 13 | curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - 14 | sudo apt-get install -y nodejs 15 | ``` 16 | Ti serve una qualsiasi versione di Node > 6.5.0. 17 | 18 | `npm`, il package manager standard di Node, viene installato automaticamente assieme a Node, non devi quindi installarlo tu a mano. 19 | 20 | **Nota**: Se Node è già installato, installa `nvm` ([Node Version Manager](https://github.com/creationix/nvm)), utilizza `nvm` per installare in automatico l'ultima versione di Node. 21 | 22 | [Yarn](https://yarnpkg.com/) è un nuovo package manager ed è molto più veloce rispetto ad NPM, mantiene una cache dei pacchetti installati, e gestisce le dipendenze in modo più [prevedibile](https://yarnpkg.com/en/docs/yarn-lock). Da quando è [uscito](https://code.facebook.com/posts/1840075619545360) a ottobre 2016, è stato adottato molto rapidamente e sta diventando il package manager di riferimento per la comunità Javascript. In questo tutorial utilizzeremo Yarn. Se tu preferisci rimanere con NPM puoi sostituire tutti i comandi `yarn add` e `yarn add --dev` in questo tutorial rispettivamente con `npm install --save` e `npm install --dev`. 23 | 24 | - Installa Yarn seguendo le [istruzioni](https://yarnpkg.com/en/docs/install). Puoi utilizzare `npm install -g yarn` o `sudo npm install -g yarn` (si, stiamo sfruttando NPM per installare Yarn, proprio come utilizzeresti Internet Explorer o Safari per installare Chrome!). 25 | 26 | - Crea una nuova cartella di base ed entraci `cd` dentro. 27 | - Esegui `yarn init` e rispondi alle domande (`yarn init -y` per saltare tutte le domande), per generare automaticamente un file `package.json`. 28 | - Crea un file `index.js` contenente `console.log('Hello world')`. 29 | - Esegui `node .` in questa cartella (`index.js` è il file che Node cerca automaticamente all'interno della cartella corrente). Dovrebbe scrivere "Hello world". 30 | 31 | Eseguire `node .` per lanciare il nostro programma è un po' troppo di basso livello. Utilizzeremo invece uno script NPM/Yarn per avviare l'esecuzione del nostro programma. Questo ci permetterà di avere un livello di astrazione tale da poter sempre utilizare `yarn start`, anche quando il nostro programma si farà più complesso. 32 | 33 | - In `package.json`, aggiungi un oggetto `scripts` all'oggetto di base, strutturato cosí: 34 | 35 | ```json 36 | "scripts": { 37 | "start": "node ." 38 | } 39 | ``` 40 | 41 | `package.json` deve essere un file JSON valido, il che significa che non puoi avere delle virgole "finali" che sono invece utilizzabili nei normali oggetti Javascript. Fai quindi molta attenzione quando modifichi a mano il tuo file `package.json`. 42 | 43 | - Esegui `yarn start`. Dovrebbe scrivere `Hello world`. 44 | 45 | - Crea un file `.gitignore` ed aggiungici le seguenti righe: 46 | 47 | ```gitignore 48 | npm-debug.log 49 | yarn-error.log 50 | ``` 51 | 52 | **Nota**: Se dai un'occhiata a file `package.json` che fornisco, vedrai uno script `tutorial-test` in ogni capitolo. Questi script mi permettono di verificare che i capitoli sono a posto eseguendo `yarn && yarn start`. Puoi cancellarli tranquillamente nei tuoi progetti. 53 | 54 | Prossima sezione: [2 - Installare ed usare un pacchetto](/tutorial/2-packages) 55 | 56 | Torna all'[indice](https://github.com/fbertone/js-stack-from-scratch). 57 | -------------------------------------------------------------------------------- /tutorial/1-node-npm-yarn-package-json/index.js: -------------------------------------------------------------------------------- 1 | console.log('Hello world'); 2 | -------------------------------------------------------------------------------- /tutorial/1-node-npm-yarn-package-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-stack-from-scratch", 3 | "version": "1.0.0", 4 | "description": "JavaScript Stack from Scratch - Step-by-step tutorial to build a modern JavaScript stack", 5 | "scripts": { 6 | "start": "node .", 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "tutorial-test": "yarn start" 9 | }, 10 | "repository": "verekia/js-stack-from-scratch", 11 | "author": "Jonathan Verrecchia - @verekia", 12 | "license": "MIT" 13 | } 14 | -------------------------------------------------------------------------------- /tutorial/10-immutable-redux-improvements/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | yarn-error.log 4 | /lib/ 5 | /dist/client-bundle.js* 6 | -------------------------------------------------------------------------------- /tutorial/10-immutable-redux-improvements/README.md: -------------------------------------------------------------------------------- 1 | # 10 - Immutable JS e Migliorie Redux 2 | 3 | ## Immutable JS 4 | 5 | A differenza del capitolo precedente, questo é abbastanza semplice e consiste in piccoli miglioramenti. 6 | 7 | Per prima cosa aggiungeremo **Immutable JS** al nostro codice. Immutable é una libreria per manipolare oggetti senza modificarli. Invece di fare: 8 | 9 | ```javascript 10 | const obj = { a: 1 }; 11 | obj.a = 2; // Mutates `obj` 12 | ``` 13 | 14 | Faresti: 15 | 16 | ```javascript 17 | const obj = Immutable.Map({ a: 1 }); 18 | obj.set('a', 2); // Returns a new object without mutating `obj` 19 | ``` 20 | 21 | Questo approccio segue il paradigma della **programmazione funzionale**, che funziona molto bene con Redux. Le tue funzioni reducer *devono* essere funzioni pure che non alterano lo stato passato come parametro, ma ritornano invece un nuovo oggetto. Usiamo Immutable per assicurarci che sia cosí. 22 | 23 | - Esegui `yarn add immutable` 24 | 25 | Utilizzeremo `Map` nel nostro codice, ma ESLint e la configurazione Airbnb si lamenteranno dell'utilizzo di una dell'iniziale maiuscola per quella che non é una classe. Aggiungi questo al `package.json` sotto `eslintConfig`: 26 | 27 | ```json 28 | "rules": { 29 | "new-cap": [ 30 | 2, 31 | { 32 | "capIsNewExceptions": [ 33 | "Map", 34 | "List" 35 | ] 36 | } 37 | ] 38 | } 39 | ``` 40 | 41 | Questo fa in modo che `Map` e `List` (i due oggetti di Immutable che utilizzeremo in continuazione) siano delle eccezioni alle regole di ESLint. Questa formattazione JSON cosí prolissa é generata automaticamente da Yarn/NPM, non possiamo quindi renderla piú compatta. 42 | 43 | Ad ogni modo, torniamo a Immutable: 44 | 45 | Modifica `dog-reducer.js` in modo che diventi cosí: 46 | 47 | ```javascript 48 | import Immutable from 'immutable'; 49 | import { MAKE_BARK } from '../actions/dog-actions'; 50 | 51 | const initialState = Immutable.Map({ 52 | hasBarked: false, 53 | }); 54 | 55 | const dogReducer = (state = initialState, action) => { 56 | switch (action.type) { 57 | case MAKE_BARK: 58 | return state.set('hasBarked', action.payload); 59 | default: 60 | return state; 61 | } 62 | }; 63 | 64 | export default dogReducer; 65 | ``` 66 | 67 | Lo stato iniziale viene adesso creato utilizzando una Map di Immutable, e il nuovo stato viene generato utilizzando `set()`, impedendo ogni modifica allo stato precedente. 68 | 69 | In `containers/bark-message.js`, aggiorna la funzione `mapStateToProps` in modo da usare `.get('hasBarked')` al posto di `.hasBarked`: 70 | 71 | ```javascript 72 | const mapStateToProps = state => ({ 73 | message: state.dog.get('hasBarked') ? 'The dog barked' : 'The dog did not bark', 74 | }); 75 | ``` 76 | 77 | L'app dovrebbe ancora comportarsi esattamente come prima. 78 | 79 | **Nota**: Se Babel si lamenta del fatto che Immutable supera i 100KB, aggiungi `"compact": false` nel `package.json` alla voce `babel`. 80 | 81 | Come puoi vedere dal pezzo di codice precedente, il nostro oggetto di stato contiene ancora l'attributo `dog` che non é immutabile. Va bene cosí, ma se vuoi manipolare esclusivamente oggetti immutabili, puoi installare il pacchetto `redux-immutable` per sostituire la funzione `combineReducers` di Redux. 82 | 83 | **Opzionale**: 84 | 85 | - Esegui `yarn add redux-immutable` 86 | - Sostituisci la funzione `combineReducers` in `app.jsx` per usare quella importata da `redux-immutable`. 87 | - In `bark-message.js` sostituisci `state.dog.get('hasBarked')` con `state.getIn(['dog', 'hasBarked'])`. 88 | 89 | ## Azioni Redux 90 | 91 | Man mano che aggiungi sempre piú azioni alla tua app, ti accorgerai che stai scrivendo molto codice ripetuto. Il pacchetto `redux-actions` ti aiuterá a ridurre le ripetizioni. Con `redux-actions` puoi riscrivere il file `dog-actions.js` in modo piú compatto: 92 | 93 | ```javascript 94 | import { createAction } from 'redux-actions'; 95 | 96 | export const MAKE_BARK = 'MAKE_BARK'; 97 | export const makeBark = createAction(MAKE_BARK, () => true); 98 | ``` 99 | 100 | `redux-actions` implementa il modello di [Azione Standard Flux](https://github.com/acdlite/flux-standard-action), proprio come l'azione che abbiamo scritto precedentemente, quindi integrare `redux-actions` sará del tutto lineare se segui questo modello. 101 | 102 | - Non dimenticarti di eseguire `yarn add redux-actions`. 103 | 104 | Prossima sezione: [11 - Testare con Mocha, Chai e Sinon](/tutorial/11-testing-mocha-chai-sinon) 105 | 106 | Torna alla [sezione precedente](/tutorial/9-redux) o all'[indice](https://github.com/fbertone/js-stack-from-scratch). 107 | -------------------------------------------------------------------------------- /tutorial/10-immutable-redux-improvements/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tutorial/10-immutable-redux-improvements/gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | 3 | import gulp from 'gulp'; 4 | import babel from 'gulp-babel'; 5 | import eslint from 'gulp-eslint'; 6 | import del from 'del'; 7 | import webpack from 'webpack-stream'; 8 | import webpackConfig from './webpack.config.babel'; 9 | 10 | const paths = { 11 | allSrcJs: 'src/**/*.js?(x)', 12 | serverSrcJs: 'src/server/**/*.js?(x)', 13 | sharedSrcJs: 'src/shared/**/*.js?(x)', 14 | clientEntryPoint: 'src/client/app.jsx', 15 | clientBundle: 'dist/client-bundle.js?(.map)', 16 | gulpFile: 'gulpfile.babel.js', 17 | webpackFile: 'webpack.config.babel.js', 18 | libDir: 'lib', 19 | distDir: 'dist', 20 | }; 21 | 22 | gulp.task('lint', () => 23 | gulp.src([ 24 | paths.allSrcJs, 25 | paths.gulpFile, 26 | paths.webpackFile, 27 | ]) 28 | .pipe(eslint()) 29 | .pipe(eslint.format()) 30 | .pipe(eslint.failAfterError()) 31 | ); 32 | 33 | gulp.task('clean', () => del([ 34 | paths.libDir, 35 | paths.clientBundle, 36 | ])); 37 | 38 | gulp.task('build', ['lint', 'clean'], () => 39 | gulp.src(paths.allSrcJs) 40 | .pipe(babel()) 41 | .pipe(gulp.dest(paths.libDir)) 42 | ); 43 | 44 | gulp.task('main', ['lint', 'clean'], () => 45 | gulp.src(paths.clientEntryPoint) 46 | .pipe(webpack(webpackConfig)) 47 | .pipe(gulp.dest(paths.distDir)) 48 | ); 49 | 50 | gulp.task('watch', () => { 51 | gulp.watch(paths.allSrcJs, ['main']); 52 | }); 53 | 54 | gulp.task('default', ['watch', 'main']); 55 | -------------------------------------------------------------------------------- /tutorial/10-immutable-redux-improvements/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-stack-from-scratch", 3 | "version": "1.0.0", 4 | "description": "JavaScript Stack from Scratch - Step-by-step tutorial to build a modern JavaScript stack", 5 | "scripts": { 6 | "start": "gulp", 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "tutorial-test": "gulp main" 9 | }, 10 | "eslintConfig": { 11 | "extends": "airbnb", 12 | "plugins": [ 13 | "import" 14 | ], 15 | "env": { 16 | "browser": true 17 | }, 18 | "rules": { 19 | "new-cap": [ 20 | 2, 21 | { 22 | "capIsNewExceptions": [ 23 | "Map", 24 | "List" 25 | ] 26 | } 27 | ] 28 | } 29 | }, 30 | "babel": { 31 | "presets": [ 32 | "latest", 33 | "react" 34 | ], 35 | "compact": false 36 | }, 37 | "dependencies": { 38 | "babel-polyfill": "^6.16.0", 39 | "immutable": "^3.8.1", 40 | "react": "^15.3.2", 41 | "react-dom": "^15.3.2", 42 | "react-redux": "^4.4.5", 43 | "redux": "^3.6.0", 44 | "redux-actions": "^0.12.0", 45 | "redux-immutable": "^3.0.8" 46 | }, 47 | "devDependencies": { 48 | "babel-loader": "^6.2.5", 49 | "babel-preset-latest": "^6.16.0", 50 | "babel-preset-react": "^6.16.0", 51 | "del": "^2.2.2", 52 | "eslint": "^3.8.1", 53 | "eslint-config-airbnb": "^12.0.0", 54 | "eslint-plugin-import": "^2.0.1", 55 | "eslint-plugin-jsx-a11y": "^2.2.3", 56 | "eslint-plugin-react": "^6.4.1", 57 | "gulp": "^3.9.1", 58 | "gulp-babel": "^6.1.2", 59 | "gulp-eslint": "^3.0.1", 60 | "webpack-stream": "^3.2.0" 61 | }, 62 | "repository": "verekia/js-stack-from-scratch", 63 | "author": "Jonathan Verrecchia - @verekia", 64 | "license": "MIT" 65 | } 66 | -------------------------------------------------------------------------------- /tutorial/10-immutable-redux-improvements/src/client/actions/dog-actions.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | 3 | export const MAKE_BARK = 'MAKE_BARK'; 4 | export const makeBark = createAction(MAKE_BARK, () => true); 5 | -------------------------------------------------------------------------------- /tutorial/10-immutable-redux-improvements/src/client/app.jsx: -------------------------------------------------------------------------------- 1 | import 'babel-polyfill'; 2 | 3 | import React from 'react'; 4 | import ReactDOM from 'react-dom'; 5 | import { createStore } from 'redux'; 6 | import { Provider } from 'react-redux'; 7 | import { combineReducers } from 'redux-immutable'; 8 | import dogReducer from './reducers/dog-reducer'; 9 | import BarkMessage from './containers/bark-message'; 10 | import BarkButton from './containers/bark-button'; 11 | 12 | const store = createStore(combineReducers({ 13 | dog: dogReducer, 14 | })); 15 | 16 | ReactDOM.render( 17 |