Создание и использование Source Maps для css и js в GULP 4

Хотелось бы в двух словах рассказать, как настроить Source Maps для GULP 4, но не получится вырвать из контекста просто пару строк кода, поэтому разобью статью на 2 части. Первая будет с базовым кодом для Source Maps, а во второй части будет куча кода из рабочего проекта.

Source Maps нужны для проектов, где происходит сборка нескольких файлов в один, например, компиляция файлов scss в один файл main.min.css или конкатенация js-файлов в один scripts.min.js. Карты источников нужны для того, чтобы быстро вносить правки, и не искать в каком файле задано определенное правило или функция, особенно когда для сборки используются десятки файлов или различных библиотек.

Так будет выглядеть в инспекторе код без Source Maps:

Так будет выглядеть код с использованием Source Maps:

И по итогу, если нам нужно увеличить отступ снизу у элемента .icon, то нам не нужно искать по всем файлам scss где задано это правило, а с помощью карты источников видим, что данное правило указано в файле _general.scss на 44 строке.

Если вам это не нужно, то дальше можно не читать.

1. Базовый пример вывода Source Maps для js-файла

var gulp = require('gulp');
var plugin1 = require('gulp-plugin1');
var plugin2 = require('gulp-plugin2');
var sourcemaps = require('gulp-sourcemaps');
 
gulp.task('javascript', function() {
  gulp.src('src/**/*.js')
    .pipe(sourcemaps.init())
      .pipe(plugin1())
      .pipe(plugin2())
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('dist'));
});

Где — plugin1() и plugin2() — это какие-то образные плагины, которые занимаются минификацией и конкатенацией js-файлов, например.

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

2. Кастомизированный пример подключения Source Maps в js-файлах и в css-файлах

Используемые пакеты:

var syntax       = 'scss',
    gulp         = require('gulp'),
    sass         = require('gulp-sass'),
    cleancss     = require('gulp-clean-css'),
    autoprefixer = require('gulp-autoprefixer'),
    concat       = require('gulp-concat'),
    uglify       = require('gulp-uglify'),
    rename       = require('gulp-rename'),
    sourcemaps   = require('gulp-sourcemaps'),
    notify       = require('gulp-notify'),

Задача для компиляции файла main.min.css с Source Maps

// Compile .scss to *.min.css
gulp.task('styles', function() {
  return gulp.src('app/'+syntax+'/**/*.'+syntax+'') // берем все файлы scss
  .pipe(sourcemaps.init()) // инициализируем создание Source Maps
  .pipe(sass({ outputStyle: 'compressed' }).on("error", notify.onError())) // компилируем сжатый файл .css
  .pipe(rename({ suffix: '.min', prefix : '' })) // переименовываем файл в .min.css
  .pipe(autoprefixer(['last 15 versions'])) // добавляем вендорные префиксы
  .pipe(cleancss( {level: { 1: { specialComments: 0 } } })) // удаляем все комментарии из кода
  .pipe(sourcemaps.write()) // пути для записи SourceMaps - в данном случае карта SourceMaps будет добавлена прям в данный файл main.min.css в самом конце
  .pipe(gulp.dest('app/css')) // перемещение скомпилированного файла main.min.css в папку app/css
});

Задача для конкатенации файла scripts.min.js с Source Maps

// Concatenate all .js from /libs/ to libs.min.js
gulp.task('scripts', function() {
  return gulp.src([
    'app/libs/jquery/dist/jquery.min.js', // указываем пути всех подключаемых библиотек и файлов JS
    'app/js/common.js', // основной файл функций подключаем в самом конце 
  ])
  .pipe(sourcemaps.init()) // инициализируем создание Source Maps
  .pipe(concat('scripts.min.js')) // объединяем все вышеперечисленные файлы в один scripts.min.js
  .pipe(uglify()) // минифицируем и удаляем комментарии из файла scripts.min.js
  .pipe(sourcemaps.write()) // пути для записи SourceMaps - в данном случае карта SourceMaps будет добавлена прям в данный файл scripts.min.js в самом конце в формате комментария
  .pipe(gulp.dest('app/js')) // перемещаем полученный файл scripts.min.js в директорию app/js
});

Все классно, но есть одна проблема.

sourcemaps.write() — не указаны пути для файла *.map, значит карта источников будет записана внутри файла в самый конец, тем самым увеличивая вес файлов более чем в два раза. Это не круто, но зато карты источников будут работать и в Chrome, и в Firefox.
sourcemaps.write('.') — в таком формате source map запишется отдельным файлом в той же папке, что и основной файл, в формате main.min.css.map и scripts.min.js.map.

Проблема с лишним содержимым в виде карты путей решаема.

Source Maps нужны нам только во время разработки, поэтому при билде продашена просто удалим все комментарии из файлов .css и .js — а карта источников записана именно в виде комментария.

Это часть кода из моей таски ‘build’:

var buildCss = gulp.src('app/css/**/*.css')
  .pipe(cleancss( {level: { 1: { specialComments: 0 } } })) // удаляем все комментарии из css
  .pipe(gulp.dest('dist/css')); // отправляем полученный файл на продакшен
 
var buildJs = gulp.src('app/js/**/*.js')
  .pipe(uglify()) // удаляем все комментарии из js
  .pipe(gulp.dest('dist/js')); // отправляем полученный файл на продакшен

По итогу, на продакшене будут чистые минифицированные файлы без лишнего кода и комментариев.

Создание спрайтов в GULP 4 с поддержкой Retina

Для оптимизации запросов на сервер можно объединить иконки и небольшие картинки, которые используются в css,…

Как оптимизировать и максимально сжать изображения в GULP 4 с помощью gulp-imagemin

В общем, перепробовал десятки разных плагинов и настроек, но .jpg совсем не оптимизировались, а иногда…

Бесконечный анимированный фон с эффектом параллакса

Бесконечный анимированный фон с эффектом параллакса создан на основе варианта 2 из этой статьи HTML…

Изменение внешнего вида чекбоксов и радио-кнопок с помощью CSS

Изменение внешнего вида для чекбокса с помощью CSS HTML для чекбокса или радио-кнопок CSS для…

Ответить