Skip to content

Latest commit

 

History

History
367 lines (242 loc) · 30.2 KB

02-babel-es6-eslint-flow-jest-husky.md

File metadata and controls

367 lines (242 loc) · 30.2 KB

02 - Babel, ES6, ESLint, Flow, Jest и Husky

Кода за тази глава можете да намерите тук.

Тук ще използваме ES6 синтаксис, надграждащ "добрия стар" ES5 синтаксис (познат на всички просто като JavaScript). Всички браузъри и JS среди "разбират" и приемат добре ES5, но не и ES6. Тук на помощ идва инструмент наречен Babel!

Babel

💡 Babel е компилатор, който трансформира ES6 код (и други неща като например React's JSX синтаксис) в ES5 код. Предимството е, че е доста модулярен и може да бъде използван в много различни среди. Засега това е предпочитания ES5 компилатор от React обществото.

  • Преместете вашия index.js файл в нова папка наречена src. Това е мястото където ще пишеше вашия ES6 код. Премахнете кода, отнасящ се за color пакета в index.js файла и го заместете с:
const str = 'ES6'
console.log(`Hello ${str}`)

Тук използваме т.нар. темплейт стринг, което е ново свойство, предоставено от ES6, което ни позволява директно инжектиране на променливи в стринг, без да има нужда от конкатенация, използвайки ${}. Обърнете внимание, че това се реализира чрез използване на задни кавички backquotes.

  • Изпълнете yarn add --dev babel-cli, за да инсталирате CLI интерфейса за Babel.

Babel CLI предоставя два модула: babel, който компилира ES6 файлове до ES5 такива и babel-node, който можете да използвате, за да заместите извикванията към node и да изпълнявате директно ES6 файлове. babel-node е чудесен за разработка, но е прекалено тежък и не е предвиден за производствена среда (production). В тази глава ще използваме babel-node за настройка на средата за разработка, а в следващата ще използваме babel за приготвянето на ES5 файловете за production.

  • В package.json, в start скрипта, заместете node . с babel-node src (index.js е файлът по подразбиране, който се търси от Node при първоначалното зареждане, поради което можем да пропуснем изричното му споменаване).

Ако сега опитате да изпълните yarn start, ще отпечата коректно резултата, но всъщност Babel все още не върши никаква работа. Това е така, защото не сме подали никаква информация за трансформациите, които искаме да се приложат. Единствената причина, поради която отпечатва правилно резултата е, че Node разбира ES6 без помощта на Babel. Но някои браузъри или стари версии на Node няма да могат!

  • Изпълнете yarn add --dev babel-preset-env, за да инсталирате един от предварително зададените пакети за Babel наречен env, който съдържа конфигурации за най-новите свойства на ECMAScript, поддържани от Babel.

  • Създайте .babelrc файл в основната директория на вашия проект, който файл е валиден JSON файл за вашата Babel конфигурация. Напишете следното, за да накарате Babel да използва env:

{
  "presets": [
    "env"
  ]
}

🏁 yarn start все още трябва да работи, но сега наистина върши някаква работа. Не можем да кажем дали наистина е така, тъй като използваме babel-node, за да интерпретираме ES6 кода в момента на работа. Скоро ще имате доказателство, че вашия ES6 код наистина се трансформира когато достигнете до синтаксис на ES6 модули секцията от тази глава.

ES6

💡 ES6: Най-значимото подобрение на JavaScript езика. Има прекалено много новости идващи от ES6, за да ги изложа тук. Но един типичен ES6 код би използвал класове с class, константи с const и променливи с let, темплейт стрингове с Test ${a} и arrow функции ((text) => { console.log(text) }).

Създаване на ES6 клас

  • Създайте нов файл, src/dog.js, съдържащ следния ES6 клас:
class Dog {
  constructor(name) {
    this.name = name
  }

  bark() {
    return `Wah wah, I am ${this.name}`
  }
}

module.exports = Dog

Ако не сте се занимавали с ООП (обектно ориентирано програмиране) преди, това не би трябвало да ви изглежда изненадващо, тъй като е сравнително ново и за JavaScript. Класът е открит за използване от външния свят чрез присвояването му на module.exports.

В src/index.js, напишете следното:

const Dog = require('./dog')

const toby = new Dog('Toby')

console.log(toby.bark())

Както можете да видите, за разлика от пакета color, който използвахме преди, тук когато искаме да използваме един от нашите файлове трябва да използваме ./ в require().

🏁 Изпълнете yarn start, трябва да отпечата "Wah wah, I am Toby".

Синтаксис на ES6 модули

Тук просто заместваме const Dog = require('./dog') с import Dog from './dog', което идва от по-новия ES6 синтаксис за ES6 модули (точно обратното на "CommonJS" модулния синтаксис). В момента не се поддържа от NodeJS, така че това е вашето доказателство, че Babel обработва тези ES6 файлове правилно.

В dog.js, също така заместваме module.exports = Dog с export default Dog

🏁 yarn start все още трябва да отпечатва "Wah wah, I am Toby".

ESLint

💡 ESLint е линтерът най-често избиран при работа с ES6 код. Линтер е нещо, което ви дава препоръки (recommendations) за форматиране на кода (code formatting), което налага консистентност в стила (style consistency) на писане на вашия код и кода, който споделяте с вашия екип. Също така е много добър начин за учене на JavaScript чрез правене на грешки, които ESLint хваща и ви показва.

ESLint работи с набор от правила. Техният списък може да намерите тук. Вместо да конфигурираме тези, които искаме да използваме в нашия код, ще използваме конфигурация създадена от Airbnb. Тази конфигурация използва няколко плъгина, така че ще трябва да ги инсталираме и тях.

Проверете най-последните инструкции от Airbnb за инсталиране на конфигурационния пакет и всички негови зависимости (dependencies) правилно. От 03.02.2017 насам, те препоръчват използването на следната команда във вашия терминал:

npm info eslint-config-airbnb@latest peerDependencies --json | command sed 's/[\{\},]//g ; s/: /@/g' | xargs yarn add --dev eslint-config-airbnb@latest

Това би трябвало да инсталира всичко, от което имате нужда и да добави eslint-config-airbnb, eslint-plugin-import, eslint-plugin-jsx-a11y и eslint-plugin-react във вашия package.json файл автоматично.

Забележка: Аз заместих npm install с yarn add в командата. Също така, това няма да работи на Windows, така че погледнете в package.json файла в това репозитори и просто инсталирайте всички неща отнасящи се до ESLint ръчно, използвайки yarn add --dev packagename@^#.#.#, като на мястото на #.#.# поставете версиите на всеки пакет посочени в package.json файла.

  • Създайте .eslintrc.json файл в основната директория на вашия проект, по същия начин както направихме за Babel и напишете следното в него:
{
  "extends": "airbnb"
}

Ще създадем NPM/Yarn скрипт, който да стартира ESLint вместо нас. Нека инсталираме eslint пакета, за да можем да използваме eslint CLI:

  • Изпълнете yarn add --dev eslint

Обновете scripts във вашия package.json като добавите нова test задача:

"scripts": {
  "start": "babel-node src",
  "test": "eslint src"
},

Тук просто казваме на ESLint, че искаме да се изпълнява варху всички JavaScript файлове в папката src.

Ще използваме тази стандартна test задача, за да изпълняваме поредица от всички команди валидиращи по някакъв начин кода ни - било то с лингинг, проверка на типовете или юнит тестване.

  • Изпълнете yarn test и би трябвало да видите цяла поредица от грешки отнасящи се до липсващи точки и запетаи, предупреждения за използвани console.log() в index.js. Добавете /* eslint-disable no-console */ най-отгоре в вашия index.js файл, за да позволите използването на console в този файл.

Забележка: Ако използвате Windows, проверете дали вашия редактор и Git са настроени да използват Unix LF line endings, а не Windows CRLF. Ако вашият проект биде използван само в Windows базирани среди, бихте могли да добавите "linebreak-style": [2, "windows"] в правилата на ESLint масива (вижте примера по-долу), за да наложите използването на CRLF.

Точка и запетая

Добре, това е може би най-разгорещения дебат в JavaScript обществото, нека поговорим една минутка за това. JavaScript притежава нещо наречено Automatic Semicolon Insertion (автоматично вмъкване на точка и запетая), което ви позволява да пишете вашия код с или без точка и запетая. Това наистина зависи главно от личните предпочитания, няма правилен или грешен подход по този въпрос. Ако харесвате синтаксиса на Python, Ruby или Scala, вероятно ще изберете да не слагате точка и запетая в края на всеки ред. Ако предпочитате синтаксиса на Java, C# или PHP, вероятно ще предпочетете да ги слагате.

Повечето хора пишат JavaScript с точки и запетаи по навик. Същото се случи и при мен, докато не видях няколко примера от документацията на Redux и опитах да не ги поставям. В началото ми изглеждаше малко странно, просто защото не бях свикнал. След само един ден на писане на код без точки и запетаи вече не можех да си помисля за връщане назад и използването им отново. Това вече ми изглеждаше толкова тромаво и излишно. Моето мнение е, че код без точки и запетаи е по-лесен за четене и по-бърз за писане.

Препоръчвам да прочетете ESLint documentation about semicolons. Както споменахме вече, ако изберете да не пишете точки и запетаи, трябва да имате предвид, че в някои редки случаи използването им е наложително. ESLint може да ви защити в тези случаи с правилото no-unexpected-multiline. Нека да настроим ESLint за безопасно преминаване към писане на код без точки и запетаи .eslintrc.json:

{
  "extends": "airbnb",
  "rules": {
    "semi": [2, "never"],
    "no-unexpected-multiline": 2
  }
}

🏁 Изпълнете yarn test, сега би трябвало да минава успешно. Опитайте да добавите излишна точка и запетая някъде, за да проверим дали правилото работи коректно.

Сигурен съм, че някои от вас ще предпочетат да продължат да използват точка и запетая, което ще направи кода предоставен в това ръководство малко по-неудобен за използване. Ако използвате ръководството просто за учене, сигурен съм че бихте могли да прескочите използването на точка и запетая докато се върнете към вашите ежедневни проекти. Ако искате да използвате кода предоставен в това ръководство като основа за ваш проект, то тогава ще се наложи да го преработите, което би трябвало да бъде сравнително бърза задача с помощта на ESLint настроен да използва точки и запетаи. Извинявам се ако вашият случай е такъв.

Compat

Compat е един чудесен ESLint плъгин, който ви предупреждава ако се опитвате да използвате някое JavaScript API, което не е налично в браузърите, които искате да поддържате. Използва Browserslist, което разчита на Can I Use.

  • Изпълнете yarn add --dev eslint-plugin-compat

  • Добавете следното във вашия package.json файл, за да покажете, че искаме да поддържаме браузъри, които имат повече от 1% пазарен дял:

"browserslist": ["> 1%"],
  • Редактирайте вашия .eslintrc.json файл със следното:
{
  "extends": "airbnb",
  "plugins": [
    "compat"
  ],
  "rules": {
    "semi": [2, "never"],
    "no-unexpected-multiline": 2,
    "compat/compat": 2
  }
}

Можете да опитате плъгина чрез използването на navigator.serviceWorker или fetch във вашия код например, което би трябвало да доведе до ESLint предупреждение.

ESLint във вашия редактор

В тази глава настроихме ESLint за работа в терминала, което е чудесно за хващане на грешки по време на билдването на проекта (build time) или преди запазване на промените (before pushing), но вие бихте искали също така то да бъде интегрирано във вашата среда за разработка (IDE), за да получавате моментална обратна връзка при възникване на грешка или предупреждение. Не използвайте вградените във вашата среда за разработка опции за линтване. Конфигурирайте го така, че да се използват пакетите във вашата node_modules папка. По този начин ще може да използва всички конфигурации на вашия проект, Airbnb настройките и т.н. В противен случай ще използвате само някои общи правила и опции за линтване.

Flow

💡 Flow: Инструмент за проверка на типовете, създаден от Facebook. Засича неконсистентните типове във вашия код. Например, ще ви даде грешка ако се опитате да използвате стрингова променлива на място, на което се очаква числова такава.

В момента нашия JavaScript код е валиден ES6 код. Flow може да анализира чист JavaScript и да ви даде някои препоръки, но за да използваме пълните му възможности ще трябва да добавим анотации в нашия код, които ще го превърнат в нестандартен JavaScript код. Трябва да покажем на Babel и ESLint какво означават тези анотации, за да предотвратим грешките, които биха дали когато парсваме нашите файлове.

  • Изпълнете yarn add --dev flow-bin babel-preset-flow babel-eslint eslint-plugin-flowtype

flow-bin е пакета, който ни трябва за да можем да стартираме Flow чрез нашите scripts задачи, babel-preset-flow е предварително дефиниран пакет за Babel, за да може да разбира Flow анотациите, babel-eslint е пакет, който позволява ESLint да разчита на парсъра на Babel вместо на своя собствен и eslint-plugin-flowtype е ESLint плъгин за линтване на Flow анотации.

  • Обновете вашия .babelrc файл със следното::
{
  "presets": [
    "env",
    "flow"
  ]
}
  • Обновете също и .eslintrc.json файла:
{
  "extends": [
    "airbnb",
    "plugin:flowtype/recommended"
  ],
  "plugins": [
    "flowtype",
    "compat"
  ],
  "rules": {
    "semi": [2, "never"],
    "no-unexpected-multiline": 2,
    "compat/compat": 2
  }
}

Забележка: plugin:flowtype/recommended съдържа инструкцията за ESLint за използване на парсъра на Babel. Ако искате да бъдете още по-изчерпателни, можете да добавите "parser": "babel-eslint" в .eslintrc.json.

Знам, че инфромацията до тук е много за възприемане, така че си вземете минутка и помислете малко. Аз съм още изумен, че дори е възможно за ESLint да използва парсъра на Babel, за да може да разбира Flow анотации. Тези два инструмента са наистина невероятни от гледна точка на модулярността, която предлагат.

  • Добавете flow във вашата test задача:
"scripts": {
  "start": "babel-node src",
  "test": "eslint src && flow"
},
  • Създайте .flowconfig файл в основната директория на вашия проект:
[options]
suppress_comment= \\(.\\|\n\\)*\\flow-disable-next-line

Това е една полезна настройка, която използваме, за да накараме Flow да игнорира всякакви предупреждения и съобщения на следващия ред. Използва се по следния начин, подобно на eslint-disable:

// flow-disable-next-line
something.flow(doesnt.like).for.instance()

Добре, до тук би трябвало да сме готови с конфигуриционната част.

  • Добавете Flow анотации в src/dog.js по следния начин:
// @flow

class Dog {
  name: string

  constructor(name: string) {
    this.name = name
  }

  bark() {
    return `Wah wah, I am ${this.name}`
  }
}

export default Dog

// @flow коментарът казва на Flow, че искаме типовете в този файл да бъдат проверени. В останалата си част, Flow анотациите са просто две точки след параметър на функция или име на функция. Проверете документацията за повече подробности.

  • Добавете // @flow най-отгоре във вашия index.js файл.

yarn test сега би трябвало да извърши линтването и да провери типовете във вашия код.

Има 2 неща, които искам да опитате:

  • В dog.js, заместете constructor(name: string) с constructor(name: number) и изпълнете отново yarn test. Би трябвало да получите Flow грешка, указваща, че тези типове са несъвместими. Това значи, че Flow е настроен правилно.

  • Сега заместете constructor(name: string) с constructor(name:string) и изпълнете yarn test. Би трябвало да получите ESLint грешка, указваща, че Flow анотациите трябва да имат разстояние след двуеточието. Това значи, че Flow плъгина за ESLint е настроен коректно.

🏁 Ако сте получили двете различни грешки значи сте готови с настройването на Flow и ESLint! Не забравяйте да поставите обратно разстоянието във Flow анотацията.

Flow във вашия редактор

Точно както направихме с ESLint, ще тябва да конфигурирате вашия редактор / IDE, за да получавате моментална обратна връзка когато Flow засече проблем във вашия код.

Jest

💡 Jest: JavaScript библиотека за тестване, създадена от Facebook. Много лесна за първоначална настройка и предлага всичко, което бихте очаквали от една библиотека за тестване. Също така може да тества React компоненти.

  • Изпълнете yarn add --dev jest babel-jest, за да инсталирате Jest и пакета, чрез който да използва Babel.

  • Добавете следното във вашия .eslintrc.json, за да позволите употребата на функциите на Jest без да трябва да ги импортвате във всеки един файл:

"env": {
  "jest": true
}
  • Създайте src/dog.test.js файл, съдържащ:
import Dog from './dog'

test('Dog.bark', () => {
  const testDog = new Dog('Test')
  expect(testDog.bark()).toBe('Wah wah, I am Test')
})
  • Добавете jest във вашия test скрипт:
"scripts": {
  "start": "babel-node src",
  "test": "eslint src && flow && jest --coverage"
},

Флагът --coverage кара Jest да генерира информация за покритието на вашите тестове автоматично. Това е полезно когато искате да видите кои части от вашия код не са подсигурени с тестове. Той записва тази информация в папка coverage.

  • Добавете /coverage/ във вашия .gitignore

🏁 Изпълнете yarn test. След линтинга и проверката на типовете, би трябвало да изпълни Jest тестовете и да покаже таблица с тест покритието. Всичко трябва да бъде зелено!

Git Hooks с Husky

💡 Git Hooks: Скриптове, които се изпълняват когато настъпи дадено действие, например вмъкване (commit) или запазване (push) на промени в кода.

Окей, до момента имаме нашата test задача, която ни казва дали нашия код изглежда добре или не. Ще настроим т.нар. "кукички" (Git Hooks), чрез които ще изпълняваме автоматично тази задача преди всеки git commit и git push, което ще предотврати възможността за "вмъкване" на лош код в репозиторито, т.е. код който не минава проверките в test задачата.

Husky е пакет, чрез който настройването и използването на "кукички" (Git Hooks) става много лесно.

  • Изпълнете yarn add --dev husky

Всичко, което трябва да направим сега е да създадем две нови задачи в scripts - precommit and prepush:

"scripts": {
  "start": "babel-node src",
  "test": "eslint src && flow && jest --coverage",
  "precommit": "yarn test",
  "prepush": "yarn test"
},

🏁 Ако сега се опитате да запазите промените във вашия код, задачата test ще се стартира автоматично.

Ако не работи правилно е възможно yarn add --dev husky да не е инсталирал Git Hooks правилно. На мен лично никога не ми се е случвало, но на други хора - да. Ако това се случи и при вас, изпълнете yarn add --dev husky --force, може да публикувате нов пост тук с описание на случилото се.

Забележка: Ако запазвате (pushing) вашите промени веднага след като сте ги вмъкнали (commit), можете да използвате git push --no-verify, за да избегнете пускането на всички тестове отново.

Следваща глава: 03 - Express, Nodemon, PM2

Назад към предишната глава или към съдържанието.