Настройка среды разработки: инструкция для новичков
Первые шаги в разработке могут быть сложными – ведь вы еще не знаете об инструментах и средствах, которые могут облегчить вашу задачу. О них – эта статья от преподавателя GeekBrains Артема Шашкова. Здесь состоится ваше знакомство со средой разработки, с Node.js и NPM, а также Gulp. Интересно? Тогда загляните и в вебинар Артема Шашкова «Настройка среды разработки Frontend-разработчика» – чтобы увидеть, как применить на практике материал статьи.
Выбираем среду разработки
IDE – Integrated Development Environment, или интегрированная среда разработки – это система программных средств, предназначенная для создания ПО. Сред существует много: от бесплатных, с минимально достаточным функционалом, до мощных платных программ с внушительной ценой. Рекомендация новичкам – бесплатный Visual Studio или Brackets. Если цена для вас – не преграда, то попробуйте продукт от JetBrains.
Выбираем IDE, устанавливаем и запускаем ее, и создаем пока пустой проект. Еще немного теории – и начнем писать «магические заклинания», которые помогут в разработке.
Таск-менеджер и Ко
Чтобы «творить магию», потребуется таск-менеджер, предназначенный для автоматического выполнения часто возникающих задач. Наиболее популярны Grunt, Webpack и Gulp. Первый уже устарел и не блещет скоростью, второй быстро новичку не поддастся – сложноват в освоении. А Gulp – то, что нужно: быстрый и простой.
Gulp написан на JavaScript. Для работы с ним используется командная строка, а задачи описываются в специальном файле – gulpfile. Для работы с Gulp понадобятся Node.js и NPM.
Node или Node.js – это программная платформа. Она основана на движке V8, который транслирует JavaScript в машинный код. Node.js превращает JavaScript из узкоспециализированного – в язык общего назначения. Берем платформу отсюда и ставим LTS-версию, так как она протестирована и стабильна.
NPM (Node.js Package Manager) – это менеджер пакетов, входящий в состав Node.js. С его помощью будем устанавливать все необходимое для работы.
Устанавливаем и настраиваем инструментарий
Работать будем в консоли (терминале), так что открываем ее либо в IDE, либо отдельно. Создаем в IDE новый проект (например, «frontend»). Проверяем, успешно ли установился Node.js: набираем в консоли:
node -v
или
npm -v
Если все сделано правильно, в консоли увидим версию ПО. Если нет – пробуем перезапустить консоль или переустановить Node.
Node установилась, NPM на месте – можно инициализировать проект. Переходим в консоли в корневую папку проекта и пишем там же:
npm init
На все вопросы отвечаем утвердительно – нажимаем «Enter» (эти настройки пока нам не интересны). По завершении в корне проекта получаем файл package.json – это своего рода «инструкция по сборке». В нем хранится информация о всех зависимостях, задействованных в проекте.
Устанавливаем Gulp: сначала глобально, а далее уже локально – в каждом проекте, где планируется его использовать. Будем работать с четвертой версией, где есть интересные и полезные новые фишки.
Пишем в консоли:
npm i -g gulpjs/gulp#4.0 npm i gulpjs/gulp#4.0
Первая команда ставит Gulp глобально, а вторая – непосредственно в наш проект.
Процесс может занять некоторое время – ждем.
После успешной установки в проекте появится папка node_modules, а в файле package.json – следующие строки:
"dependencies": { "gulp": "github:gulpjs/gulp#4.0" }
Это наша новая зависимость! В больших проектах таких могут быть десятки.
Теперь все готово для того, чтобы создать первую задачу.
Пишем первый таск
Создадим в корне проекта отдельный файл для описания и назовем его gulpfile.js. Открываем его и пишем первый таск (задачу):
const gulp = require('gulp'); gulp.task('hello', function (callback) { console.log('Hello!'); callback(); });
В первой строке подключаем Gulp (далее будем действовать аналогично с остальными необходимыми модулями).
Любой таск в Gulp создается методом .task(), который принимает два аргумента – название задачи и функцию-обработчик. Отметим, что в Gulp задачи асинхронны: надо дать знать, что задача выполнена, и ее выполняет callback() (в данном таске это просто функция-пустышка, так как нам нечего возвращать). Если этого не сделать, то в консоли мы увидим:
[01:57:52] Using gulpfile ~\WebstormProjects\frontend\gulpfile.js [01:57:52] Starting 'hello'... Hello! [01:57:52] The following tasks did not complete: hello [01:57:52] Did you forget to signal async completion?
Первый таск создан: можно запускать его в консоли! Пишем команду:
gulp hello
Здесь gulp – это вызов собственно gulp, а hello – название таска, который хотим выполнить. Все очень просто.
Усложняемся – работаем с препроцессором
Создадим что-то более сложное и функциональное, а попутно познакомимся с оставшимися методами Gulp.
Выстраиваем структуру папок. При разработке принято хранить исходники и сборку в разных папках. Создаем их: src для исходных материалов и build для готовой сборки.
Чтобы усложнить задачу, добавим в разработку препроцессор pcss (CSS-препроцессор). Это надстройка, которая с помощью новых синтаксических конструкций добавляет CSS ранее недоступные возможности. Происходит преобразование кода, написанного с использованием препроцессорного языка, в чистый и валидный CSS-код.
Установим препроцессор и несколько вспомогательных библиотек для работы с css.
Ставим сам препроцессор:
npm i gulp-postcss
Далее устанавливаем autoprefixer, cssnext и precss
npm i autoprefixer npm i cssnext npm I precss
В файле package.json появляются следующие строки:
"gulp-postcss": "^7.0.0", "autoprefixer": "^7.1.6", "cssnext": "^1.8.4", "precss": "^2.0.0" "gulp-dest": "^0.2.3",
Понимаете, для чего это нужно? Скоро сами удивитесь, как это полезно.
Подключаем препроцессор и дополнительные модули (в начале файла):
const postcss = require('gulp-postcss'); const autoprefixer = require('autoprefixer'); const cssnext = require('cssnext'); const precss = require('precss'); const dest = require('gulp-dest');
Создадим в src папку pcss, где будем хранить стили. Добавим файл style.pcss и опишем несколько стилей в синтаксисе pcss:
* { padding: 0; margin: 0; } .firstClass { background: #f00; &__active { border: 1px solid #000; &-on { border-color: #0f0; } } } .hello { font-size: 60px; color: #000000; }
Файл готов! Создадим «таск», который будет переписывать pcss в css и класть в папку build/css. Для удобства работы с директориями добавим в gulpfile объект конфигурации:
const config = { src: "./src", // директория с исходниками build: "./build" // Директория сборки };
Теперь напишем сам таск и назовем его «css»:
gulp.task('css', function () { const processors = [autoprefixer, cssnext, precss]; return gulp.src(`${config.src}/pcss/**/*.pcss`) .pipe(postcss(processors)) .pipe(dest('css', {ext: '.css'})) .pipe(gulp.dest(config.build)) });
Разберемся, что тут происходит:
const processors = [autoprefixer, cssnext, precss];
Задан массив с дополнительными модулями для нашего postcss. Далее идет возврат (return) «цепочки» потоков (.pipe в каждом таком потоке выполняются какие-то задачи).
Метод .src у gulp указывает, откуда брать файлы для обработки (/**/*.pcss говорит о том, что нужно сканировать текущую и все вложенные папки на наличие файлов с расширением pcss).
Gulp.dest задает, куда положить результат обработки. Postcss вызывает обработку .pcss-файлов с параметрами из processors. dest (не путать с gulp.dest), дает возможность задать расширение выходного файла (в нашем случае – .css) и папку, в которую нужно положить файл.
Задача написана – протестируем ее! Набираем в консоли:
gulp css
Наблюдаем следующее:
$ gulp css [13:29:26] Using gulpfile ~/Downloads/frontend/gulpfile.js [13:29:26] Starting 'css'... [13:29:27] Finished 'css' after 1.08 s
Переходим в build и видим, что там появилась папка css, а в ней – файл style.css с таким содержанием:
* { padding: 0; margin: 0; } .firstClass { background: #f00; } .firstClass__active { border: 1px solid #000; } .firstClass__active-on { border-color: #0f0; } .hello { font-size: 60px; color: #000000; }
Перед нами привычный CSS-код, который можно подключить html-файлу.
Собираем js
Будем используем ES6-синтаксис – понадобится соответствующий плагин, чтобы сохранить кроссбраузерность приложения. Ставим Babel (занимается преобразованием ES6 в ES5):
npm i babel-core npm i gulp-babel babel-preset-env
Подключаем Babel:
const babel = require('gulp-babel');
Напишем задачу ‘js’, которая будет обрабатывать js-файлы:
gulp.task('js', function () { return gulp.src('./src/js/**/*.js') .pipe(babel({ presets: ['env'] })) .pipe(gulp.dest(`${config.build}/js`)) });
Все аналогично задаче css, только вместо postcss в дело вступает babel.
Напишем простенький js-файл с ES6-кодом (пусть это будет script.js, размещенный в папке src/js). Испытаем работу таска:
function hello(name) { return `Hello! ${name}`; } console.log(hello('Петя!'));
Выполним задачу:
gulp js
Результатом будет файл script.js в папке build/js со следующим содержанием:
'use strict'; function hello() { var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'n/a'; return 'Hello! ' + name; } console.log(hello('Петя'));
В результате работы Babel код немного усложнился по сравнению с исходным.
С одним файлом все хорошо, но что произойдет, если их будет 2, 3, 10 и больше? Совсем неудобно все это подключать к странице. Эту проблему поможет решить модуль gulp-concat.
Поставим его:
npm i gulp-concat
Скорректируем gulpfile:
const concat = require('gulp-concat');
Доработаем таск js:
gulp.task('js', function () { return gulp.src(`${config.src}/js/**/*.js`) .pipe(babel({ presets: ['env'] })) .pipe(concat('main.js')) .pipe(gulp.dest(`${config.build}/js`)) });
Теперь concat(‘main.js’) объединяет все файлы в один – main.js, который удобно подключать к странице (попробуйте создать несколько файлов и понаблюдайте за результатом).
Научившись обрабатывать стили, JavaScript-код, вы все еще каждый раз набираете gulp ‘task’ в консоли. Это не очень удобно. Можно ли объединить все в одной задаче?
Да, и прежде чем это сделать, напишем еще пару вспомогательных тасков для очистки папки сборки и переноса остальных файлов (html, картинок, шрифтов и т.д.).
Ставим ‘del’:
npm i del
Подключаем:
const del = require('del');
Напишем задачи ‘clr’ и ‘assets’. Первая будет вычищать папку build перед сборкой, а вторая – просто переносить файлы.
gulp.task('clr', function () { return del('${config.build}/*') });
gulp.task('assets', function () { return gulp.src('./src/assets/**') .pipe(gulp.dest('./build/')); });
Создадим отдельный таск для html:
gulp.task('html', function () { return gulp.src(`${config.src}/assets/*.html`) .pipe(gulp.dest('./build')) });
Теперь можем вычищать нашу директорию сборки и переносить остальные файлы. Но при разработке изменения происходят во многих файлах, и каждый раз нужно пересобирать проект вручную. Чтобы избавиться от этой рутины, воспользуемся методом gulp.watch.
Напишем задачу ‘watch’, которая будет отслеживать изменения в нужных файлах и при необходимости запускать соответствующие таски:
gulp.task('watch', function () { gulp.watch(`${config.src}/pcss/**/*.pcss`, gulp.series('css')); gulp.watch(`${config.src}/js/**/*.js`, gulp.series('js')); gulp.watch(`${config.src}/assets/*.html`, gulp.series('html')); });
В данной задаче мы следим за изменениями в файлах стилей, скриптов и html.
Осталось написать задачу для первичной сборки – назовем ее ‘build’, а также задачу ‘default’, которая позволит, просто набрав команду ‘gulp’, собрать проект и запустить «вотчеры».
Задача ‘build’:
gulp.task('build', gulp.series( 'clr', gulp.parallel('css', 'js', 'assets', 'html') ));
Используем метод .parallel, чтобы ускорить процесс и запустить все задачи в параллельных потоках.
Задача ‘default’:
gulp.task('default', gulp.series('build', gulp.parallel('watch', 'server')));
Метод .series запускает задачи последовательно: сначала выполнится ‘build’, а далее параллельно стартуют ‘watch’ и ‘server’.
Пишем задачу ‘server’
Стоп, что за задача ‘server’ – откуда, зачем? Это для «полного фэншуя» в разработке. Она «поднимает» виртуальный сервер, перезагружает браузеры и синхронизирует их в случае изменений. И все это – при помощи одной команды ‘gulp’, введенной перед началом работы. Далее все происходит автоматически. Magic!
Ставим модуль ‘browser-sync’ для задачи ‘server’:
npm i browser-sync
Подключаем:
const browserSync = require('browser-sync').create();
И пишем таск ‘server’:
gulp.task('server', function () { browserSync.init({ server: { baseDir: config.build, index: 'index.html' } }); browserSync.watch(`${config.build}/**/*.*`).on('change', browserSync.reload) });
Запускаем сервер, в настройках которого указываем базовую директорию (config.build) и индекс-файл, который будет открываться в браузере.
Остается набрать в консоли gulp и наслаждаться разработкой.
Сжимаем код
В заключение – небольшой бонус. Минифицируем JavaScript-код, чтобы уменьшить конечный размер файла.
Ставим gulp-uglifyjs:
npm i gulp-uglifyjs
Дорабатываем таск ‘js’:
gulp.task('js', function () { return gulp.src(`${config.src}/js/**/*.js`) .pipe(babel({ presets: ['env'] })) .pipe(concat('main.js')) .pipe(uglifyJs()) .pipe(gulp.dest(`${config.build}/js`)) });
Перезапускаем и снова выполняем ‘gulp’ (остановить предыдущий можно нажатием ctrl+c), чтобы применились изменения. Код в main.js теперь сжат: читаемость стала хуже, но функциональность сохранилась.
P.S. Помните, мы говорили про зависимости и package.json? Попробуйте удалить папку build и node_ modules, а затем выполнить задачи. Оп, ничего не работает!.. А теперь – еще немного магии. В консоли в корне проекта пишем команду npm i и дожидаемся ее выполнения. Пробуем выполнить задачи теперь... Бинго!
Так вы можете легко развернуть ваш проект на любой другой машине. Помните: никогда не переносите проект полностью, то есть с папкой node_modules и папкой со сборкой. Ведь на разных операционных системах различные модули могут работать некорректно – их нужно ставить под конкретную ОС. Перенося проект, который разрабатывался на Win, на машину с MacOS, вы рискуете – может и «не завестись». Скорее всего, вам придется частично или полностью переустанавливать модули.
Код из этой статьи можно использовать как основу при автоматизации разработки в ваших проектах. Вы можете легко модифицировать gulpfile.js, добавляя или удаляя новые модули и задачи. Удачи в кодинге!