В этом посте я буду держать конфиг gulp, который использую в текущий момент. Т.е. по мере улучшения, конфиг будет меняться.
Конфиг рассчитан на использование SCSS (или SASS) и Vue.js. Однако, если вы хотите просто упаковать скрипты и стили, он тоже должен сработать.
TLDR
Итак, в корне проекта создаем файл gulpfile.js
:
/**
* Example of gulp configuration
* @link https://github.com/13DaGGeR/gulpfile-example
* @version 0.1.2
*/
const css_syntax = 'scss', // sass|scss
source_dir = 'src/', // must contain js and (sass or scss) directories
destination_dir = 'public/'; // will receive result files in js and css subdirectories respectively
const gulp = require('gulp'),
sass = require('gulp-sass'), // to preprocess scss and sass
path = require('path'), // to resolve absolute paths
glob = require('glob'), // to find files by mask
sourcemaps = require('gulp-sourcemaps'), // to generate .map files
log = require('fancy-log'), // to show our logs in gulp's format
webpack = require('webpack'),
uglifyJsPlugin = require('uglifyjs-webpack-plugin'), // to minify js
postcss = require('gulp-postcss'), // for most css needs, uses packages below
autoprefixer = require('autoprefixer'), // for browser compatibility
atImport = require('postcss-import'), // for @import usage
cssnano = require('cssnano') // to minify css
;
const {VueLoaderPlugin} = require('vue-loader');
function dev_styles() {
let processors = [
atImport,
autoprefixer({browsers: ['last 15 version']}),
];
return gulp.src(source_dir + css_syntax + '/*.' + css_syntax)
.pipe(sass({outputStyle: 'expand'}))
.pipe(postcss(processors))
.pipe(gulp.dest(destination_dir + 'css'))
}
function prod_styles() {
let processors = [
atImport,
autoprefixer({browsers: ['last 15 version']}),
cssnano
];
return gulp.src(source_dir + css_syntax + '/*.' + css_syntax)
.pipe(sourcemaps.init())
.pipe(sass({outputStyle: 'expand'}))
.pipe(postcss(processors))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(destination_dir + 'css'))
}
function webpackTask(is_dev) {
log('webpack started');
let postCssLoader = {
loader: 'postcss-loader',
options: {
plugins: function () {
let modules = [
autoprefixer({browsers: ['last 15 version']})
];
if (!is_dev) {
modules.push(cssnano);
}
return modules;
}
}
};
let config = {
watch: !!is_dev,
mode: is_dev ? 'development' : 'production',
entry: glob.sync(source_dir + '/js/*.js').reduce((acc, cur) => {
acc[path.basename(cur, '.js')] = path.resolve(cur);
return acc
}, {}),
output: {
path: path.resolve(destination_dir + 'js'),
publicPath: '/js/',
filename: '[name].js'
},
module: {
rules: [
{test: /\.css$/, use: ['vue-style-loader', 'css-loader', postCssLoader],},
{test: /\.scss$/, use: ['vue-style-loader', 'css-loader', 'sass-loader', postCssLoader],},
{test: /\.sass$/, use: ['vue-style-loader', 'css-loader', 'sass-loader?indentedSyntax', postCssLoader],},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
'scss': ['vue-style-loader', 'css-loader', 'sass-loader', postCssLoader],
'sass': ['vue-style-loader', 'css-loader', 'sass-loader?indentedSyntax', postCssLoader]
}
}
},
{test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/}
]
},
resolve: {alias: {vue$: 'vue/dist/vue.min.js'}, extensions: ['*', '.js', '.vue', '.json']},
plugins: [
new VueLoaderPlugin()
]
};
if (!is_dev) {
config.devtool = 'source-map';
}
return webpack(config, (err, stats) => {
let hasError = !!err;
if (!err && stats.compilation.errors.length) {
err = stats.compilation.errors;
hasError = true
}
if (hasError) {
log.error('ERROR:', err);
} else {
log('webpack finished');
}
});
}
exports.default = function () {
webpackTask();
return prod_styles();
};
exports.dev = function () {
dev_styles();
gulp.watch(source_dir + css_syntax + '/**/*.' + css_syntax, dev_styles);
webpackTask(1);
};
Необходимые пакеты:
yarn add -D gulp gulp-sass gulp-sourcemaps webpack uglifyjs-webpack-plugin gulp-postcss autoprefixer postcss-import cssnano vue-loader vue-template-compiler @babel/core babel-loader sass-loader css-loader postcss-loader vue
Запуск
Текущий конфиг предполагает 2 варианта запуска:
gulp dev
-- быстро компилирует при изменениях файлов, нужен для отладки стилей/скриптовgulp
-- минифицирует и создает сорсмапы, отрабатывает один раз и сравнительно медленно. Предполагается запустить один раз перед последним тестированием перед коммитом.
Оба варианта запускаются в консоли в корневой директории проекта, либо используя пресет из IDE (ex. PhpStorm)
Мотивация
Теперь разберем, что используется и зачем.
- Зачем вообще обрабатывать стили и скрипты? -- вы когда либо приходили к мысли "о, клевая штука, жаль, поддерживается только современными браузерами", или "почему css каскадный но в исходниках нельзя использовать наследование", или "опять забыл приписать -webkit- и все поехало на %некий_браузер%"? Вот как раз, чтобы избавить себя от таких проблем, разработчики автоматизировали обработку исходников, и обернули все это в относительно удобные инструменты. Нам остается только подключить, использовать и радоваться жизни. Хвала опенсорсу!
Кроме описанных задач, мы решим задачу минификации и упаковки файлов, что приведет нас к ускорению загрузки страниц. - Что мы получим при использовании этого конфига -- по одному файлу скрипта и стиля на каждую точку входа.
- Что понимается под точкой входа -- файл scss или js, содержащий import-ы необходимых нам библиотек и созданных нами файлов.
- gulp.js -- это потоковая система сборки. Потоковая означает, что обрабатываемые ресурсы рассматриваются как поток данных, а-ля пайпы в linux. Мы указываем источник(-и), набор преобразований, и результирующий файл(-ы).
- scss / sass -- "Syntactically awesome style sheets", эдакие css на стероидах. Кратко: позволяет использовать принципы хорошего кода в css. Нужны переменные -- есть, инкапсуляция -- в разумных пределах. Субъективно всегда предпочитал синтаксис другого предпроцессора: less, но т.к. плотно использую twitter bootstrap, особого смысла в зоопарке не увидел и перешел на scss.
- webpack -- упаковщик js. Изначально создан для того, чтобы сделать из кучи файлов js один большой. Из коробки поддерживает sourcemap-ы, используем
uglifyjs-webpack-plugin
для минификации иbabel-loader
для транслитерации современного js-а в js твоего дедушки (в исходниках используем стрелочные функции, но код работает в ie7). - postcss -- фреймворк для работы с css. В нашем случае использует
autoprefixer
(для, очевидно, автоматической простановки всяких там -moz- и -webkit-),postcss-import
для упаковки множества файлов в один иcssnano
для минификации css. - Почему не делать все на модулях gulp -- на момент написания конфига модули gulp-а постигла участь npm -- сотни дублирующих пакетов, часто заменяющих друг друга, часто несовместимых друг с другом.
webpack
я подключил, когда не нашел адекватного решения упаковки файлов, при условии использования нативного синтаксиса подключения файлов в js.post-css
-- потому что на данный момент нельзя с помощьюgulp
одновременно упаковать файлы и сгенерировать сорсмапы. Вполне возможно, что все таки можно, но тратить время на танцы с бубном мне не хочется. - Почему не делать все через webpack -- webpack не предполагает схему работы вообще без js. Предложенный конфиг можно использовать для подготовки стилей как классического backend-heavy приложения так и для SPA на vue.js.
- Почему не используется пакет webpack для gulp -- при такой схеме webpack будет запускаться после каждого обновления скриптов, это долго. В предложенной мной схеме webpack запускается единожды при запуске gulp и сам следит за изменениями файлов. Так зачем же тут gulp -- чтобы не плодить много конфигов в корне проекта.