├── .travis.yml ├── .gitignore ├── img ├── chai.png ├── flow.png ├── jest.png ├── js.png ├── npm.png ├── pm2.png ├── yarn.png ├── eslint.png ├── mocha.png ├── react.png ├── redux.png ├── js-padded.png ├── webpack.png ├── flow-padded.png ├── jest-padded.png ├── pm2-padded.png ├── yarn-padded.png ├── eslint-padded.png ├── flow-padded-90.png ├── jest-padded-90.png ├── pm2-padded-90.png ├── react-padded.png ├── react-router.png ├── redux-padded.png ├── webpack-padded.png ├── yarn-padded-90.png ├── bootstrap-padded.png ├── eslint-padded-90.png ├── react-padded-90.png ├── redux-padded-90.png ├── bootstrap-padded-90.png ├── react-router-padded.png ├── webpack-padded-90.png └── react-router-padded-90.png ├── package.json ├── .github └── ISSUE_TEMPLATE ├── mdlint.js ├── LICENSE.md ├── CHANGELOG.md ├── how-to-translate.md ├── yarn.lock ├── README.md └── tutorial ├── 07-socket-io.md ├── 09-travis-coveralls-heroku.md ├── 01-node-yarn-package-json.md ├── 03-express-nodemon-pm2.md ├── 04-webpack-react-hmr.md ├── 08-bootstrap-jss.md ├── 06-react-router-ssr-helmet.md ├── 02-babel-es6-eslint-flow-jest-husky.md └── 05-redux-immutable-fetch.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: node 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | 5 | -------------------------------------------------------------------------------- /img/chai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/chai.png -------------------------------------------------------------------------------- /img/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/flow.png -------------------------------------------------------------------------------- /img/jest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/jest.png -------------------------------------------------------------------------------- /img/js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/js.png -------------------------------------------------------------------------------- /img/npm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/npm.png -------------------------------------------------------------------------------- /img/pm2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/pm2.png -------------------------------------------------------------------------------- /img/yarn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/yarn.png -------------------------------------------------------------------------------- /img/eslint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/eslint.png -------------------------------------------------------------------------------- /img/mocha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/mocha.png -------------------------------------------------------------------------------- /img/react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/react.png -------------------------------------------------------------------------------- /img/redux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/redux.png -------------------------------------------------------------------------------- /img/js-padded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/js-padded.png -------------------------------------------------------------------------------- /img/webpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/webpack.png -------------------------------------------------------------------------------- /img/flow-padded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/flow-padded.png -------------------------------------------------------------------------------- /img/jest-padded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/jest-padded.png -------------------------------------------------------------------------------- /img/pm2-padded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/pm2-padded.png -------------------------------------------------------------------------------- /img/yarn-padded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/yarn-padded.png -------------------------------------------------------------------------------- /img/eslint-padded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/eslint-padded.png -------------------------------------------------------------------------------- /img/flow-padded-90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/flow-padded-90.png -------------------------------------------------------------------------------- /img/jest-padded-90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/jest-padded-90.png -------------------------------------------------------------------------------- /img/pm2-padded-90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/pm2-padded-90.png -------------------------------------------------------------------------------- /img/react-padded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/react-padded.png -------------------------------------------------------------------------------- /img/react-router.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/react-router.png -------------------------------------------------------------------------------- /img/redux-padded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/redux-padded.png -------------------------------------------------------------------------------- /img/webpack-padded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/webpack-padded.png -------------------------------------------------------------------------------- /img/yarn-padded-90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/yarn-padded-90.png -------------------------------------------------------------------------------- /img/bootstrap-padded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/bootstrap-padded.png -------------------------------------------------------------------------------- /img/eslint-padded-90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/eslint-padded-90.png -------------------------------------------------------------------------------- /img/react-padded-90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/react-padded-90.png -------------------------------------------------------------------------------- /img/redux-padded-90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/redux-padded-90.png -------------------------------------------------------------------------------- /img/bootstrap-padded-90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/bootstrap-padded-90.png -------------------------------------------------------------------------------- /img/react-router-padded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/react-router-padded.png -------------------------------------------------------------------------------- /img/webpack-padded-90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/webpack-padded-90.png -------------------------------------------------------------------------------- /img/react-router-padded-90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertone/guida-javascript-moderno/HEAD/img/react-router-padded-90.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-stack-from-scratch", 3 | "version": "2.4.5", 4 | "description": "JavaScript Stack from Scratch - Step-by-step tutorial to build a modern JavaScript stack", 5 | "scripts": { 6 | "test": "node mdlint.js" 7 | }, 8 | "devDependencies": { 9 | "glob": "^7.1.1", 10 | "markdownlint": "^0.4.0" 11 | }, 12 | "repository": "verekia/js-stack-from-scratch", 13 | "author": "Jonathan Verrecchia - @verekia", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE: -------------------------------------------------------------------------------- 1 | ### Type of issue: (feature suggestion, bug?) 2 | 3 | ### Chapter: 4 | 5 | ### If it's a bug: 6 | 7 | Please try using the code provided instead of your own to see if that solves the issue. If it does, compare the content of relevant files to see if anything is missing in your version. Every chapter is automatically tested, so issues are likely coming from missing an instruction in the tutorial or a typo. Feel free to open an issue if there is a problem with instructions though. 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2017 Jonathan Verrecchia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## v2.4.5 4 | 5 | - Add `babel-plugin-flow-react-proptypes`. 6 | - Add `eslint-plugin-compat`. 7 | - Add JSS `composes` example. 8 | 9 | ## v2.4.4 10 | 11 | - Update Immutable to remove the `import * as Immutable from 'immutable'` syntax. 12 | - Declare Flow types outside of function params for React components. 13 | - Improve Webpack `publicPath`. 14 | 15 | ## V2, up to v2.4.3 16 | 17 | - Gulp is gone, replaced by NPM (Yarn) scripts. 18 | - Express has been added, with template strings for static HTML. Gzip compression enabled. 19 | - Support for development environment with Nodemon and production environment with PM2. 20 | - Minification or sourcemaps depending on the environment via Webpack. 21 | - Add Webpack Dev Server, with Hot Module Replacement and `react-hot-loader`. 22 | - Add an asynchronous call example with `redux-thunk`. 23 | - Linting / type checking / testing is not launched at every file change anymore, but triggered by Git Hooks via Husky. 24 | - Some chapters have been combined to make it easier to maintain the tutorial. 25 | - Replace Chai and Mocha by Jest. 26 | - Add React-Router, Server-Side rendering, `react-helmet`. 27 | - Rename all "dog" things and replaced it by "hello" things. It's a Hello World app after all. 28 | - Add Twitter Bootstrap, JSS, and `react-jss` for styling. 29 | - Add a Websocket example with Socket.IO. 30 | - Add optional Heroku, Travis, and Coveralls integrations. 31 | -------------------------------------------------------------------------------- /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 an [ongoing translation](https://github.com/verekia/js-stack-from-scratch/issues/147) 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 | - Post in [this issue](https://github.com/verekia/js-stack-from-scratch/issues/147) the language and URL of your forked repo. 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/c65dfa65d02c21063d94f0955de90947ba5273ad...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 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | argparse@^1.0.7: 6 | version "1.0.9" 7 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" 8 | dependencies: 9 | sprintf-js "~1.0.2" 10 | 11 | balanced-match@^0.4.1: 12 | version "0.4.2" 13 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" 14 | 15 | brace-expansion@^1.0.0: 16 | version "1.1.6" 17 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" 18 | dependencies: 19 | balanced-match "^0.4.1" 20 | concat-map "0.0.1" 21 | 22 | concat-map@0.0.1: 23 | version "0.0.1" 24 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 25 | 26 | entities@~1.1.1: 27 | version "1.1.1" 28 | resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" 29 | 30 | fs.realpath@^1.0.0: 31 | version "1.0.0" 32 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 33 | 34 | glob@^7.1.1: 35 | version "7.1.1" 36 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" 37 | dependencies: 38 | fs.realpath "^1.0.0" 39 | inflight "^1.0.4" 40 | inherits "2" 41 | minimatch "^3.0.2" 42 | once "^1.3.0" 43 | path-is-absolute "^1.0.0" 44 | 45 | inflight@^1.0.4: 46 | version "1.0.6" 47 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 48 | dependencies: 49 | once "^1.3.0" 50 | wrappy "1" 51 | 52 | inherits@2: 53 | version "2.0.3" 54 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 55 | 56 | linkify-it@^2.0.0: 57 | version "2.0.3" 58 | resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" 59 | dependencies: 60 | uc.micro "^1.0.1" 61 | 62 | markdown-it@^8.3.0: 63 | version "8.3.1" 64 | resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.3.1.tgz#2f4b622948ccdc193d66f3ca2d43125ac4ac7323" 65 | dependencies: 66 | argparse "^1.0.7" 67 | entities "~1.1.1" 68 | linkify-it "^2.0.0" 69 | mdurl "^1.0.1" 70 | uc.micro "^1.0.3" 71 | 72 | markdownlint@^0.4.0: 73 | version "0.4.0" 74 | resolved "https://registry.yarnpkg.com/markdownlint/-/markdownlint-0.4.0.tgz#5be8a342c4ab4d5c6cfe8702db30c63bbed01589" 75 | dependencies: 76 | markdown-it "^8.3.0" 77 | 78 | mdurl@^1.0.1: 79 | version "1.0.1" 80 | resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" 81 | 82 | minimatch@^3.0.2: 83 | version "3.0.3" 84 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" 85 | dependencies: 86 | brace-expansion "^1.0.0" 87 | 88 | once@^1.3.0: 89 | version "1.4.0" 90 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 91 | dependencies: 92 | wrappy "1" 93 | 94 | path-is-absolute@^1.0.0: 95 | version "1.0.1" 96 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 97 | 98 | sprintf-js@~1.0.2: 99 | version "1.0.3" 100 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 101 | 102 | uc.micro@^1.0.1, uc.micro@^1.0.3: 103 | version "1.0.3" 104 | resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" 105 | 106 | wrappy@1: 107 | version "1.0.2" 108 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Guida alla creazione di un progetto Javascript Moderno 2 | 3 | [](https://travis-ci.org/verekia/js-stack-from-scratch) 4 | [](https://github.com/verekia/js-stack-from-scratch/releases) 5 | [](https://david-dm.org/verekia/js-stack-boilerplate) 6 | [](https://david-dm.org/verekia/js-stack-boilerplate?type=dev) 7 | [](https://gitter.im/js-stack-from-scratch/) 8 | 9 | [](https://facebook.github.io/react/) 10 | [](http://redux.js.org/) 11 | [](https://github.com/ReactTraining/react-router) 12 | [](https://flowtype.org/) 13 | [](http://eslint.org/) 14 | [](https://facebook.github.io/jest/) 15 | [](https://yarnpkg.com/) 16 | [](https://webpack.github.io/) 17 | [](http://getbootstrap.com/) 18 | 19 | Benvenuto a questa guida: **Guida alla creazione di un progetto Javascript Moderno**. 20 | 21 | > 🎉 **Questa è la seconda versione della guida, grosse modifiche sono state fatte rispetto alla prima. Controlla il [Change Log](/CHANGELOG.md)!** 22 | 23 | Questa è una guida essenziale per la costruzione di uno stack Javascript utilizzando gli strumenti più attuali. Richiede qualche conoscienza generica di programmazione ed alcune basi di Javascript. **È focalizzata sull'utilizzo in sequenza di alcuni tool** e ti presenta **l'esempio più semplice possibile** per ogni tool. Puoi vedere questa guida come *un modo per scrivere il tuo boilerplate personale partendo da zero*. Siccome l'obiettivo di questa guida è l'utilizzo combinato di una serie di tool, non ti spiegherò nel dettaglio come funziona ciascun tool da solo. Fai riferimento alla loro documentazione o cerca altri tutorial se ti interessa approfondire maggiormente. 24 | 25 | Chiaramente non avrai bisogno di utilizzare tutto lo stack se devi solo creare una semplice pagina web con poche interazioni in JS (una combinazione di Browserify/Webpack + Babel + jQuery è sufficiente per poter scrivere codice ES6 in file separati), ma se vuoi creare una web app scalabile, ed hai bisogno di un aiuto per configurare il tutto, questo tutorial farà proprio al tuo caso. 26 | 27 | Una buona parte dello stack descritto in questa guida utilizza React. Se sei un principiante e vuoi solo imparare React, il progetto [create-react-app](https://github.com/facebookincubator/create-react-app) ti permetterà di avere un ambiente React funzionante molto rapidamente, utilizzando una configurazione già pronta. Consiglierei questa strada a chi ad esempio entra in un team che utilizza già React e deve mettersi al passo utilizzando un ambiente semplice per fare delle prove. In questa guida non ti fornirò una configurazione già pronta perchè voglio che tu comprenda tutto il procedimento che c'è dietro. 28 | 29 | Esempi di codice sono inclusi in ogni capitolo, puoi avviarli utilizzando i comandi `yarn && yarn start`. Ti consiglio comunque di riscrivere tutto per conto tuo seguendo le **istruzioni passo a passo**. 30 | 31 | Il codice completo è disponibile in questo repository: [JS-Stack-Boilerplate](https://github.com/verekia/js-stack-boilerplate) e nelle [release](https://github.com/verekia/js-stack-from-scratch/releases). C'è anche una [demo live](https://js-stack.herokuapp.com/) 32 | 33 | Funziona su Linux, macOS, e Windows. 34 | 35 | > **Nota**: Da quando questo tutorial è stato aggiornato a maggio 2017, alcune librerie hanno leggermente modificato le loro API. 95% del tutorial è ancora perfettamente valido, ma se riscontri dei problemi, assicurati di controllare gli [open issues](https://github.com/verekia/js-stack-from-scratch/issues?q=is%3Aopen+is%3Aissue+label%3Abug). 36 | 37 | [01 - Node, Yarn, `package.json`](/tutorial/01-node-yarn-package-json.md#readme) 38 | 39 | [02 - Babel, ES6, ESLint, Flow, Jest, Husky](/tutorial/02-babel-es6-eslint-flow-jest-husky.md#readme) 40 | 41 | [03 - Express, Nodemon, PM2](/tutorial/03-express-nodemon-pm2.md#readme) 42 | 43 | [04 - Webpack, React, HMR](/tutorial/04-webpack-react-hmr.md#readme) 44 | 45 | [05 - Redux, Immutable, Fetch](/tutorial/05-redux-immutable-fetch.md#readme) 46 | 47 | [06 - React Router, Server-Side Rendering, Helmet](/tutorial/06-react-router-ssr-helmet.md#readme) 48 | 49 | [07 - Socket.IO](/tutorial/07-socket-io.md#readme) 50 | 51 | [08 - Bootstrap, JSS](/tutorial/08-bootstrap-jss.md#readme) 52 | 53 | [09 - Travis, Coveralls, Heroku](/tutorial/09-travis-coveralls-heroku.md#readme) 54 | 55 | ## Prossimamente 56 | 57 | Impostare il tuo editor (Atom inizialmente), MongoDB, Progressive Web App, E2E testing. 58 | 59 | ## Traduzioni 60 | 61 | Se vuoi aggiungere la tua traduzione, leggi le [raccomandazioni](/how-to-translate.md) per iniziare! 62 | 63 | ### V2 64 | 65 | Presto nuove traduzioni ;) 66 | 67 | - [Bulgarian](https://github.com/mihailgaberov/js-stack-from-scratch) by [mihailgaberov](http://github.com/mihailgaberov) 68 | - [Chinese (simplified)](https://github.com/yepbug/js-stack-from-scratch/) by [@yepbug](https://github.com/yepbug) 69 | - [French](https://github.com/naomihauret/js-stack-from-scratch/) by [Naomi Hauret](https://twitter.com/naomihauret) 70 | - [Italian](https://github.com/fbertone/guida-javascript-moderno) by [Fabrizio Bertone](https://github.com/fbertone) - [fbertone.it](http://fbertone.it) 71 | 72 | Controlla le [traduzioni in corso](https://github.com/verekia/js-stack-from-scratch/issues/147). 73 | 74 | ### V1 75 | 76 | - [Chinese (simplified)](https://github.com/pd4d10/js-stack-from-scratch) by [@pd4d10](http://github.com/pd4d10) 77 | - [Italian](https://github.com/fbertone/js-stack-from-scratch) by [Fabrizio Bertone](https://github.com/fbertone) 78 | - [Japanese](https://github.com/takahashim/js-stack-from-scratch) by [@takahashim](https://github.com/takahashim) 79 | - [Russian](https://github.com/UsulPro/js-stack-from-scratch) by [React Theming](https://github.com/sm-react/react-theming) 80 | - [Thai](https://github.com/MicroBenz/js-stack-from-scratch) by [MicroBenz](https://github.com/MicroBenz) 81 | 82 | ## Credits 83 | 84 | Versione originale creata da [@verekia](https://twitter.com/verekia) – [verekia.com](http://verekia.com/). 85 | Traduzione di [Fabrizio Bertone](https://github.com/fbertone) – [fbertone.it](http://fbertone.it/). 86 | 87 | Licenza: MIT 88 | -------------------------------------------------------------------------------- /tutorial/07-socket-io.md: -------------------------------------------------------------------------------- 1 | # 07 - Socket.IO 2 | 3 | Il codice di questo capitolo è disponibile [qua](https://github.com/verekia/js-stack-walkthrough/tree/master/07-socket-io). 4 | 5 | > 💡 **[Socket.IO](https://github.com/socketio/socket.io)** è una libreria per utilizzare in modo semplice i Websocket. Fornisce delle comode API e supporta delle soluzioni alternative per i browser che non implementano i nativamente Websocket. 6 | 7 | In questo capitolo configureremo un semplice scambio di messaggi tra il client ed il server. Per non aggiungere ulteriori pagine e component – che sarebbero scollegati dalle funzionalità che ci interessano – implementeremo questo scambio di messaggi direttamente nella console del browser. Niente UI per questo capitolo. 8 | 9 | - Esegui `yarn add socket.io socket.io-client` 10 | 11 | ## Server-side 12 | 13 | - Modifica `src/server/index.js` in questo modo: 14 | 15 | ```js 16 | // @flow 17 | 18 | import compression from 'compression' 19 | import express from 'express' 20 | import { Server } from 'http' 21 | import socketIO from 'socket.io' 22 | 23 | import routing from './routing' 24 | import { WEB_PORT, STATIC_PATH } from '../shared/config' 25 | import { isProd } from '../shared/util' 26 | import setUpSocket from './socket' 27 | 28 | const app = express() 29 | // flow-disable-next-line 30 | const http = Server(app) 31 | const io = socketIO(http) 32 | setUpSocket(io) 33 | 34 | app.use(compression()) 35 | app.use(STATIC_PATH, express.static('dist')) 36 | app.use(STATIC_PATH, express.static('public')) 37 | 38 | routing(app) 39 | 40 | http.listen(WEB_PORT, () => { 41 | // eslint-disable-next-line no-console 42 | console.log(`Server running on port ${WEB_PORT} ${isProd ? '(production)' : 43 | '(development).\nKeep "yarn dev:wds" running in an other terminal'}.`) 44 | }) 45 | ``` 46 | 47 | Nota che per permettere a Socket.IO di funzionare, devi usare `Server` di `http` in modalità `listen` per le richieste in arrivo, e non `app` di Express. Per fortuna non cambia molto nel codice. Tutti i dettagli dei Websocket sono configurati in un file esterno, richiamato da `setUpSocket`. 48 | 49 | - Aggiungi le seguenti costanti in `src/shared/config.js`: 50 | 51 | ```js 52 | export const IO_CONNECT = 'connect' 53 | export const IO_DISCONNECT = 'disconnect' 54 | export const IO_CLIENT_HELLO = 'IO_CLIENT_HELLO' 55 | export const IO_CLIENT_JOIN_ROOM = 'IO_CLIENT_JOIN_ROOM' 56 | export const IO_SERVER_HELLO = 'IO_SERVER_HELLO' 57 | ``` 58 | 59 | Questi sono i *tipi di messaggi* che il client ed il server si scambieranno. Ti consiglio di usare come prefisso `IO_CLIENT` o `IO_SERVER` per rendere chiaro *chi* sta inviando il messaggio. Altrimenti le cose possono farsi parecchio confuse quando hai molti tipi di messaggio. 60 | 61 | Come puoi vedere, abbiamo un `IO_CLIENT_JOIN_ROOM`, perchè come dimostrazione faremo in modo che i client si colleghino ad una room (come una chatroom). Le room sono utili per inviare i messaggi in broadcast ad una serie di utenti. 62 | 63 | - Crea `src/server/socket.js` contenente: 64 | 65 | ```js 66 | // @flow 67 | 68 | import { 69 | IO_CONNECT, 70 | IO_DISCONNECT, 71 | IO_CLIENT_JOIN_ROOM, 72 | IO_CLIENT_HELLO, 73 | IO_SERVER_HELLO, 74 | } from '../shared/config' 75 | 76 | /* eslint-disable no-console */ 77 | const setUpSocket = (io: Object) => { 78 | io.on(IO_CONNECT, (socket) => { 79 | console.log('[socket.io] A client connected.') 80 | 81 | socket.on(IO_CLIENT_JOIN_ROOM, (room) => { 82 | socket.join(room) 83 | console.log(`[socket.io] A client joined room ${room}.`) 84 | 85 | io.emit(IO_SERVER_HELLO, 'Hello everyone!') 86 | io.to(room).emit(IO_SERVER_HELLO, `Hello clients of room ${room}!`) 87 | socket.emit(IO_SERVER_HELLO, 'Hello you!') 88 | }) 89 | 90 | socket.on(IO_CLIENT_HELLO, (clientMessage) => { 91 | console.log(`[socket.io] Client: ${clientMessage}`) 92 | }) 93 | 94 | socket.on(IO_DISCONNECT, () => { 95 | console.log('[socket.io] A client disconnected.') 96 | }) 97 | }) 98 | } 99 | /* eslint-enable no-console */ 100 | 101 | export default setUpSocket 102 | ``` 103 | 104 | Okay, in questo file abbiamo implementato *come il server dovrebbe reagire quando dei client si collegano o inviano dei messaggi*: 105 | 106 | - Quando il client si connette, lo logghiamo nella console del server, ed utilizziamo l'oggetto `socket`, attraverso il quale possiamo comunicare con il client. 107 | - Quando un client invia `IO_CLIENT_JOIN_ROOM`, lo facciamo accedere alla `room` che desidera. Quando si è collegato ad una room, inviamo 3 messaggi: 1 un messaggio ad ogni utente, 1 messaggio agli utenti della room, 1 messaggio solo a quel client. 108 | - Quando il client invia `IO_CLIENT_HELLO`, logghiamo il messaggio nella console del server. 109 | - Quando il client si disconnette, logghiamo anche questo evento. 110 | 111 | ## Client-side 112 | 113 | Il lato client sarà molto simile. 114 | 115 | - Modifica `src/client/index.jsx` così: 116 | 117 | ```js 118 | // [...] 119 | import setUpSocket from './socket' 120 | 121 | // [at the very end of the file] 122 | setUpSocket(store) 123 | ``` 124 | 125 | Come puoi vedere, passiamo lo store di Redux a `setUpSocket`. In questo modo quando un messaggio Websocket che arriva dal server deve modificare lo stato Redux del client, possiamo fare il `dispatch` delle azioni. Tuttavia in questo esempio non eseguiremo il `dispatch` di niente. 126 | 127 | - Crea `src/client/socket.js` contenente: 128 | 129 | ```js 130 | // @flow 131 | 132 | import socketIOClient from 'socket.io-client' 133 | 134 | import { 135 | IO_CONNECT, 136 | IO_DISCONNECT, 137 | IO_CLIENT_HELLO, 138 | IO_CLIENT_JOIN_ROOM, 139 | IO_SERVER_HELLO, 140 | } from '../shared/config' 141 | 142 | const socket = socketIOClient(window.location.host) 143 | 144 | /* eslint-disable no-console */ 145 | // eslint-disable-next-line no-unused-vars 146 | const setUpSocket = (store: Object) => { 147 | socket.on(IO_CONNECT, () => { 148 | console.log('[socket.io] Connected.') 149 | socket.emit(IO_CLIENT_JOIN_ROOM, 'hello-1234') 150 | socket.emit(IO_CLIENT_HELLO, 'Hello!') 151 | }) 152 | 153 | socket.on(IO_SERVER_HELLO, (serverMessage) => { 154 | console.log(`[socket.io] Server: ${serverMessage}`) 155 | }) 156 | 157 | socket.on(IO_DISCONNECT, () => { 158 | console.log('[socket.io] Disconnected.') 159 | }) 160 | } 161 | /* eslint-enable no-console */ 162 | 163 | export default setUpSocket 164 | ``` 165 | 166 | Quello che succede qua non dovrebbe sorprenderti se hai capido quello che abbiamo fatto nel server: 167 | 168 | - Appena il client si collega, lo logghiamo nella console del browser ed entriamo in `hello-1234` tramite un messaggio `IO_CLIENT_JOIN_ROOM`. 169 | - Successivamente inviamo `Hello!` tramite un messaggio `IO_CLIENT_HELLO`. 170 | - Se il server ci invia un messaggio `IO_SERVER_HELLO`, lo logghiamo nella console del browser. 171 | - Logghiamo anche ogni eventuale disconnessione. 172 | 173 | 🏁 Esegui `yarn start` e `yarn dev:wds`, poi apri `http://localhost:8000`. Apri poi la console del browser, e controlla la console del server Express. Dovresti vedere la comunicazione tramite Websocket tra il client ed il server. 174 | 175 | Prossimo capitolo: [08 - Bootstrap, JSS](08-bootstrap-jss.md#readme) 176 | 177 | Torna al [capitolo precedente](06-react-router-ssr-helmet.md#readme) o all'[indice dei contenuti](https://github.com/fbertone/guida-javascript-moderno#indice-dei-contenuti). 178 | -------------------------------------------------------------------------------- /tutorial/09-travis-coveralls-heroku.md: -------------------------------------------------------------------------------- 1 | # 09 - Travis, Coveralls, ed Heroku 2 | 3 | Il codice di questo capitolo è disponibile nel branch `master` del repository [JS-Stack-Boilerplate](https://github.com/verekia/js-stack-boilerplate). 4 | 5 | In questo capitolo integreremo l'app con servizi di terze parti. Questi servizi offrono piani gratuiti e a pagamento. È un po' controverso utilizzare servizi di questo tipo in un tutorial che fa leva unicamente su tool opensource sviluppati dalla comunità, per questo motivo verranno mantenuti 2 branch separati del repository [JS-Stack-Boilerplate](https://github.com/verekia/js-stack-boilerplate), `master` e `master-no-services`. 6 | 7 | ## Travis 8 | 9 | > 💡 **[Travis CI](https://travis-ci.org/)** è una piattaforma popolare di continuous integration, gratuita per progetti open source. 10 | 11 | Se il tuo progetto è disponibile apertamente su Github, l'integrazione con Travis è molto semplice. Innanzitutto autenticati su Travis utilizzando il tuo account Github, e aggiungi il tuo repository. 12 | 13 | - Poi crea il file `.travis.yml` contenente: 14 | 15 | ```yaml 16 | language: node_js 17 | node_js: node 18 | script: yarn test && yarn prod:build 19 | ``` 20 | 21 | Travis si accorgerà automaticamente che utilizzi Yarn perchè è presente il file `yarn.lock`. Ogni volta che fai un push del codice sul tuo repository in Github, eseguirà `yarn test && yarn prod:build`. Se niente va storto, dovresti vedere una build verde. 22 | 23 | ## Coveralls 24 | 25 | > 💡 **[Coveralls](https://coveralls.io)** è un servizio che mantiene una cronologia e delle statistiche sulla copertura dei test. 26 | 27 | Se il tuo progetto è open-source su Github e compatibile con i servizi di Continuous Integration supportati da Coveralls, l'unica cosa che devi fare è inviare in pipe il file di copertura generato da Jest all'eseguibile di `coveralls`. 28 | 29 | - Esegui `yarn add --dev coveralls` 30 | 31 | - Modifica la sezione `script` di `.travis.yml` in questo modo: 32 | 33 | ```yaml 34 | script: yarn test && yarn prod:build && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js 35 | ``` 36 | 37 | Adesso, ogni volta che Travis farà una build, sottometterà automaticamente le informazioni di copertura dei test di Jest a Coveralls. 38 | 39 | ## Badges 40 | 41 | È tutto verde su Travis e Coveralls? Ottimo, mostralo al mondo con dei badge scintillanti! 42 | 43 | Puoi usare direttamente il codice fornito da Travis o Coveralls, oppure utilizzare [shields.io](http://shields.io/) per rendere omogenei o personalizzare i badge. Usiamo shields.io. 44 | 45 | - Crea o modifica il tuo `README.md` in questo modo: 46 | 47 | ```md 48 | [](https://travis-ci.org/GITHUB-USERNAME/GITHUB-REPO) 49 | [](https://coveralls.io/github/GITHUB-USERNAME/GITHUB-REPO?branch=master) 50 | ``` 51 | 52 | Ovviamente, sostituisci `GITHUB-USERNAME/GITHUB-REPO` con il tuo username di Github ed il nome del repository. 53 | 54 | ## Heroku 55 | 56 | > 💡 **[Heroku](https://www.heroku.com/)** è una [PaaS](https://en.wikipedia.org/wiki/Platform_as_a_service) su cui puoi effettuare il deploy. Si occuperà dei dettagli dell'infrastruttura, in modo che tu possa focalizzarti sullo sviluppo dell'app senza preoccuparti di quello che succede al di sotto. 57 | 58 | Questo tutorial non è sponsorizzato in alcun modo da Heroku, ma essendo Heroku una piattaforma che sa il fatto suo, ti spegherò come puoi farci il deploy dell'app. Questo è il tipo di affetto gratuito che ricevi quando costruisci un ottimo prodotto. 59 | 60 | **Nota**: Una sezione su AWS potrebbe essere aggiunta in questo capitolo successivamente, ma una cosa alla volta. 61 | 62 | ### Web setup 63 | 64 | - Se non l'hai ancora fatto, installa la [CLI di Heroku](https://devcenter.heroku.com/articles/getting-started-with-nodejs) ed effettua il log in. 65 | 66 | - Vai nella tua [Dashboard di Heroku](https://dashboard.heroku.com/) e crea 2 app, una chiamata `your-project` e un'altra chiamata ad esempio `your-project-staging`. 67 | 68 | Lasceremo che Heroku si occupi di effettuare il transpiling del nostro codice ES6/Flow tramite Babel, e generi dei bundle per i client tramite Webpack. Ma siccome quelle sono delle `devDependencies`, Yarn non le installerà in un ambiente di produzione come Heroku. Cambiamo questo comportamente utilizzando la variabile d'ambiente `NPM_CONFIG_PRODUCTION`. 69 | 70 | - In entrambe le app, sotto Settings > Config Variables, aggiunge `NPM_CONFIG_PRODUCTION` impostata a `false`. 71 | 72 | - Crea una Pipeline, e permetti ad Heroku l'accesso al tuo Github. 73 | 74 | - Aggiungi le 2 app alla pipeline, imposta quella di staging in modo che venga effettuato un auto-deploy in seguito ai cambiamenti in `master`, e abilita Review Apps. 75 | 76 | Ok, prepariamo il nostro progetto per il deploy su Heroku. 77 | 78 | ### Esecuzione in modalità produzione in locale 79 | 80 | - Crea il file `.env` contenente: 81 | 82 | ```.env 83 | NODE_ENV='production' 84 | PORT='8000' 85 | ``` 86 | 87 | È all'interno di questo file che dovresti inserire le variabili locali e segrete. Non inserirle nei commit in un repository pubblico se il tuo progetto è privato. 88 | 89 | - Aggiungi `/.env` al tuo `.gitignore` 90 | 91 | - Crea il file `Procfile` contenente: 92 | 93 | ```Procfile 94 | web: node lib/server 95 | ``` 96 | 97 | Qua è dove specifichiamo il punto d'ingresso del nostro server. 98 | 99 | Non useremo più PM2, useremo al suo posto `heroku local` per lanciare in modalità produzione in locale. 100 | 101 | - Esegui `yarn remove pm2` 102 | 103 | - Modilica lo script `prod:start` in `package.json`: 104 | 105 | ```json 106 | "prod:start": "heroku local", 107 | ``` 108 | 109 | - Rimuovi `prod:stop` da `package.json`. Non ci servirà più siccome `heroku local` è un processo che rimane appeso e possiamo killare con Ctrl+C, a differenza di `pm2 start`. 110 | 111 | 🏁 Esegui `yarn prod:build` e `yarn prod:start`. Dovrebbe far partire il server e visualizzare i log. 112 | 113 | ### Deploy in produzione 114 | 115 | - Aggiungi la seguente linea a `scripts` in `package.json`: 116 | 117 | ```json 118 | "heroku-postbuild": "yarn prod:build", 119 | ``` 120 | 121 | `heroku-postbuild` è un task che verrà eseguito ogni volta che effettuerai il deploy di un'app su Heroku. 122 | 123 | Probabilmente vorrai anche specificare una versione precisa di Node o Yarn da utilizzare su Heroku. 124 | 125 | - Aggiungi quanto segue a `package.json`: 126 | 127 | ```json 128 | "engines": { 129 | "node": "7.x", 130 | "yarn": "0.20.3" 131 | }, 132 | ``` 133 | 134 | - Crea `app.json` contenente: 135 | 136 | ```json 137 | { 138 | "env": { 139 | "NPM_CONFIG_PRODUCTION": "false" 140 | } 141 | } 142 | ``` 143 | 144 | Questo è da utilizzare in Review App. 145 | 146 | Adesso dovresti essere pronto per effettuare i deploy tramite la Pipeline di Heroku. 147 | 148 | 🏁 Crea un nuovo branch di git, fai delle modifiche e apri Github Pull Request per istanziare una Review App. Verifica le tue modifiche in Review App URL e se ti sembra tutto corretto, fai il merge della tua Pull Request sul `master` in Github. Dopo alcuni minuti, la tua app di staging dovrebbe essere stata inviata in deploy automaticamente. Verifica le modifiche nello staging app URL, e se ti sembra che vada ancora tutto bene, promuovi lo staging in produzione. 149 | 150 | Hai finito! Congratulazioni se hai terminato questo tutorial partendo da zero. 151 | 152 | Ti meriti questa medaglia emoji: 🏅 153 | 154 | Torna al [capitolo precedente](08-bootstrap-jss.md#readme) o all'[indice dei contenuti](https://github.com/fbertone/guida-javascript-moderno#indice-dei-contenuti). 155 | -------------------------------------------------------------------------------- /tutorial/01-node-yarn-package-json.md: -------------------------------------------------------------------------------- 1 | # 01 - Node, Yarn, e `package.json` 2 | 3 | Il codice per questo capitolo è disponibile [qua](https://github.com/verekia/js-stack-walkthrough/tree/master/01-node-yarn-package-json). 4 | 5 | In questa sezione configureremo Node, Yarn, un file `package.json` di base, e proveremo un package. 6 | 7 | ## Node 8 | 9 | > 💡 **[Node.js](https://nodejs.org/)** è un ambiente di runtime per JavaScript. Viene utilizzato principalmente per lo sviluppo di Back-End, ma anche come ambiente di scripting in generale. Nel contesto dello sviluppo di Front-End, può essere utilizzato per l'esecuzione di tutta una serie di task, come il linting, esecuzione di test, e manipolazione dei file. 10 | 11 | Utilizzeremo Node praticamente per tutto il tutorial, quindi ne avrai bisogno. Vai alla pagina di [download](https://nodejs.org/en/download/current/) per l'installazione in **macOS** o **Windows**, o alla pagina di [installazione tramite package manager](https://nodejs.org/en/download/package-manager/) per le distribuzioni Linux. 12 | 13 | Ad esempio, in **Ubuntu / Debian**, eseguiresti questi comandi per installare Node: 14 | 15 | ```sh 16 | curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash - 17 | sudo apt-get install -y nodejs 18 | ``` 19 | 20 | Ti serve una versione di Node > 6.5.0. 21 | 22 | ## Node Version Management Tools 23 | 24 | Se ti serve la flessibilità di poter utilizzare versioni multiple di Node, installa [NVM](https://github.com/creationix/nvm)) oppure [tj/n](https://github.com/tj/n). 25 | 26 | ## NPM 27 | 28 | NPM è il package manager di default per Node. Viene automaticamente installato insieme a Node. I package manager sono utilizzati per installare e gestire i pacchetti (moduli di codice scritti da te o da altri). Utilizzeremo molti pacchetti in questo tutorial, ma ci serviremo di Yarn, un package manager differente. 29 | 30 | ## Yarn 31 | 32 | > 💡 **[Yarn](https://yarnpkg.com/)** è un package manager per Node.js che è molto più veloce di NPM, ha il supporto offline, e gestisce le dipendenza in modo più [predicibile](https://yarnpkg.com/en/docs/yarn-lock). 33 | 34 | Da quando è stato [rilasciato](https://code.facebook.com/posts/1840075619545360) ad ottobre 2016, è stato adottato molto rapidamente e potrebbe diventare presto il package manager di riferimento per la comunità JavaScript. Se preferisci rimanere con NPM puoi semplicemente sostituire tutti i comandi `yarn add` e `yarn add --dev` con `npm install --save` e `npm install --save-dev`. 35 | 36 | Installa Yarn seguendo le [istruzioni](https://yarnpkg.com/en/docs/install) per il tuo OS. Se utilizzi macOS o Unix, ti consiglio di usare lo script **Installation Script** che trovi nella scheda *Alternatives* per [evitare](https://github.com/yarnpkg/yarn/issues/1505) di essere dipendente da altri package manager: 37 | 38 | ```sh 39 | curl -o- -L https://yarnpkg.com/install.sh | bash 40 | ``` 41 | 42 | ## `package.json` 43 | 44 | > 💡 **[package.json](https://yarnpkg.com/en/docs/package-json)** è il file che serve a descrivere e configurare i progetti JavaScript. Contiene delle informazioni generali (il nome del progetto, la versione, i contributor, la licenza, etc), opzioni di configurazione dei tool che usi, e anche una sezione per l'esecuzione di *task*. 45 | 46 | - Crea una cartella di progetto ed entraci da console (`cd`). 47 | - Esegui `yarn init` e rispondi alle domande (`yarn init -y` per saltare tutte le domande), per generare automaticamente il file `package.json`. 48 | 49 | Ecco il contenuto del file `package.json` che useremo per questo tutorial: 50 | 51 | ```json 52 | { 53 | "name": "your-project", 54 | "version": "1.0.0", 55 | "license": "MIT" 56 | } 57 | ``` 58 | 59 | ## Hello World 60 | 61 | - Crea un file `index.js` contenente `console.log('Hello world')` 62 | 63 | 🏁 Esegui `node .` in questa cartella (`index.js` è il file che Node cerca di default per l'esecuzione). Dovrebbe scrivere "Hello world". 64 | 65 | **Nota**: Vedi quella bandierina 🏁 ? La inserirò ogni volta che raggiungi un **checkpoint**. A volte faremo molte modifiche di seguito, e il codice potrebbe non funzionare fino al raggiungimento del checkpoint successivo. 66 | 67 | ## `start` script 68 | 69 | Scrivere `node .` per eseguire il nostro programma è un po' troppo di basso livello. Utilizzeremo uno script NPM/Yarn per far partire l'esecuzione del codice. Questo ci permetterà di avere un buon livello di astrazione e poter sempre eseguire `yarn start`, anche quando il nostro programma diventerà più complesso. 70 | 71 | - All'interno di `package.json`, aggiungi un oggetto `scripts` in questo modo: 72 | 73 | ```json 74 | { 75 | "name": "your-project", 76 | "version": "1.0.0", 77 | "license": "MIT", 78 | "scripts": { 79 | "start": "node ." 80 | } 81 | } 82 | ``` 83 | 84 | `start` è il nome che diamo al *task* che farà partire il nostro programma. Creeremo molti task differenti in questo oggetto `scripts` nel corso di questo tutorial. `start` tipicamente è il nome che viene dato al task di default. Altri nomi di task standard sono `stop` e `test`. 85 | 86 | `package.json` deve essere un file JSON valido, il che significa che non può avere delle virgole finali. Devi quindi fare attenzione quando modifichi a mano il file `package.json`. 87 | 88 | 🏁 Lancia `yarn start`. Dovrebbe venire scritto `Hello world`. 89 | 90 | ## Git e `.gitignore` 91 | 92 | - Inizializza un repository Git con `git init` 93 | 94 | - Crea un file `.gitignore` ed inserisci al suo interno quanto segue: 95 | 96 | ```gitignore 97 | .DS_Store 98 | /*.log 99 | ``` 100 | 101 | I file `.DS_Store` sono dei file di macOS che vengono generati automaticamente e non dovresti mai avere inclusi nel tuo repository. 102 | 103 | `npm-debug.log` e `yarn-error.log` sono dei file che vengono creati quando il package manager riscontra un errore, non li vogliamo includere nel repository. 104 | 105 | ## Installare ed utilizzare un package 106 | 107 | In questa sezione vedremo come installare ed utilizzare un package. Un "package" è semplicemente del codice scritto da altri, che puoi riutilizzare nel tuo codice. Può essere qualunque cosa. Adesso ad esempio utilizzeremo un package che può aiutarti ad utilizzare i codici dei colori. 108 | 109 | - Installa il package chiamato `color` attraverso il comando `yarn add color` 110 | 111 | Apri `package.json` per vedere come Yarn ha automaticamente aggiunto `color` nelle `dependencies`. 112 | 113 | Una cartella `node_modules` è stata creata per contenere il package. 114 | 115 | - Aggiungi `node_modules/` al file `.gitignore` 116 | 117 | Noterai anche che un file `yarn.lock` è stato generato da Yarn. Dovresti includere questo file nel repository, perchè farà in modo da assicurare che ogni persona del tuo team utilizzi le stesse versioni dei package. Se stai utilizzando NPM invece di Yarn, l'equivalente di questo file si chiama *shrinkwrap*. 118 | 119 | - Scrivi quanto segue nel file `index.js`: 120 | 121 | ```js 122 | const color = require('color') 123 | 124 | const redHexa = color({ r: 255, g: 0, b: 0 }).hex() 125 | 126 | console.log(redHexa) 127 | ``` 128 | 129 | 🏁 Esegui `yarn start`. Dovrebbe scrivere `#FF0000`. 130 | 131 | Congratulazioni, hai installato ed utilizzato un package! 132 | 133 | `color` è stato utilizzato in questa sezione unicamente per farti vedere come puoi utilizzare un semplice package. Non lo utilizzeremo più in seguito, puoi quindi disintallarlo: 134 | 135 | - Esegui `yarn remove color` 136 | 137 | ## Due tipi di dipendenze 138 | 139 | Ci sono due tipi di dipendenze di package, `"dependencies"` e `"devDependencies"`: 140 | 141 | **Dependencies** sono librerie che sono necessarie per il funzionamento dell'applicazione (React, Redux, Lodash, jQuery, etc). Le installi con il comando `yarn add [package]`. 142 | 143 | **Dev Dependencies** sono librerie utilizzate durante lo sviluppo o per fare il build dell'applicazione (Webpack, SASS, linter, framework di testing, etc). Queste vanno installate utilizzando il comando `yarn add --dev [package]`. 144 | 145 | Prossimo capitolo: [02 - Babel, ES6, ESLint, Flow, Jest, Husky](02-babel-es6-eslint-flow-jest-husky.md#readme) 146 | 147 | Torna all'[indice dei contenuti](https://github.com/fbertone/guida-javascript-moderno#indice-dei-contenuti). 148 | -------------------------------------------------------------------------------- /tutorial/03-express-nodemon-pm2.md: -------------------------------------------------------------------------------- 1 | # 03 - Express, Nodemon, e PM2 2 | 3 | Il codice per questo capitolo è disponibile [qua](https://github.com/verekia/js-stack-walkthrough/tree/master/03-express-nodemon-pm2). 4 | 5 | In questa sezione creeremo il server che si occuperà del render della nostra web app. Configureremo inoltre per il server una modalità di sviluppo ed una di produzione. 6 | 7 | ## Express 8 | 9 | > 💡 **[Express](http://expressjs.com/)** è di gran lunga il framework web più famoso per Node. Dispone di un'API molto semplice e minimale, e le sue funzionalità possono essere estese tramite *middleware*. 10 | 11 | Configuriamo un server Express per servire una pagina HTML page con del CSS. 12 | 13 | - Cancella tutto in `src` 14 | 15 | Crea i seguenti file e cartelle: 16 | 17 | - Crea un file `public/css/style.css` con questo contenuto: 18 | 19 | ```css 20 | body { 21 | width: 960px; 22 | margin: auto; 23 | font-family: sans-serif; 24 | } 25 | 26 | h1 { 27 | color: limegreen; 28 | } 29 | ``` 30 | 31 | - Crea una cartella vuota `src/client/`. 32 | 33 | - Crea una cartella vuota `src/shared/`. 34 | 35 | Questa cartella è dove inseriremo il codice Javascript *isomorfico / universale* – file che verranno utilizzati sia dal client che dal server. Un buon esempio di codice condiviso sono le *routes*, come vedrai più avanti quando faremo delle chiamate asincrone. Per il momento impostiamo solo alcune constanti di configurazione come esempio. 36 | 37 | - Crea un file `src/shared/config.js` contenente: 38 | 39 | ```js 40 | // @flow 41 | 42 | export const WEB_PORT = process.env.PORT || 8000 43 | export const STATIC_PATH = '/static' 44 | export const APP_NAME = 'Hello App' 45 | ``` 46 | 47 | Se il processo di Node utilizzato per eseguire la tua applicazione ha una variabile d'ambiente `process.env.PORT` impostata (ad esempio quando fai il deploy su Heroku), utilizzarà il valore di questa variabile come porta. Se non è configurata, utilizziamo come default la `8000`. 48 | 49 | - Crea il file `src/shared/util.js` contenente: 50 | 51 | ```js 52 | // @flow 53 | 54 | // eslint-disable-next-line import/prefer-default-export 55 | export const isProd = process.env.NODE_ENV === 'production' 56 | ``` 57 | 58 | Questo è un modo semplice per verificare se siamo in produzione o no. Il commento `// eslint-disable-next-line import/prefer-default-export` ci serve perchè abbiamo un solo export in questo caso. Potrai rimuoverlo quando aggiungerai nuove export in questo file. 59 | 60 | - Esegui `yarn add express compression` 61 | 62 | `compression` è un middleware di Express per attivare la compressione Gzip sul server. 63 | 64 | - Crea il file `src/server/index.js` contenente: 65 | 66 | ```js 67 | // @flow 68 | 69 | import compression from 'compression' 70 | import express from 'express' 71 | 72 | import { APP_NAME, STATIC_PATH, WEB_PORT } from '../shared/config' 73 | import { isProd } from '../shared/util' 74 | import renderApp from './render-app' 75 | 76 | const app = express() 77 | 78 | app.use(compression()) 79 | app.use(STATIC_PATH, express.static('dist')) 80 | app.use(STATIC_PATH, express.static('public')) 81 | 82 | app.get('/', (req, res) => { 83 | res.send(renderApp(APP_NAME)) 84 | }) 85 | 86 | app.listen(WEB_PORT, () => { 87 | // eslint-disable-next-line no-console 88 | console.log(`Server running on port ${WEB_PORT} ${isProd ? '(production)' : '(development)'}.`) 89 | }) 90 | ``` 91 | 92 | Niente di particolare qua, è quasi il tutorial "Hello World" di Express con alcune import aggiuntive. Stiamo utilizzando 2 directory differenti per i file statici. `dist` per i file generati, `public` per quelli fissi. 93 | 94 | - Crea il file `src/server/render-app.js` contenente: 95 | 96 | ```js 97 | // @flow 98 | 99 | import { STATIC_PATH } from '../shared/config' 100 | 101 | const renderApp = (title: string) => 102 | ` 103 | 104 |
105 |156 | 157 |
158 |Open your browser console.
165 |Hover me.
441 |Resize the window.
442 | 443 |