Главная » Хабрахабр » Настраиваем удобный npm проект для себя и команды или немного о современных фронтенд инструментах

Настраиваем удобный npm проект для себя и команды или немного о современных фронтенд инструментах

Недавно мне попалась задача настроить оборот приватных npm пакетов. Всем привет. Тут бы все и закончилось, но возникла вторая задача — написать демо репозиторий для npm пакета, который можно было бы взять, клонировать и на его базе быстро создать что-то полезное и в едином стиле. Все звучало очень интересно и многообещающе пока не оказалось, что делать там совсем не много.

Плюс удобная публикация в npm. В результате получился проект с настроенным форматированием, кодстайлом, тестами на каждый пулл, лимитами на покрытие кода, отчетом о покрытии кода и автоматической документацией. Подробности о настройке — под катом.

Требования

Cначала я прикинул что у нас уже есть:

  • Новые проекты пишутся на TypeScript
  • Кроме новых проектов, есть еще куча проектов на чистом JavaScript
  • Есть требования писать тесты и результаты нужно отправлять на анализ

Что я хочу еще: Потом прикинул свои хотелки — раз уж есть время и желание, почему бы не разгуляться.

  • Хочу единый стиль форматирования
  • Хочу единый стиль TypeScript
  • Хочу документацию, но не хочу ее писать
  • Вообще хочу все автоматизировать по максимуму. Что бы фыр-фыр-фыр и в продакшн

В итоге требования оформились в следующее:

  • Модуль должен быть на TypeScript и проверен с помощью TsLint
  • Модуль должен быть используемым из-под TypeScript и из-под JavaScript
  • Тесты должны быть настроены на git hook, минимальное покрытие кода должно быть тоже настроено, статистика должна быть
  • Форматирование должно быть настроено
  • Документация должна создаваться из кода
  • Публикация должна быть удобной и единообразной
  • Все что можно должно быть автоматизировано

Вроде бы неплохо, нужно пробовать.

Предварительные телодвижения

Вообще все зависимости ставим локально, т.к. Создаем (клонируем) репозиторий, инициализируем package.json, ставим локально TypeScript. Не забываем фиксировать зависимости версий. все будет уходить на сервер.

git init
npm init
npm i -D typescript
./node_modules/.bin/tsc --init

Тут же на месте нужно подправить tsconfig.json под себя — выставить target, libs, include/exclude, outDir и остальные опции.

Стиль форматирования

Первый это файл .editorconfig. Для сохранения единообразия форматирования я взял два инструмента. Он понимается всеми основными IDE (WebStorm, VSCode, Visual Studio и т.д.), не требует установки ничего лишнего и работает с большим количеством типов файлов — js, ts, md, и так далее.

#root = true [*] indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 100
indent_size = 4 [*.md] trim_trailing_whitespace = false

Теперь автоформатирование будет вести себя более-менее одинаково у меня и у коллег.

Это npm пакет, который проверяет, и по возможности, автоматически корректирует ваше форматирование текста. Второй инструмент — prettier. Установите его локально и добавьте первую команду в package.json

npm i -D prettier

package.json

"prettier": "prettier --config .prettierrc.json --write src/**/*.ts"

Создайте .prettierrc.json в корне проекта вот примерно с таким спорным содрежанием (если что — пост совсем не о том, какие кавычки лучше, но вы можете попробовать) У prettier нет команды init, так что конфигурировать его нужно вручную.

.prettierrc.json

{ "tabWidth": 4, "useTabs": false, "semi": true, "singleQuote": true, "trailingComma": "es5", "arrowParens": "always"
}

Если ему не понравится ваше форматирование — он его исправит автоматически. Теперь создайте папку src, в ней создайте index.ts с каким-то условным содержанием и попробуйте запустить prettier. Если вы не хотите вспоминать об этом только во время коммита/пуша можно настроить его на автозапуск или поставить расширение для студии. Очень удобно.

Стиль кода

Для JavaScript есть eslint, для TypeScript есть tslint. Со стилем кода все тоже не сложно. Ставим tslint и создаем tsconfig.js для хранения настроек

