Может войдёшь?
Черновики Написать статью Профиль

Предел возможностей Laravel Mix

В своих вопросах на форуме я уже неоднократно высказывал недовольство в адрес 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,

  1. Вполне можно разрабатывать на одной кодовой базе сразу и бэкенд и фронт

...с тех пор я увлёкся оптимизацией процесса разработки фронтэнда и бэкэнда на одной базе фреймворка 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 станут ненужными.

Как вы считаете, полезен ли этот материал? Да Нет

Комментарии (4)

xardch

Image alt

почему в beautify нельзя сразу указать false?

Gleb2708

Следут проверить выходной CSS на наличие ошибок, перед тем как отправлять его в продакшен. Для этого понадобятся средства валидации CSS, которые имеются в большинстве IDE для веб-разработки. Если Вы сразу всё сожмёте в одну строку, то даже если Вам подсветят ошибку в этой строке, то попробуйте её ещё найти, прежде чем исправить. Кроме того, выходной CSS нужно просматривать, когда по какой-то причине никак не применяются стили, прописанные Вами в SASS к нужным элементам — одной из причин может быть неправильно определённая вложенность, потому надо просмотреть, какой селектор был сгенерирован.

xardch

у вас код в конструкции выполняется только при NODE_ENV === production, в beautify всегда будет false

Gleb2708

Прошу прощения, когда отвечал, торопился, и не внимательно прочитал, что Вы написали. Да, Вы правы, тут действительно условная конструкция не нужна. Исправил. Спасибо Вам за коррекцию.

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.