На прошлой неделе я обсуждал, как настроить Node.js и Gulp в Visual Studio 2015 . Во время этого обсуждения я упомянул, что я использую Gulp для объединения, минимизации и кеширования моих файлов HTML, CSS и JavaScript.
На этой неделе я собираюсь рассказать вам, как именно я это делаю.
Итак, если у вас еще не установлены Node.js и Gulp, вы можете вернуться и прочитать статью, которую я написал на прошлой неделе.
Поскольку большинство людей, читающих этот блог, являются разработчиками ASP.NET, на этом пути может быть несколько конкретных советов .NET. Но файл Gulp, который я собираюсь показать вам, не зависит от технологий. Так что, если вы используете какую-то другую технологию, вы все равно выиграете от этой статьи.
Пакетирование
Первое, что мы хотим сделать, это объединить все наши файлы CSS и файлы JavaScript в один файл для CSS и один файл для JavaScript. Есть несколько способов, которыми вы могли бы сделать это, но я хотел, чтобы был какой-то способ, который позволил бы мне работать без привязки во время разработки и связываться, когда я выпускал код. Поскольку я работаю с одностраничным приложением (SPA), это было простой задачей: настроить файл по умолчанию на index.debug.html для разработки и index.release.html и использовать преобразования web.config, чтобы указать, какие из них должны быть используется в какой среде. Если вы работаете в какой-то другой среде, я уверен, что у вас есть какой-то аналогичный способ указания файла по умолчанию на основе настроек среды.
Итак, вся моя работа по разработке будет выполнена в index.debug.html.
Как я уже сказал, существует много способов объединения JavaScript и CSS-кода, но я обнаружил, что, как мне кажется, требуется наименьшее количество работы, это использование модуля gulp-useref . Этот модуль позволяет нам помещать токены в наш HTML-файл, которые указывают, какие файлы мы хотим сжать и каким должно быть полученное имя файла.
Ваш HTML-файл будет выглядеть примерно так:
<html>
<head>
<!-- build:css css/combined.css -->
<link href="css/one.css" rel="stylesheet">
<link href="css/two.css" rel="stylesheet">
<!-- endbuild -->
</head>
<body>
<!-- other normal content goes here -->
<!-- build:js scripts/combined.js -->
<script type="text/javascript"
src="scripts/one.js"></script>
<script type="text/javascript"
src="scripts/two.js"></script>
<!-- endbuild -->
</body>
</html>
Useref видит токен сборки и создает файл CSS с именем комбинированный.css и файл JavaScript с именем комбинированный.js и изменяет выходной HTML-код так, чтобы он выглядел следующим образом:
<html>
<head>
<link rel="stylesheet" href="css/combined.css"/>
</head>
<body>
<script src="scripts/combined.js"></script>
</body>
</html>
Чтобы использовать эту функцию в своем файле Gulp, установите его с помощью NPM:
npm install gulp-useref --save-dev
Убедитесь, что вы запускаете NPM в каталоге, в котором находится файл gulpfile.js.
В своем файле Gulp вы добавите следующий код:
var gulp = require('gulp');
var useref = require('gulp-useref');
gulp.task('useRef', [],function() {
return gulp.src('index.debug.html')
.pipe(useref())
.pipe(gulp.dest('index'));
});
Конечным результатом является то, что в подкаталоге с именем index появится новый файл index.debug.html вместе с новыми файлами css / комбинированный.css и scripts / комбинированный.js.
Условная обработка
Одна из многих вещей, которые мне нравятся в Gulp, это то, что он основан на потоке. То есть мне не нужно записывать файлы в каталог до тех пор, пока я не захочу — в отличие от Grunt (другого популярного инструмента для обработки файлов Node.js), где все целиком основано на файлах.
Однако, поскольку у меня есть три разных типа файлов, полученных в предыдущем процессе, и я хочу сжать каждый из файлов, мне потребуется какой-то способ условной обработки файлов, выходящих из useref.
Для этого нам нужен gulp-if .
Вы можете установить gulp-if, используя NPM, используя следующую команду:
npm install gulp-if --save-dev
Основное использование gulp-if выглядит следующим образом:
var gulpif = require('gulp-if');
gulpif (/ * условие файла здесь * /,
/ * следующий процесс потока идет сюда * /);
Сократить JavaScript
Следующее, что мы хотим сделать, это минимизировать полученный объединенный файл JavaScript. Есть несколько, которые вы могли бы использовать. Тот, на котором я остановился, — глоток-угорь .
Установите gulp-uglify, используя:
npm install gulp-uglify --save-dev
Итак, объединяя это с gulp-if, использование будет выглядеть так:
var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');
... other code here
.pipe(gulpif('*.js', uglify()));
Это просто общая суть. Мы соберем все это вместе в нескольких параграфах.
Минимизировать CSS
Чтобы минимизировать CSS, я решил использовать gulp-cssnano .
Установите gulp-cssnano, используя:
npm install gulp-cssnano --save-dev
И используйте его в нашем коде так:
var cssnano = require('gulp-cssnano');
var gulpif = require('gulp-if');
... code here ...
.pipe(gulpif('*.css', uglify()));
Файлы карт
После того, как все наши файлы будут минимизированы, мы захотим увидеть оригинальный исходный код, даже если у вас есть минимизированный файл, который использует сайт. Я не буду вдаваться в подробности о том, что такое файл карты или что он здесь делает. Но если у вас есть проблема на рабочем сервере, вы захотите, чтобы, по крайней мере, были доступны файлы карт, чтобы вы могли отследить проблему.
Чтобы создать файл карты, вам нужно использовать gulp-sourcemaps .
Установить с помощью:
npm install gulp-sourcemaps --save-dev
Я покажу вам, как это все подключается в ближайшее время.
Еще один пакет
Да, хотите верьте, хотите нет, нам нужен еще один пакет, чтобы все это работало.
Видите ли, чтобы заставить minify работать с useref, нам нужно установить модуль lazypipe . Который вы можете установить используя:
npm install lazypipe --save-dev
Собираем все вместе
И вот теперь, наконец, мы можем собрать все это в один большой сценарий.
var gulp = require('gulp');
var useref = require('gulp-useref');
var uglify = require('gulp-uglify');
var cssnano = require('gulp-cssnano');
var lazypipe = require('lazypipe');
var sourcemaps = require('gulp-sourcemaps');
var gulpif = require('gulp-if');
// compressTasks is a sub process used by useRef (below)
// that compresses (takes out white space etc) the
// javascript and css files
var compressTasks = lazypipe()
.pipe(sourcemaps.init, { loadMaps: true })
.pipe(function () { return gulpif('*.js', uglify()); })
.pipe(function() {
return gulpif('*.css', cssnano({
zindex: false }));
});
// useRef looks at markers in index.debug.html and
// combines all of the files into one file. once the
// files are combined the compressTasks process
// is called and then the files are all written out to
// the index directory.
gulp.task('useRef', [],function() {
return gulp.src('index.debug.html')
.pipe(useref({},
lazypipe()
.pipe(compressTasks)
))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('index'));
});
Сжатие файла HTML
Итак, как говорится в комментариях, и, как я уже говорил, все это помещается в каталог index. Далее мы хотим сжать файл HTML и переместить index.debug.html обратно в корневой каталог с именем index.release.html, а затем поместить файл CSS и файл JavaScript в соответствующие каталоги, свисающие с корень.
Чтобы сжать HTML-файл, вы можете использовать модуль NPM gulp-htmlmin , который вы можете установить с помощью:
npm install gulp-htmlmin --save-dev
И, код:
var htmlmin = require('gulp-htmlmin');
// minIndex takes all of the whitespace out of the
// main index file
gulp.task('minIndex', ['useRef'], function() {
return gulp.src('index/index.debug.html')
.pipe(htmlmin({ collapseWhitespace: true,
removeComments: true }))
.pipe(gulp.dest('index'));
});
Переименовать индексный файл
Для переименования файла мы используем gulp-rename
npm install gulp-rename --save-dev
И, следующий код:
var gulpRename = require('gulp-rename');
// renameIndex renames the index file and puts it
// in the root directory
gulp.task('renameIndex', ['minIndex'], function () {
return gulp.src('index/index.debug.html')
.pipe(gulpRename('index/index.release.html'))
.pipe(gulp.dest('.'));
});
Это переименовывает файл и помещает его в корневой каталог.
Перемещение файлов
Далее нам нужно вернуть файлы, которые находятся в нашем каталоге index, в каталоги, в которые они входят. Для этого мы используем встроенную команду узла gulp.dest ().
gulp.task('copyJs', ['useRef'], function () {
// copy the js and map files generated from useref to
// the real app directory
return gulp.src('index/app/*.*')
.pipe(gulp.dest('app'));
});
gulp.task('copyCss', ['useRef'], function () {
// copy the css and map files generated from useref to
// the real css directory
return gulp.src('index/css/*.*')
.pipe(gulp.dest('css'));
});
Очистки кэша
Одна из давних проблем использования страниц CSS и JavaScript на нашем сайте заключается в том, что когда мы размещаем новые версии, у нас нет возможности сообщить браузеру, что мы просто добавляем новый файл, если мы не изменим имя файла. Хитрость заключается в том, чтобы файл выглядел как новый файл. Обычно это делается путем помещения параметра запроса в конец.
Еще раз, есть несколько решений этой проблемы, доступных для Gulp, но тот, который мне нравится больше всего, читает файл и генерирует для него хеш-строку, добавляя ее в качестве строки запроса. Это делает файл уникальным, но браузер загружает его только в том случае, если он действительно другой.
Чтобы реализовать очистку кеша, вам нужно установить gulp-cache-bust :
npm install gulp-cache-bust --save-dev
И последний кусочек кода, который заставит все это работать:
var cacheBuster = require('gulp-cache-bust');
// cacheBuster looks at the css and js files and appends a hash to the
// request to cause the file to get reloaded when the file changes.
gulp.task('cacheBuster', ['copyCss', 'copyJs', 'renameIndex'], function () {
return gulp.src('index/index.release.html')
.pipe(cacheBuster())
.pipe(gulp.dest('.'));
});
Улучшения
Если вы хотите пойти на неприятности, вы можете создать это как один большой сценарий, который никогда не помещал файлы в каталог index. Но я обнаружил, что файлы, записанные в промежуточный каталог, полезны для целей отладки.
Финальный код
Вы можете получить полный скрипт Gulp от GitHub .