npm i -D tslint
./node_modules/.bin/tslint --init

package.json

"lint": "tslint -c tslint.json 'src/**/*.ts' 'tests/**/*.spec.ts'"

Вот, например, конфиг от airbnb. Вы можете написать собственные правила, а можете использовать уже существующие правила с помощью параметра extend.

Разработчики tslint шутят

module.exports = ] }
};

Ну разве это не красиво?

Так что, если вы будете использовать оба — нужно будет следить за соответствием или отказаться от чего-то. Есть важный момент — tslint и prettier пересекаются по функционалу (например в длинне строки или "висящих" запятых).

И еще, для тех кто хочет проверять не все файлы, а только staged — есть пакет lint-staged

Тесты

Во-первых, чтобы они запускались автоматически, во-вторых контроль покрытия, в-третьих какой-то отчет, желательно в lcov формате (если что — lcov отлично понимается разными анализаторам — от SonarQube до CodeCov). Что нам нужно от тестов прежде всего? Автоматизацией мы займемся чуток позже, пока настроим сами тесты.

Ставим karma, jasmine и весь соответствующий ей обвес

npm i -D karma karma-jasmine jasmine karma-typescript karma-chrome-launcher @types/jasmine
./node_modules/.bin/karma init

Немного модифицируем karma.conf.js и сразу настроим работу с покрытием

karma.conf.js

karmaTypescriptConfig : { include: ["./src/**/*.ts", "./tests/**/*.spec.ts"], tsconfig: "./tsconfig.json", reports: { "html": "coverage", "lcovonly": { directory: './coverage', filename: '../lcov.dat' } }, coverageOptions: { threshold: { global: { statements: 60, branches: 60, functions: 60, lines: 60, excludes: [] }, file: { statements: 60, branches: 60, functions: 60, lines: 60, excludes: [], overrides: {} } } },
}

И, конечно, не забываем дописать новую команду в package.json

package.json

"test": "karma start"

Если вы используете или планируете использовать CI то лучше поставить HeadlessChrome:

npm i -D puppeteer

Правки можно посмотреть в демо репозитории. И доконфигурировать Karma (Chrome исправить на ChromeHeadless) плюс еще кое-что.

Заодно проверьте отчет о покрытии (он находится в папке coverage) и уберите его из-под контроля версий, в репозитории он не нужен. Запустите тесты, проверьте что все работает.

Отчет:

Стиль коммитов

Для этого я взял commitizen. Коммиты тоже можно унифицировать (и заодно довести кого-то до белого каления, если переборщить, так что лучше без фанатизма). Он работает в форме диалога, поддерживает conventional-changelog формат (из его коммитов можно создавать changelog) и для него есть VsCode плагин

npm i -D commitizen
npm i -D cz-conventional-changelog

cz-conventional-changelog это адаптер, который отвечает за вопросы, и как следствие, за формат ваших коммитов

Добавьте новую команду в scripts секцию

"commit":"git-cz"

И новую секцию package.json — config для commitizen

"config": { "commitizen": { "path": "./node_modules/cz-conventional-changelog" } }

Диалог с commitizen выглядит так:

Документация

Документация у нас будет двух видов — из кода и из коммитов. Теперь к документации. Он очень просто ставится и работает. Для документации из кода я взял typedoc (аналог esdoc но для TypeScript). Главное не забудьте убрать результаты его трудов из-под контроля версий.

npm i typedoc -D

и обновляем package.json

package.json

"doc": "typedoc --out docs/src/ --readme ./README.md"

Флаг --readme заставит включить readme в главную страницу документации что удобно.

Второй тип документации это changelog, и с ним нам поможет conventional-changelog-cli пакет.

npm i -D conventional-changelog-cli

package.json

"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"

Теперь для того что бы обновить changelog достаточно запусть npm run changelog. От angular здесь только форматирования и ничего больше. Ну мы же всегда пишем идеальные коммиты, так что это проблемой быть не должно. Главное внимательно писать коммиты.

Билд

