В своих вопросах на форуме я уже неоднократно высказывал недовольство в адрес Laravel Elixir и Lavarel Mix, но эксперты Laravel настойчиво рекомендуют использовать именно эти инструменты. В первую очередь я критикую указаные выше инструменты за отсутствие гибкости и сложности в пользовательских настройках. Я думаю, этим инструментам не по зубам то, что я делаю спомощью gulp и webpack, но это лишь мои предположения и я могу ошибаться. В этой статье, я бы хотел вместе с опытными пользователями Laravel Mix сравнить данный инструмент с возможностями нативных gulp и webpack и узнать предел возможностей Laravel Mix.
Далее я приведу настройки, которые использую в своих Laravel-проектах на данный момент (я добавляю в корень проекта собственные package.json и webpack.config.js и далее устанавливаю нативные gulp и webpack). Я попрошу опытных пользователей Laravel Mix переписать эти настройки в инструкции для Laravel Mix, чтобы эффект от этих инструкций был такой же, как и от моих инструкций; либо открыто заявить, что это невозможно (только уточните, что именно и почему невозможно). Отсутствие реакции на данную просьбу длительное время тоже можно будет расценить как ответ «Laravel Mix это не по зубам...».
Я прекрасно понимаю, что многим лень переписывать эти настройки за бесплатно или просто нет на это времени, но опять же, это повышает вероятность того, что для Laravel Mix инструкции будут в лучшем случае не слишком проще, а в худшем — гораздо сложнее с внедрением в какие-то конфигурационные файлы Laravel.
Файл gulpfile.js
jsvar gulp = require('gulp'), pug = require('gulp-pug'), sass = require('gulp-sass'), browserSync = require('browser-sync'), cssnano = require('gulp-cssnano'), autoprefixer = require('gulp-autoprefixer'), rename = require('gulp-rename'), del = require('del'), imagemin = require('gulp-imagemin'), pngquant = require('imagemin-pngquant'), cache = require('gulp-cache'), runSequence = require('run-sequence'), shorthand = require('gulp-shorthand'); gulp.task('default', ['watch']); gulp.task('pug', function() { return gulp.src('resources/assets/pug/*.pug') .pipe(pug({ pretty: true, basedir: 'resources/assets/pug' })) .pipe(gulp.dest('resources/assets')) .pipe(browserSync.reload({stream: true})); }); gulp.task('sass', function(){ return gulp.src('resources/assets/sass/*.+(sass|scss)') .pipe(sass()) .pipe(autoprefixer(['last 15 versions', '> 1%', 'ie 8', 'ie 7'], { cascade: true })) .pipe(gulp.dest('resources/assets/css')) .pipe(browserSync.reload({stream: true})); }); gulp.task('browser-sync', function() { browserSync({ server: { baseDir: 'resources/assets' }, notify: false }); }); gulp.task('watch', ['browser-sync', 'pug', 'sass'], function() { gulp.watch('resources/assets/pug/**/*.pug', ['pug']); gulp.watch('resources/assets/sass/*.+(sass|scss)', ['sass']); gulp.watch('resources/assets/es6/*.js', browserSync.reload); }); // Продакшен gulp.task('Build production', function(){ runSequence( 'Clean previous production build', 'sass', 'Prepare CSS for production', 'Copy Fonts Folder To Production', 'Prepare images for production' ); }); gulp.task('Clean previous production build', function() { return del.sync(['public/css/*.css', 'public/img/**/*']); }); gulp.task('Prepare CSS for production', function(){ return gulp.src('resources/assets/css/*.css') .pipe(shorthand()) .pipe(cssnano()) .pipe(rename({suffix: '.min'})) .pipe(gulp.dest('public/css')); }); gulp.task('Copy Fonts Folder To Production', function(){ return gulp.src('resources/assets/fonts/**/*') .pipe(gulp.dest('public/fonts')); }); gulp.task('Prepare images for production', function() { return gulp.src('resources/assets/img/**/*') .pipe(cache(imagemin({ interlaced: true, progressive: true, svgoPlugins: [{removeViewBox: false}], use: [pngquant()] }))) .pipe(gulp.dest('public/img')); }); gulp.task('Clear cash', function () { return cache.clearAll(); });
В папке resources/assets/pug находятся файлы препроцессора pug, которые компилируются в .html и помещаются в resources/assets.
jsgulp.task('pug', function() { return gulp.src('resources/assets/pug/*.pug') .pipe(pug({ pretty: true, basedir: 'resources/assets/pug' })) .pipe(gulp.dest('resources/assets')) .pipe(browserSync.reload({stream: true})); });
gulp-таск по умолчанию после выполнения других тасков (в т. ч. pug и sass) открывает файл index.html. Это лишь вёрстка; превращение её в шаблоны blade — это уже следующий этап. Как сказал мастер constb в вопросе Настройка средств front-end разработки без использоваия elixir,
- Вполне можно разрабатывать на одной кодовой базе сразу и бэкенд и фронт
...с тех пор я увлёкся оптимизацией процесса разработки фронтэнда и бэкэнда на одной базе фреймворка Laravel.
* В папке resources/assets/sass находятся файлы расширения .scss, которые при development-сборке компилируются в resources/assets/css с добавлением вендорных префиксов, а при production-сборке — компилируются, минифицируются, оптимизируются (gulp-shorthand) и выкладываются в public/css:
jsgulp.task('sass', function(){ return gulp.src('resources/assets/sass/*.+(sass|scss)') .pipe(sass()) .pipe(autoprefixer(['last 15 versions', '> 1%', 'ie 8', 'ie 7'], { cascade: true })) .pipe(gulp.dest('resources/assets/css')) .pipe(browserSync.reload({stream: true})); }); gulp.task('Prepare CSS for production', function(){ return gulp.src('resources/assets/css/*.css') .pipe(shorthand()) .pipe(cssnano()) .pipe(rename({suffix: '.min'})) .pipe(gulp.dest('public/css')); });
* Таск Prepare images for production сжимает изображения и выкладывает их в public/img, а Copy Fonts Folder To Production просто копирует шрифты в public/fonts.
* Функция runSequence, которая используется в таске Build production, требует новейшие версии gulp.
Вообще gulp-таски не хорошо писать в несколько слов с пробелами, но я противник запоминания консольных комманд, а среда NetBeans позволяет запускать нужные таски без консоли, так что я могу отдавать предпочтение хотя и длинным, но понятным именам задач.
За всё, что связино с JavaScript, отвечает webpack. Исходники находится в папке es6.
webpack.config.js
jsconst NODE_ENV = process.env.NODE_ENV || 'development'; const webpack = require('webpack'); const output_path = NODE_ENV === 'production' ? (__dirname + '/public/js'): (__dirname + '/resources/assets/js'); module.exports = { context: __dirname + '/resources/assets/es6', entry: { top: './top.js', about: './about.js' }, output: { path: output_path, filename: '[name].js' }, watch: NODE_ENV === 'development', watchOptions: { aggregateTimeout: 100 }, devtool: NODE_ENV === 'development' ? 'cheap-inline-module-source-map' : false, resolve : { alias: { "jquery-ui": "jquery-ui-dist/jquery-ui.js" }, extensions: ['.js', '.jsx', '.json', '*'] }, module: { rules: [ { test: [ /\.jsx?$/ ], exclude: /node_modules/, use: [ 'babel-loader' ] } ] }, plugins: [ new webpack.ProvidePlugin({ jQuery: "jquery", $: "jquery" }) ] }; if (NODE_ENV === 'production') { module.exports.plugins.push( new webpack.optimize.UglifyJsPlugin({ beautify: false, mangle: { screw_ie8: true, keep_fnames: true }, compress: { screw_ie8: true }, comments: false }) ); }
* При development сборке es6 (но расширение тоже .js) конвертируется в JavaScript стандарта es5, происходит сборка модулей в файлы точек входа и они помещаются в /resources/assets/js
* При production-сборке происходит также минификация js-файлов, а затем они они отправляются в public/js.
На данный момент я пока запускаю gulp и webpack отдельно, потому что ещё не решил задачу интеграции gulp и свежей версии webpack, но работаю над этим. Если всё получится, то отдельный запуск webpack и файл webpack.config.js станут ненужными.
Комментарии (6)
почему в beautify нельзя сразу указать false?
Следут проверить выходной CSS на наличие ошибок, перед тем как отправлять его в продакшен. Для этого понадобятся средства валидации CSS, которые имеются в большинстве IDE для веб-разработки. Если Вы сразу всё сожмёте в одну строку, то даже если Вам подсветят ошибку в этой строке, то попробуйте её ещё найти, прежде чем исправить. Кроме того, выходной CSS нужно просматривать, когда по какой-то причине никак не применяются стили, прописанные Вами в SASS к нужным элементам — одной из причин может быть неправильно определённая вложенность, потому надо просмотреть, какой селектор был сгенерирован.
у вас код в конструкции выполняется только при NODE_ENV === production, в beautify всегда будет false
Прошу прощения, когда отвечал, торопился, и не внимательно прочитал, что Вы написали. Да, Вы правы, тут действительно условная конструкция не нужна. Исправил. Спасибо Вам за коррекцию.
Laravel это PHP фреймворк и разработка фронтенда не входит в его обязанности. Если вы фронтенд разработчик пользуйтесь чем вам угодно, Laravel вам ничего не должен. Mix призван лишь максимально облегчить и ускорить создание элементарного фронтенда, чтобы визуализировать результаты работы backend и не засорять мозг php программиста безудержно растущим зоопарком из фронтенда.
Насколько я знаю, то в документации написано, что вы не обязаны использовать Laravel Mix, вы свободны в действиях, хотите использовать иное, используйте. Laravel Mix это всего лишь надстройка над webpack.