Gulp

22 Июля 2020 14:00 (Редактировано: 30 Июля 2020 15:29)

Gulp - сборщик проектов, написанный на языке программирования Javascript. Предназначен для автоматизации типовых задач, возникающих при работе с проектом (копирование, преобразование, компиляция файлов и многое другое).

В данной статье я рассмотрю настройку gulp для проекта, состоящего из двух частей - тестовый (app-vue.loc) и продакшн (vue.loc). Создавать/изменять файлы, настраивать сборщик будем на тестовом, а копироваться и собираться все будет на продакшн. В статье все отражено как есть со всеми путями к локальным проектам.

Программное окружение:

  1. Windows 10;
  2. OpenServer (Apache 2.4, PHP 7.4, MariaDB 10.1);
  3. PHPStorm;
  4. GIT.

Подготовка рабочего пространства

Для установки gulp и настройки сборщика необходим менеджер пакетов npm, который идет в составе Node.js. Поэтому качаем node.js с офф. сайта и устанавливаем его как обычную программу.

Далее, для работы потребуется рабочая среда: Visual Studio, PHPStorm, WebStorm и т.д. Я использую, по большей части, PHPStorm. Качаем то, что по душе и устанавливаем.

Подготовка проекта

Структура проекта

Для начала создадим такую структуру проекта:

-vue-app.loc
--index.html
--main.js

Здесь всего два файла: точка входа index.html и основной файл со скриптами main.js, в нем будут подключаться библиотеки с помощью системы сборки.

Настройка сборщика

После того как убедились, что Node.js установлен и все работает, открываем терминал и вводим следующую команду для инициализации проекта:

npm init

Нам будут заданы вопросы по проекту. Можем заполнить поля либо пропустить, это не принципиально. Можно будет дозаполнить в файле package.json.

Установка Jquery

Проект инициализирован! Теперь можно приступать к установке библиотек. Установим Jquery. Вводим в терминал следующую команду:

npm install jquery

В корне проекта будет создана директория node_modules. Ее не нужно трогать, в нее будут сваливаться все необходимые библиотеки.

Далее открываем файл main.js и выписываем туда следующую конструкцию:

const $ = require("jquery");

Такая конструкция подключит закачанный нами jquery в проект с помощью системы сборки, но ее у нас пока нет поэтому работать не будет! Ее настроим чуть позже. Для начала, нужно установить gulp.

Установка gulp

Запускаем следующую команду:

npm install gulp --save-dev

После этого, в файле package.json появится запись о gulp:

Далее создаем в корне проекта файл gulpfile.js. В этом файле мы определим логику работы сборщика. Пишем следующий код в файл:

const gulp = require("gulp");

gulp.task("copy-html", () => {
    return gulp.src("./app/src/index.html")
        .pipe(gulp.dest(dist));
});

Внутри блока gulp.task мы описываем задачу, которая будет выполняться. В данном случае, будет скопирвоан файл index.html из указанного места в другое указанное место. В принципе, можно это по тестировать и по вводить команду gulp copy-html в терминал попутно меняя содержимое файла index.html. Таким образом, мы увидим, что команда отрабатывает корректно, в противном случае, искать ошибку!

Установка модулей для gulp

1. Browserify

Модуль, позволяющий использовать конструкции require('modules') и проводить сборки зависимостей.

Документация - ссылка.

Устанавливаем его через терминал в режиме разработки:

npm install browserify --save-dev

2. Vinyl-source-stream

Обеспечивает наилучшее взаимодействие browserify с gulp.

Документация - ссылка.

Устанавливаем в режиме для разработки:

npm install vinyl-source-stream --save-dev

Далее, приводим файл gulpfile.js к следующему виду:

const gulp = require("gulp");
const source = require('vinyl-source-stream');
const browserify = require('browserify');

const dist = "C:/OpenServer/domains/vue.loc/admin";

//Копирует index.html, с которым мы работаем
gulp.task("copy-html", () => {
    return gulp.src("./app/src/index.html")
        .pipe(gulp.dest(dist));
});

//Собирает js-файл из main.js. В Последнем же будут прописаны директивы для сборки типа require.
//Конечный файл будет помещен по указанному адресу в константе dist
gulp.task("build-js", () => {
    return browserify('./app/src/main.js').bundle()
                .pipe(source('bundle.js'))
                .pipe(gulp.dest(dist))
});

В итоге, мы имеем 2 задачи:

  1. Копирование index.html в директорию admin на проде.
  2. Сборка bundle.js на основе main.js и отправка его в директорию admin на проде.

В качестве проверки делаем следующее:

  1. Приводим index.html к следующему виду: 
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    <h1>Hello World</h1>
    <script src="bundle.js"></script>
    </body>
    </html>
  2. Добавялем в main.js простой скрипт для плавного исчезновения заголовка h1. Окончательный вид main.js должен быть таким:
    const $ = require("jquery");
    
    $('h1').fadeOut('slow');
  3. Запускаем две команды в терминале: 
    gulp guild-js
    gulp copy-html

После этого должен собраться файл bundle.js и поместиться в директорю C:/OpenServer/domains/vue.loc/admin вместе с файлом index.html. Открываем страницу Index.html в директории admin и видим как заголовок исчезает.

