В своих вопросах на форуме я уже неоднократно высказывал недовольство в адрес **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 == %%(js) var 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**. %%(js) 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-таск** по умолчанию после выполнения других тасков (в т. ч. **pug** и **sass**) открывает файл **index.html**. Это лишь вёрстка; превращение её в шаблоны blade - это уже следующий этап. Как сказал мастер **constb** в вопросе ((https://laravel.ru/forum/viewtopic.php?id=2455 Настройка средств front-end разработки без использоваия elixir)), > Вполне можно разрабатывать на одной кодовой базе сразу и бэкенд и фронт ...с тех пор я увлёкся оптимизацией процесса разработки фронтэнда и бэкэнда на одной базе фреймворка Laravel. * В папке **resources/assets/sass** находятся файлы расширения **.scss**, которые при development-сборке компилируются в **resources/assets/css** с добавлением вендорных префиксов, а при **production-сборке** - компилируются, минифицируются, оптимизируются (**gulp-shorthand**) и выкладываются в **public/css**: %%(js) 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('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 == %%(js) const 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** станут ненужными.