Кроме того, неплохо было бы сделать еще и минифицированный бандл, просто на всякий случай. Поскольку наш пакет должен работать и для JavaScript, нам нужно превратить TypeScript в JavaScript. Для этого нам понадобится uglifyjs и немного подправить package.json

npm i -D uglifyjs

package.json

"clean":"rmdir dist /S /Q", "build": "tsc --p ./ --sourceMap false", "bundle": "uglifyjs ./dist/*.js --compress --mangle --output ./dist/index.min.js"

Кстати, если вы хотите контролировать размер вашего проекта, есть еще два интересных пакета

Очень, очень полезно. Их точно также можно интегрировать в процесс коммита/пуша/паблиша что бы держаться в допустимых размерах бандла.

Автоматизация

Ну вот, основные шаги мы уже сделали, теперь все нужно автоматизировать иначе работать будет откровенно неудобно.

Он переписывает git hooks и вызывает сопоставленные команды из package.json. Для этого нам понадобится еще один пакет — husky. Если скрипт вернет ошибку, коммит упадет. Например, когда вы делаете коммит, сработает precommit, push — prepush и так далее.

npm i -D husky

package.json

"precommit":"npm run prettier", "prepush": "call npm run lint && call npm run test"

Так что если хотите все сделать по-честному придется поставить еще и npm-run-all пакет, он делает все тоже самое но кросплатформенно. Тут есть важный нюанс, использование call синтаксиса не кроссплатформенно и на unix системах не взлетит.

Публикация

Давайте подумаем, что мы хотим от публикации? Ну вот мы и дошли до публикации нашего (пусть и пустого) пакета.

  • Еще раз все протестировать
  • Собрать билд артефакты
  • Собрать документацию
  • Поднять версию
  • Запушить теги
  • Отправить в npm

Или забудешь что-то, или чеклист писать нужно. Руками это все делать — грустно. Можно поставить еще один пакет — unleash. Нужно тоже автоматизировать. А можно воспользоваться нативными хуками самого npm — preversion, version, postversion, например вот так:

"preversion": "npm run test", "version": "call npm run clean && call npm run build && npm run bundle && call npm run doc && call npm run changelog && git add . && git commit -m 'changelogupdate' --no-verify", "postversion": "git add . && git push && git push --tags",

Осталось указать для package.json что включать в пакет, точку входа и путь к нашим типам (не забудьте указать --declaration флаг в tsconfig.json что бы получить d.ts файлы)

package.json

"main": "./dist/index.min.js", "types": "./dist/index.d.ts", "files": [ "dist/", "src/", "tests/" ]

Теперь достаточно выполнить Ну вот вроде бы и все.

npm version ...
npm publish

И все остальное будет сделано в автоматическом режиме.

Бонус

Напомню, там настроен HeadlessChrome так что, если вам это важно, советую туда заглянуть. В качестве бонуса есть демо репозиторий, который все это поддерживает + CI с помощью travis-ci.

Благодарности

Большая благодарность Алексею Волкову за его доклад на JsFest, который и стал основой этой статьи.

Спасибо max7z, indestructible, justboris за уточнение, что пути к локальным зависимостям можно не указывать.

И немного статистики

  • Размер node_modules: 444 MB (NTFS)
  • Количество зависимостей первого уровня: 17
  • Общее количество использованых пакетов: 643

Полезные ссылки


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

[Из песочницы] Валидация сложных форм React. Часть 1

Для начала надо установить компонент react-validation-boo, предполагаю что с react вы знакомы и как настроить знаете. npm install react-validation-boo Чтобы много не болтать, сразу приведу небольшой пример кода. import React, from 'react'; import {connect, Form, Input, logger} from 'react-validation-boo'; class ...

[Перевод] Микросервисы на Go с помощью Go kit: Введение

Эта статья — введение в Go kit. В этой статье я опишу использование Go kit, набора инструментов и библиотек для создания микросервисов на Go. Первая часть в моем блоге, исходный код примеров доступен здесь. Когда вы разрабатываете облачно-ориентированную распределенную систему, ...