Но если посомтреть исходный код и сам файл bundle.js то видно, что он громоздкий и сложно разобраться где какой модуль и где наш код подключен.

Поэтому можно для разработки сделать файлы раздельными, для этого прописываем в файле gulpfile.js для browserify такой параметр - {debug: true}.

return browserify('./app/src/main.js', {debug: true}).bundle()

В итоге, имеем уже такую структуру:

3. Установка babelify

Сам Babel нужен для трансормации js-кода новых стандартов в более старые для поддержки старыми браузерами, а babelify позволяет взаимодействовать Babel с gulp.

Документация Babel - ссылка.

Документация babelify - ссылка.

Установка через терминал для режима разработки:

npm install --save-dev babelify @babel/core @babel/preset-env

babelify установлен. Приводим задачу сборки bundle.js в файле gulpfile.js к следующему виду:

//Собирает js-файл из main.js, в котором мы пропишем директивы сбора, переименовывает его и помещает по указанному адресу
gulp.task("build-js", () => {
    return browserify('./app/src/main.js', {debug: true})
                .transform("babelify", {presets: ["@babel/preset-env"], sourceMaps: true})
                .bundle()
                .pipe(source('bundle.js'))
                .pipe(gulp.dest(dist))
});

Таким образом, прежде чем собираться, наш файл bundle.js к старому формату JavaScript для поддержки старыми браузерами.

4. Установка gulp scss. Работаем со стилями.

Компилирует scss в css

Документация - ссылка.

Запускаем в терминале следующую команду установки:

npm install gulp-sass --save-dev

Пакет установлен, далее, создаем директорию scss в директории src и добавляем файл style.scss. Архитектура приложения должна иметь следующий вид:

Добавляем в style.scss небольшое правило:

h1 {
  color: red;
}

Теперь добавим новую задачу для gulp в файле gukpfile.js также добавив константу с подключением gulp-sass в начале файла:

const gulp = require("gulp");
const source = require('vinyl-source-stream');
const browserify = require('browserify');
const sass = require('gulp-sass');

.../*Старый неизменный код*/...

gulp.task("build-sass", () => {
    return gulp.src('./app/scss/style.scss')
                .pipe(sass().on('error', sass.logError))
                .pipe(gulp.dest(dist));
});

Тестируем запуская поочередно:

gulp build-sass
gulp copy-html
gulp build-js

Все должно собраться и на странице админки должен пропадать уже красный заголовок

Доработка проекта

  1. Добавляем две директории в директорию app - api и assets;
  2. Дорабатываем gulpfile.js, чтобы он также копировал все файлы из директорий api и assets в проект. Добавляем такие задачи в файл:
    gulp.task("copy-api", () => {
        return gulp.src('./app/api/**/*.*')
                    .pipe(gulp.dest(dist + "/api"));
    });
    
    gulp.task("copy-assets", () => {
        return gulp.src('./app/assets/**/*.*')
            .pipe(gulp.dest(dist + "/assets"));
    });
  3. Добавляем в директорию api файл api.php и добавляем простой код для тестирования:
    <?php
    
    echo "Hello world!";
  4. Запускаем gulp copy-api и убеждаемся, что в основной проект в директорию admin/api скопировался файл api.php.

Автоматизируем gulp

Добавляем в конец файла gulpfile.js такой таск:

gulp.task("watch", () => {
    gulp.watch('./app/src/index.html', gulp.parallel('copy-html'));
});

В двух словах: когда будет изменяться файл index.html, будет запускаться метод parallel, который запусти copy-html и скопирует файл в проект.

Теперь, запускаем gulp watch и система будет отслеживать изменения в файле index.html и при сохранении файла копировать его в проект.

Делаем все тоже самое для остальных файлов проекта, добавляем в gulpfile.js следующие элементы для watch:

gulp.task("watch", () => {
    gulp.watch('./app/src/index.html', gulp.parallel('copy-html'));
    gulp.watch('./app/api/**/*.*', gulp.parallel('copy-api'));
    gulp.watch('./app/assets/**/*.*', gulp.parallel('copy-assets'));
    gulp.watch('./app/src/**/*.js', gulp.parallel('build-js'));
    gulp.watch('./app/scss/**/*.scss', gulp.parallel('build-sass'));
});

Примечание. Чтобы остановить слежение за файлами достаточно нажать ctrl + C.

Теперь делаем так, чтобы мы могли собрать все файлы одной командой build, добавляем в gulpfile.js следующее:

gulp.task("build", gulp.parallel('copy-html', 'copy-api', 'copy-assets', 'build-js', 'build-sass'));

Можно максимально автоматизировать формирование проекта на лету сделав так, чтобы проект билдился и вставал в режим слежки одной командой gulp. Добавляем в gulpfile.js следующее:

gulp.task("default", gulp.parallel("watch", "build"));

Теперь просто пишем в терминал gulp и можем спокойной работать с проектом. Тестируем, вносим изменения в разные файлы, все будет отражаться на реальном проекте.

На этом подготовка проекта и первоначальная настройка сборщика закончена!