├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── Definitions.md ├── README.md ├── READMEeng.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 │ ├── READMEeng.md │ ├── index.js │ └── package.json ├── 10-immutable-redux-improvements │ ├── .gitignore │ ├── README.md │ ├── READMEeng.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 │ ├── READMEeng.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 │ ├── READMEeng.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 │ ├── READMEeng.md │ ├── index.js │ ├── package.json │ └── yarn.lock ├── 3-es6-babel-gulp │ ├── .gitignore │ ├── README.md │ ├── READMEeng.md │ ├── gulpfile.js │ ├── package.json │ ├── src │ │ └── index.js │ └── yarn.lock ├── 4-es6-syntax-class │ ├── .gitignore │ ├── README.md │ ├── READMEeng.md │ ├── gulpfile.js │ ├── package.json │ ├── src │ │ ├── dog.js │ │ └── index.js │ └── yarn.lock ├── 5-es6-modules-syntax │ ├── .gitignore │ ├── README.md │ ├── READMEeng.md │ ├── gulpfile.babel.js │ ├── package.json │ ├── src │ │ ├── dog.js │ │ └── index.js │ └── yarn.lock ├── 6-eslint │ ├── .gitignore │ ├── README.md │ ├── READMEeng.md │ ├── gulpfile.babel.js │ ├── package.json │ ├── src │ │ ├── dog.js │ │ └── index.js │ └── yarn.lock ├── 7-client-webpack │ ├── .gitignore │ ├── README.md │ ├── READMEeng.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 │ ├── READMEeng.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 │ ├── READMEeng.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 /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Type of issue: (feature suggestion, bug, translation?) 2 | 3 | ### Chapter: 4 | 5 | ### If it's a bug: 6 | 7 | Please try using the code provided in this repository 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, a typo, or something like this. Feel free to open an issue if there is a problem with instructions though. 8 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /Definitions.md: -------------------------------------------------------------------------------- 1 | Термины и определения 2 | 3 | package - пакет 4 | https://ru.wikipedia.org/wiki/Package_(Java) 5 | 6 | class - класс 7 | 8 | Type Checking - Типизация 9 | 10 | OOP - объектно-ориентированное программирование 11 | 12 | JavaScript 13 | 14 | template strings - Шаблонные строки 15 | https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/template_strings 16 | 17 | arrow functions - стрелочные функции 18 | https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/Arrow_functions 19 | 20 | CommonJS 21 | 22 | Gulp - сборщик проектов 23 | https://habrahabr.ru/post/208890/ 24 | 25 | Task Runner - менеджер задач. 26 | (диспетчер запуска задач) 27 | 28 | Node - сервер Node 29 | 30 | plain JavaScript object - простой JavaScript объект 31 | 32 | Babel 33 | 34 | синтаксический сахар - syntactic sugar 35 | 36 | lint - статический анализ, контроль качества кода 37 | https://ru.wikipedia.org/wiki/Lint 38 | 39 | linter - статический анализатор кода. 40 | 41 | Gulpfile 42 | 43 | linting errors 44 | 45 | bundle - сборка 46 | 47 | polyfill 48 | https://remysharp.com/2010/10/08/what-is-a-polyfill 49 | 50 | TRANSPILING - транспилияция (трансляция) 51 | https://www.stevefenton.co.uk/2012/11/compiling-vs-transpiling/ 52 | 53 | tutorial - руководство 54 | 55 | entry point file - файл, указывающий на начальную точку сборки 56 | 57 | back-end - серверная часть 58 | 59 | trailing commas - завершающая запятая (/пробел) 60 | http://www.multitran.ru/c/m.exe?t=6766895_1_2&s1=trailing%20space 61 | 62 | repo/repository - репозиторий 63 | 64 | commit - фиксировать гл. 65 | commit - коммит сущ. 66 | 67 | reducer functions - reducer-функции 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Стек технологий JavaScript с нуля 2 | ## JavaScript Stack from Scratch 3 | 4 | [](https://travis-ci.org/verekia/js-stack-from-scratch) [](https://gitter.im/js-stack-from-scratch/Lobby) 5 | 6 | [](https://yarnpkg.com/) 7 | [](https://facebook.github.io/react/) 8 | [](http://gulpjs.com/) 9 | [](http://redux.js.org/) 10 | [](http://eslint.org/) 11 | [](https://webpack.github.io/) 12 | [](https://mochajs.org/) 13 | [](http://chaijs.com/) 14 | [](https://flowtype.org/) 15 | 16 | >Это русскоязычная версия руководства Джонатана Верекии ([@verekia](https://twitter.com/verekia)). Оригинальное руководство расположено [здесь](https://github.com/verekia/js-stack-from-scratch). Данное пособие постоянно развивается и дополняется автором, предоставляя читателям максимально свежую и качественную информацию. Текст оригинального пособия и прилагаемый код будут меняться с течением времени. Мы так же будем стараться поддерживать русскоязычную версию в актуальном состоянии. Данный перевод соответствует английской версии по состоянию на [commit](https://github.com/verekia/js-stack-from-scratch/commit/343922149f136bbab2512b14a2fe5efe095d62b7). 17 | Мы будем рады вашим [замечаниям и вопросам](https://github.com/UsulPro/js-stack-from-scratch/issues) 18 |
19 | 20 | Добро пожаловать в мое современное руководство по стеку технологий JavaScript: **Стек технологий JavaScript с нуля** 21 | 22 | Это минималистичное и практико-ориентированное пособие по применению JavaScript технологий. Вам потребуются общие знания по программированию и основы JavaScript. Это пособие **нацелено на интеграцию необходимых инструментов** и предоставляет **максимально простые примеры** для каждого инструмента. Вы можете рассматривать данный документ, как *возможность создать свой собственный шаблонный проект с нуля*. 23 | 24 | Конечно, вам не нужны все эти технологии, если вы делаете простую веб страницу с парой JS функций (комбинации Browserify / Webpack + Babel + jQuery достаточно, чтобы написать ES6 код в нескольких файлах и скомпилировать все через командную строку), но если вы собираетесь создать масштабируемое веб приложение, и вам нужно все правильно настроить, то это руководство отлично вам подходит. 25 | 26 | Поскольку целью этого руководства является сборка различных инструментов, я не буду вдаваться в детали по каждому из них. Если вы хотите получить по ним более глубокие знания, изучайте их документацию или другие руководства. 27 | 28 | В большой части технологий, описываемых здесь, используется React. Если вы только начинаете использовать React и просто хотите изучить его, то [create-react-app](https://github.com/facebookincubator/create-react-app) поможет вам и кратко ознакомит с инфраструктурой React на основе предустановленной конфигурации. Я бы, например, порекомендовал такой подход для тех, кому нужно влиться в команду, использующую React, и на чем-то потренироваться, чтобы подтянуть свои знания. В этом руководстве мы не будем пользоваться предустановленными конфигурациями, поскольку я хочу, чтобы вы полностью понимали все, что происходит "под капотом". 29 | 30 | Примеры кода имеются в каждой части, и вы можете запускать их через `yarn && yarn start` или `npm install && npm start`. Я рекомендую писать все с нуля самостоятельно, следуя **пошаговым инструкциям** каждого раздела. 31 | 32 | **Каждая часть содержит код, написанный в предыдущих частях**, так что если вы просто хотите получить окончательный вариант проекта, содержащий все необходимое, просто скопируйте последний раздел и смело пользуйтесь. 33 | 34 | Примечание: Порядок частей не всегда обязателен. К примеру, тестирование / типизация могут быть выполнены до введения в React. Довольно сложно перемещать или редактировать опубликованные разделы, поскольку приходится вносить изменения во все следующие за ними части. Возможно, когда все определится, я приведу всю документацию к более удобному виду. 35 | 36 | Код, приведенный в примерах, работает под Linux, macOS и Windows. 37 | 38 | ## Содержание 39 | 40 | [1 - Node, NPM, Yarn и package.json](/tutorial/1-node-npm-yarn-package-json) 41 | 42 | [2 - Установка и использование пакетов](/tutorial/2-packages) 43 | 44 | [3 - Настройка ES6 с Babel и Gulp](/tutorial/3-es6-babel-gulp) 45 | 46 | [4 - Использование ES6 классов](/tutorial/4-es6-syntax-class) 47 | 48 | [5 - Синтаксис модулей ES6](/tutorial/5-es6-modules-syntax) 49 | 50 | [6 - ESLint](/tutorial/6-eslint) 51 | 52 | [7 - Клиентское приложение на основе Webpack](/tutorial/7-client-webpack) 53 | 54 | [8 - React](/tutorial/8-react) 55 | 56 | [9 - Redux](/tutorial/9-redux) 57 | 58 | [10 - Immutable JS и улучшения Redux](/tutorial/10-immutable-redux-improvements) 59 | 60 | [11 - Тестирование с Mocha, Chai и Sinon](/tutorial/11-testing-mocha-chai-sinon) 61 | 62 | [12 - Типизация с Flow](/tutorial/12-flow) 63 | 64 | ## Далее планируется: 65 | 66 | Production / development окружение, Express, React Router, Серверный Рендеринг, Стилизация, Enzyme, Приемы Git. 67 | 68 | ## Переводы на другие языки 69 | 70 | - [Китайский](https://github.com/pd4d10/js-stack-from-scratch) by [@pd4d10](http://github.com/pd4d10) 71 | - [Итальянский](https://github.com/fbertone/js-stack-from-scratch) by [Fabrizio Bertone](https://github.com/fbertone) 72 | - [Японский](https://github.com/takahashim/js-stack-from-scratch) by [@takahashim](https://github.com/takahashim) 73 | - [Тайский](https://github.com/MicroBenz/js-stack-from-scratch) by [MicroBenz](https://github.com/MicroBenz) 74 | 75 | Если вы хотите добавить перевод на другой язык, пожалуйста читайте [рекомендации по переводу](/how-to-translate.md) чтобы начать! 76 | 77 | ## Сведения 78 | 79 | Создано [@verekia](https://twitter.com/verekia) – [verekia.com](http://verekia.com/). 80 | 81 | Переведено [@usulpro](https://github.com/UsulPro) - [react-theming](https://github.com/sm-react/react-theming) 82 | 83 | Лицензия: MIT 84 | -------------------------------------------------------------------------------- /READMEeng.md: -------------------------------------------------------------------------------- 1 | # JavaScript Stack from Scratch 2 | 3 | [](https://travis-ci.org/verekia/js-stack-from-scratch) [](https://gitter.im/js-stack-from-scratch/Lobby) 4 | 5 | [](https://yarnpkg.com/) 6 | [](https://facebook.github.io/react/) 7 | [](http://gulpjs.com/) 8 | [](http://redux.js.org/) 9 | [](http://eslint.org/) 10 | [](https://webpack.github.io/) 11 | [](https://mochajs.org/) 12 | [](http://chaijs.com/) 13 | [](https://flowtype.org/) 14 | 15 | Welcome to my modern JavaScript stack tutorial: **JavaScript Stack from Scratch**. 16 | 17 | This is a minimalistic and straight-to-the-point guide to assembling a JavaScript stack. It requires some general programming knowledge, and JavaScript basics. **It focuses on wiring tools together** and giving you the **simplest possible example** for each tool. You can see this tutorial as *a way to write your own boilerplate from scratch*. 18 | 19 | You don't need to use this entire stack if you build a simple web page with a few JS interactions of course (a combination of Browserify/Webpack + Babel + jQuery is enough to be able to write ES6 code in different files with CLI compilation), but if you want to build a web app that scales, and need help setting things up, this tutorial will work great for you. 20 | 21 | Since the goal of this tutorial is to assemble various tools, I do not go into details about how these tools work individually. Refer to their documentation or find other tutorials if you want to acquire deeper knowledge in them. 22 | 23 | A big chunk of the stack described in this tutorial uses React. If you are beginning and just want to learn React, [create-react-app](https://github.com/facebookincubator/create-react-app) will get you up and running with a React environment very quickly with a premade configuration. I would for instance recommend this approach to someone who arrives in a team that's using React and needs to catch up with a learning playground. In this tutorial you won't use a premade configuration, because I want you to understand everything that's happening under the hood. 24 | 25 | Code examples are available for each chapter, and you can run them all with `yarn && yarn start` or `npm install && npm start`. I recommend writing everything from scratch yourself by following the **step-by-step instructions** of each chapter. 26 | 27 | **Every chapter contains the code of previous chapters**, so if you are simply looking for a boilerplate project containing everything, just clone the last chapter and you're good to go. 28 | 29 | Note: The order of chapters is not necessarily the most educational. For instance, testing / type checking could have been done before introducing React. It is quite difficult to move chapters around or edit past ones, since I need to apply those changes to every following chapter. If things settle down, I might reorganize the whole thing in a better way. 30 | 31 | The code of this tutorial works on Linux, macOS, and Windows. 32 | 33 | ## Table of contents 34 | 35 | [1 - Node, NPM, Yarn, and package.json](/tutorial/1-node-npm-yarn-package-json) 36 | 37 | [2 - Installing and using a package](/tutorial/2-packages) 38 | 39 | [3 - Setting up ES6 with Babel and Gulp](/tutorial/3-es6-babel-gulp) 40 | 41 | [4 - Using the ES6 syntax with a class](/tutorial/4-es6-syntax-class) 42 | 43 | [5 - The ES6 modules syntax](/tutorial/5-es6-modules-syntax) 44 | 45 | [6 - ESLint](/tutorial/6-eslint) 46 | 47 | [7 - Client app with Webpack](/tutorial/7-client-webpack) 48 | 49 | [8 - React](/tutorial/8-react) 50 | 51 | [9 - Redux](/tutorial/9-redux) 52 | 53 | [10 - Immutable JS and Redux Improvements](/tutorial/10-immutable-redux-improvements) 54 | 55 | [11 - Testing with Mocha, Chai, and Sinon](/tutorial/11-testing-mocha-chai-sinon) 56 | 57 | [12 - Type Checking with Flow](/tutorial/12-flow) 58 | 59 | ## Coming up next 60 | 61 | Production / development environments, Express, React Router, Server-Side Rendering, Styling, Enzyme, Git Hooks. 62 | 63 | ## Translations 64 | 65 | - [中文](https://github.com/pd4d10/js-stack-from-scratch) by [@pd4d10](http://github.com/pd4d10) 66 | - [Italiano](https://github.com/fbertone/js-stack-from-scratch) by [Fabrizio Bertone](https://github.com/fbertone) 67 | - [日本語](https://github.com/takahashim/js-stack-from-scratch) by [@takahashim](https://github.com/takahashim) 68 | 69 | If you want to add your translation, please read the [translation recommendations](/how-to-translate.md) to get started! 70 | 71 | ## Credits 72 | 73 | Created by [@verekia](https://twitter.com/verekia) – [verekia.com](http://verekia.com/). 74 | 75 | License: MIT 76 | -------------------------------------------------------------------------------- /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/usulpro/js-stack-from-scratch-v1-rus/6463f01fa1b3553d91aac5822799db2751dd09f7/img/chai.png -------------------------------------------------------------------------------- /img/eslint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usulpro/js-stack-from-scratch-v1-rus/6463f01fa1b3553d91aac5822799db2751dd09f7/img/eslint.png -------------------------------------------------------------------------------- /img/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usulpro/js-stack-from-scratch-v1-rus/6463f01fa1b3553d91aac5822799db2751dd09f7/img/flow.png -------------------------------------------------------------------------------- /img/gulp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usulpro/js-stack-from-scratch-v1-rus/6463f01fa1b3553d91aac5822799db2751dd09f7/img/gulp.png -------------------------------------------------------------------------------- /img/js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usulpro/js-stack-from-scratch-v1-rus/6463f01fa1b3553d91aac5822799db2751dd09f7/img/js.png -------------------------------------------------------------------------------- /img/mocha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usulpro/js-stack-from-scratch-v1-rus/6463f01fa1b3553d91aac5822799db2751dd09f7/img/mocha.png -------------------------------------------------------------------------------- /img/npm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usulpro/js-stack-from-scratch-v1-rus/6463f01fa1b3553d91aac5822799db2751dd09f7/img/npm.png -------------------------------------------------------------------------------- /img/react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usulpro/js-stack-from-scratch-v1-rus/6463f01fa1b3553d91aac5822799db2751dd09f7/img/react.png -------------------------------------------------------------------------------- /img/redux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usulpro/js-stack-from-scratch-v1-rus/6463f01fa1b3553d91aac5822799db2751dd09f7/img/redux.png -------------------------------------------------------------------------------- /img/webpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usulpro/js-stack-from-scratch-v1-rus/6463f01fa1b3553d91aac5822799db2751dd09f7/img/webpack.png -------------------------------------------------------------------------------- /img/yarn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usulpro/js-stack-from-scratch-v1-rus/6463f01fa1b3553d91aac5822799db2751dd09f7/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 и package.json 2 | 3 | В этой части мы настроим Node, NPM, Yarn и простой `package.json`. 4 | 5 | Прежде всего нам нужно установить Node, который необходим не только для серверной части (Back-End), но и для всех тех инструментов, которые входят в состав современных технологий для создания клиентской части (Front-End). 6 | 7 | Зайдите на [страницу загрузки](https://nodejs.org/en/download/current/) дистрибутива для macOS или Windows, или установите [через менеджер пакетов](https://nodejs.org/en/download/package-manager/) для Linux. 8 | 9 | Например, на **Ubuntu / Debian**, чтобы установить Node нужно выполнить следующие команды: 10 | 11 | ```bash 12 | curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - 13 | sudo apt-get install -y nodejs 14 | ``` 15 | Вам подойдет любая версия Node > 6.5.0. 16 | 17 | `npm` - стандартный менеджер пакетов для Node, устанавливается автоматически, так что вам не нужно делать это вручную. 18 | 19 | **Примечание**: Если Node уже установлен, установите `nvm` ([Node Version Manager](https://github.com/creationix/nvm) - менеджер версий Node), выполните `nvm` install и пользуйтесь последней версией Node. 20 | 21 | [Yarn](https://yarnpkg.com/) - еще один менеджер пакетов. Он намного быстрее чем NPM, поддерживает работу офлайн и [лучше предугадывает](https://yarnpkg.com/en/docs/yarn-lock) подгрузку нужных зависимостей. С момента его [выхода](https://code.facebook.com/posts/1840075619545360) в октябре 2016, он был очень быстро принят сообществом и постепенно становится лучшим решением для JavaScript. В данном руководстве мы будем использовать Yarn. Если вы предпочитаете оставаться с NPM, просто замените все команды `yarn add` и `yarn add --dev` на `npm install --save` и `npm install --save-dev` в этом пособии. 22 | 23 | - Установите Yarn, следуя [инструкциям](https://yarnpkg.com/en/docs/install). Проще всего это сделать через `npm install -g yarn` или `sudo npm install -g yarn` (верно, мы используем NPM, чтобы установить Yarn, все равно что использовать Internet Explorer или Safari, чтобы установить Chrome!). 24 | 25 | - Создайте новую директорию для работы и зайдите (`cd`) в нее. 26 | - Запустите `yarn init` и ответьте на вопросы, чтобы создать файл `package.json` автоматически (`yarn init -y`, чтобы пропустить вопросы). 27 | - Создайте файл `index.js`, содержащий `console.log('Hello world')`. 28 | - Запустите `node .` в этой директории (`index.js` - файл по умолчанию, который Node будет запускать в текущей папке). Должно выйти "Hello world". 29 | 30 | Команда `node .` - слегка низкоуровневая для запуска программ. Вместо нее мы будем использовать NPM/Yarn скрипты, чтобы запускать выполнение нужного кода. Это даст нам хороший уровень абстракции, позволяющий всегда использовать `yarn start`, даже когда наша программа станет более сложной. 31 | 32 | - В файле `package.json`, в корневом объекте создайте объект `scripts`, чтобы было так: 33 | 34 | ```json 35 | "scripts": { 36 | "start": "node ." 37 | } 38 | ``` 39 | 40 | `package.json` должен быть действительным JSON файлом, это значит, что он не может содержать завершающие запятые (trailing commas). Так что будьте внимательны, редактируя его вручную. 41 | 42 | - Запустите `yarn start`. Должно выйти `Hello world`. 43 | 44 | - Создайте файл `.gitignore` и добавьте туда следующее: 45 | 46 | ```gitignore 47 | npm-debug.log 48 | yarn-error.log 49 | ``` 50 | 51 | **Примечание**: Если вы посмотрите на файлы `package.json`, которые я прилагаю к этому руководству, вы увидите там скрипт `tutorial-test`. Он есть в каждой части. Этот скрипт позволяет тестировать код на правильную работу при запуске `yarn && yarn start`. Вы можете удалить его из вашего проекта. 52 | 53 | Следующий раздел: [2 - Установка и использование пакетов](/tutorial/2-packages) 54 | 55 | Назад в [Содержание](/../../#Содержание). 56 | -------------------------------------------------------------------------------- /tutorial/1-node-npm-yarn-package-json/READMEeng.md: -------------------------------------------------------------------------------- 1 | # 1 - Node, NPM, Yarn, and package.json 2 | 3 | In this section we will set up Node, NPM, Yarn, and a basic `package.json` file. 4 | 5 | First, we need to install Node, which is not only used for back-end JavaScript, but all the tools we need to build a modern Front-End stack. 6 | 7 | Head to the [download page](https://nodejs.org/en/download/current/) for macOS or Windows binaries, or the [package manager installations page](https://nodejs.org/en/download/package-manager/) for Linux distributions. 8 | 9 | For instance, on **Ubuntu / Debian**, you would run the following commands to install Node: 10 | 11 | ```bash 12 | curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - 13 | sudo apt-get install -y nodejs 14 | ``` 15 | 16 | You want any version of Node > 6.5.0. 17 | 18 | `npm`, the default package manager for Node, comes automatically with Node, so you don't have to install it yourself. 19 | 20 | **Note**: If Node is already installed, install `nvm` ([Node Version Manager](https://github.com/creationix/nvm)), make `nvm` install and use the latest version of Node for you. 21 | 22 | [Yarn](https://yarnpkg.com/) is another package manager which is much faster than NPM, has offline support, and fetches dependencies [more predictably](https://yarnpkg.com/en/docs/yarn-lock). Since it [came out](https://code.facebook.com/posts/1840075619545360) in October 2016, it received a very quick adoption and is becoming the new package manager of choice of the JavaScript community. We are going to use Yarn in this tutorial. If you want to stick to NPM you can simply replace all `yarn add` and `yarn add --dev` commands of this tutorial by `npm install --save` and `npm install --dev`. 23 | 24 | - Install Yarn by following the [instructions](https://yarnpkg.com/en/docs/install). You can likely install it with `npm install -g yarn` or `sudo npm install -g yarn` (yeah, we're using NPM to install Yarn, much like you would use Internet Explorer or Safari to install Chrome!). 25 | 26 | - Create a new folder to work in, and `cd` in it. 27 | - Run `yarn init` and answer the questions (`yarn init -y` to skip all questions), to generate a `package.json` file automatically. 28 | - Create an `index.js` file containing `console.log('Hello world')`. 29 | - Run `node .` in this folder (`index.js` is the default file Node looks for in the current folder). It should print "Hello world". 30 | 31 | Running `node .` to execute our program is a bit too low-level. We are going to use an NPM/Yarn script to trigger the execution of that code instead. That will give us a nice abstraction to be able to always use `yarn start`, even when our program gets more complicated. 32 | 33 | - In `package.json`, add a `scripts` object to the root object like so: 34 | 35 | ```json 36 | "scripts": { 37 | "start": "node ." 38 | } 39 | ``` 40 | 41 | `package.json` must be a valid JSON file, which means that you cannot have trailing commas. So be careful when editing manually your `package.json` file. 42 | 43 | - Run `yarn start`. It should print `Hello world`. 44 | 45 | - Create a `.gitignore` file and add the following to it: 46 | 47 | ```gitignore 48 | npm-debug.log 49 | yarn-error.log 50 | ``` 51 | 52 | **Note**: If you take a look at the `package.json` files I provide, you will see a `tutorial-test` script in every chapter. Those scripts let me test that the chapter works fine when running `yarn && yarn start`. You can delete them in your own projects. 53 | 54 | Next section: [2 - Installing and using a package](/tutorial/2-packages) 55 | 56 | Back to the [table of contents](https://github.com/verekia/js-stack-from-scratch#table-of-contents). 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 и улучшения Redux 2 | 3 | ## Immutable JS 4 | 5 | В отличие от предыдущей части, эта довольно простая и состоит из незначительных улучшений. 6 | 7 | Сначала мы добавим **Immutable JS** в наш проект. Immutable - это библиотека, позволяющая манипулировать объектами, не изменяя их. Вместо: 8 | 9 | ```javascript 10 | const obj = { a: 1 }; 11 | obj.a = 2; // Изменяет `obj` 12 | ``` 13 | 14 | Мы можем сделать так: 15 | 16 | ```javascript 17 | const obj = Immutable.Map({ a: 1 }); 18 | obj.set('a', 2); // Возвращает новый объект не изменяя `obj` 19 | ``` 20 | 21 | Такой подход соответствует парадигме **функционального программирования**, которая хорошо подходит для работы с Redux. Ваши reducer-функции вообще-то **должны** быть чистыми и не изменять состояние хранилища (переданного в качестве параметра), а вместо этого возвращать абсолютно новое. Давайте воспользуемся Immutable, чтобы достичь этого. 22 | 23 | - Запустите `yarn add immutable` 24 | 25 | Мы будем использовать имя `Map` в нашем проекте, но ESLint и конфигурация Airbnb начнут жаловаться на использование capitalized (где первая буква заглавная) имен, если это не имя класса. Добавьте следующее в `package.json` после `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 | Таким образом, мы внесли `Map` и `List` (два Immutable объекта, которые мы будем использовать постояно) в исключения к этому ESLint правилу. Такой подробный стиль форматирования JSON выполняется автоматически Yarn/NPM, так что мы, к сожалению, не можем сделать его более компактным. 42 | 43 | В любом случае, вернемся к Immutable: 44 | 45 | Настройте `dog-reducer.js`, чтобы он выглядел так: 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 | Теперь мы создаем исходное состояние, используя Immutable Map, а новое состояние получаем применяя `set()`, что исключает любые мутации предыдущего состояния. 68 | 69 | В `containers/bark-message.js` обновите функцию `mapStateToProps`, чтобы она использовала `.get('hasBarked')` вместо `.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 | Приложение должно вести себя точно так же, как и до этого. 78 | 79 | **Примечание**: Если Babel жалуется на то, что Immutable превышает 100KB, добавьте `"compact": false` в `package.json` после `babel`. 80 | 81 | Как вы можете видеть из предыдущего фрагмента кода, сам объект state все еще содержит старый атрибут `dog`, являющийся простым объектом и подверженный мутациям. В нашем случае это нормально, но если вы хотите манипулировать только немутируемыми объектами, можете установить пакет `redux-immutable`, чтобы заменить функцию `combineReducers` у Redux. 82 | 83 | **Не обязательно**: 84 | 85 | - Запустите `yarn add redux-immutable` 86 | - Замените функцию `combineReducers` из `app.jsx` на ту, что мы импортировали из `redux-immutable`. 87 | - В `bark-message.js` замените `state.dog.get('hasBarked')` на `state.getIn(['dog', 'hasBarked'])`. 88 | 89 | ## Redux Действя (Actions) 90 | 91 | По мере того, как вы добавляете все больше и больше действий в ваше приложение, вы обнаружите, что приходится писать довольно много одного и того же кода. Пакет `redux-actions` помогает уменьшить этот повторяющийся код. С помощью `redux-actions` вы можете привести файл `dog-actions.js` к более компактному виду: 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` основывается на модели [Flux Standard Action](https://github.com/acdlite/flux-standard-action), так же, как и действия, которые мы создавали до этого, так что интеграция `redux-actions` будет бесшовной, если вы придерживаетесь этой модели. 101 | 102 | - Не забудьте запустить `yarn add redux-actions`. 103 | 104 | Следующий раздел: [11 - Тестирование с Mocha, Chai и Sinon](/tutorial/11-testing-mocha-chai-sinon) 105 | 106 | Назад в [предыдущий раздел](/tutorial/9-redux) или [Содержание](/../../#Содержание). 107 | -------------------------------------------------------------------------------- /tutorial/10-immutable-redux-improvements/READMEeng.md: -------------------------------------------------------------------------------- 1 | # 10 - Immutable JS and Redux Improvements 2 | 3 | ## Immutable JS 4 | 5 | Unlike the previous chapter, this one is rather easy, and consists in minor improvements. 6 | 7 | First, we are going to add **Immutable JS** to our codebase. Immutable is a library to manipulate objects without mutating them. Instead of doing: 8 | 9 | ```javascript 10 | const obj = { a: 1 }; 11 | obj.a = 2; // Mutates `obj` 12 | ``` 13 | 14 | You would do: 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 | This approach follows the **functional programming** paradigm, which works really well with Redux. Your reducer functions actually *have* to be pure functions that don't alter the state passed as parameter, but return a brand new state object instead. Let's use Immutable to enforce this. 22 | 23 | - Run `yarn add immutable` 24 | 25 | We are going to use `Map` in our codebase, but ESLint and the Airbnb config will complain about using a capitalized name without it being a class. Add the following to your `package.json` under `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 | This makes `Map` and `List` (the 2 Immutable objects you'll use all the time) exceptions to that ESLint rule. This verbose JSON formatting is actually done automatically by Yarn/NPM, so we cannot make it more compact unfortunately. 42 | 43 | Anyway, back to Immutable: 44 | 45 | In `dog-reducer.js` tweak your file so it looks like this: 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 | The initial state is now built using an Immutable Map, and the new state is generated using `set()`, preventing any mutation of the previous state. 68 | 69 | In `containers/bark-message.js`, update the `mapStateToProps` function to use `.get('hasBarked')` instead of `.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 | The app should still behave exactly the way it did before. 78 | 79 | **Note**: If Babel complains about Immutable exceeding 100KB, add `"compact": false` to your `package.json` under `babel`. 80 | 81 | As you can see from the code snippet above, our state object still contains a plain old `dog` object attribute, which isn't immutable. It is fine this way, but if you want to only manipulate immutable objects, you could install the `redux-immutable` package to replace Redux's `combineReducers` function. 82 | 83 | **Optional**: 84 | 85 | - Run `yarn add redux-immutable` 86 | - Replace your `combineReducers` function in `app.jsx` to use the one imported from `redux-immutable` instead. 87 | - In `bark-message.js` replace `state.dog.get('hasBarked')` by `state.getIn(['dog', 'hasBarked'])`. 88 | 89 | ## Redux Actions 90 | 91 | As you add more and more actions to your app, you will find yourself writing quite a lot of the same boilerplate. The `redux-actions` package helps reducing that boilerplate code. With `redux-actions` you can rewrite your `dog-actions.js` file in a more compact way: 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` implement the [Flux Standard Action](https://github.com/acdlite/flux-standard-action) model, just like the action we previously wrote, so integrating `redux-actions` is seamless if you follow this model. 101 | 102 | - Don't forget to run `yarn add redux-actions`. 103 | 104 | Next section: [11 - Testing with Mocha, Chai, and Sinon](/tutorial/11-testing-mocha-chai-sinon) 105 | 106 | Back to the [previous section](/tutorial/9-redux) or the [table of contents](https://github.com/verekia/js-stack-from-scratch#table-of-contents). 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 |