lxdwords's avatar

Laravel elixir task sequencing

I'm using Laravel Elixir to compile SASS, merge scripts, compression and versioning CSS & JS files. At the end, I need to remove original files after versioning them, but it seems because of non-sequence task running, JS files in controller directory (after compression) are getting removed earlier than getting versioned. Here is my gulpfile.js codes:

const elixir = require('laravel-elixir');
const gulp   = require('gulp');
const uglify = require('gulp-uglify');
const del    = require('del');

const Task   = Elixir.Task;

elixir.config.sourcemaps = false;

elixir.extend('compress', function(folder, dest) {
    if (!dest) {
        dest = folder;
    }
    new Task('compress', function() {
        gulp.src(folder + '/**/*.js')
            .pipe(uglify())
            .pipe(gulp.dest(dest + '/'));
    })
    .watch(folder + '/**/*.js');
});

elixir.extend('delete', function(path) {
    new Task('delete', function() {
        return del(path);
    });
});

elixir((mix) => {
    mix.sass('app.scss', 'public/assets/css/app.min.css')
       .scripts([
           'app.js',
           'config.js',
       ], 'public/assets/js/app.min.js')
       .compress('resources/assets/js/controllers', 'public/assets/js/controllers')
       .version([
           'assets/css/app.min.css',
           'assets/js/controllers/*.js',
           'assets/js/app.min.js'
       ])
       .delete([
           'public/assets/css/app.min.css',
           'public/assets/js/controllers',
           'public/assets/js/app.min.js'
       ]);
});

I know that there are solutions using pure-gulp, but I'm looking for solving this through elixir itself. Any idea?

0 likes
17 replies
ejdelmonico's avatar

I am not sure what you are after here. Obviously, you already know that the elixir scripts method also minifies after concatenating. And, the elixir gulp --production minifies whatever you give it. So I can not understand why you are extending elixir with a compress method. With all you are trying to do, just make a regular gulpfile and forget about elixir.

lxdwords's avatar

@ejdelmonico

Well, I need my controller files to be separated not get combined, that's why I've written a custom task for that purpose, because I'm loading them in my Angular app through ocLazyLoader when I need each of them.

So you think there is no way to make sure "remove" task starts after "version"? Because after running gulp the "version" function can not find JS files located at controllers directory, because they are all removed before. There is no problem with the other JS file which is located outside.

Here is what happening there:

  1. resources/assets/sass/app.scss ==compile==> public/assets/css/app.min.css
  2. resources/assets/js/app.js + resources/assets/js/config.js ==combine==> public/assets/js/app.min.js
  3. resources/assets/js/controllers/* .js ==compress==> public/assets/js/controllers/* .js
  4. public/assets/... ==version==> public/build/assets/...

And at the end I need original asset files from step 4 to get removed, but the code doesn't work properly as I've described before.

ejdelmonico's avatar

The only way I can think of is too start a new elixir run after the first using just the custom remove. Maybe that will work by running after the first is completed.

lxdwords's avatar

@ejdelmonico

Thanks. I gave it a try in different ways but didn't work. It seems to be a core problem related to the way elixir groups and merges commands.

ejdelmonico's avatar

I think the basic issue is the same as when webpack causes issues...gulp runs piped processes in parallel so sometimes things do not finish before being pipped to other tasks. I suppose that maybe research how to make sure the other has finished before running the remove task.

ejdelmonico's avatar

Did you by any chance use the full

elixir((mix) => {
    mix.remove([
           'public/assets/css/app.min.css',
           'public/assets/js/controllers',
           'public/assets/js/app.min.js'
       ]);
});

as the second running? Doing it this way is supposed to sequence the processes.

lxdwords's avatar

@ejdelmonico

Yes i did. I also tried with separated instances by defining new variables. No success.

ejdelmonico's avatar

I have to ask....the code sample you originally posted does not contain a "remove" task....you have "delete". Which is correct?

lxdwords's avatar

@ejdelmonico

oh, i just forgot to fix that here. there at my code everything is fine... I'm going to fix the first post.

Well, i was thinking about modifying the main elixir codes at laravel-elixir package, but I was not sure how to include and use del package there.

ejdelmonico's avatar

Well I think it already includes the del package. Check VersionTask.js. What about using modifying that file to include your task. It's sloppy but it will probably work.

1 like
lxdwords's avatar

Thanks, I should take a look at that and see how it works.

Here is what I get when try to run gulp from my original code:

C:\xampp\htdocs\project>gulp --production
[23:34:21] Using gulpfile C:\xampp\htdocs\project\gulpfile.js
[23:34:21] Starting 'all'...
[23:34:21] Starting 'sass'...
[23:34:22] Finished 'sass' after 1.22 s
[23:34:22] Starting 'scripts'...
[23:34:23] Finished 'scripts' after 641 ms
[23:34:23] Starting 'compress'...
[23:34:23] Finished 'compress' after 1.56 ms
[23:34:23] Starting 'version'...
[23:34:23] Finished 'version' after 363 ms
[23:34:23] Starting 'delete'...
events.js:160
      throw er; // Unhandled 'error' event
      ^

Error: ENOENT: no such file or directory, stat 'C:\xampp\htdocs\project\public\assets\js\controllers\dataTables.js'
    at Error (native)

but when I remove "delete" function, everything works fine.

ejdelmonico's avatar

I think you should modify your task as well. Not sure if you tested whether or not it works on its own. Something like:

elixir.extend('delete', function(path) {
    new Task('delete', function() {
        return gulp.pipe(del([path]));
    });
});

Maybe worth a try.

lxdwords's avatar

@ejdelmonico

Thank you. Here is the result:

C:\xampp\htdocs\project>gulp --production
[00:07:28] Using gulpfile C:\xampp\htdocs\project\gulpfile.js
[00:07:28] Starting 'all'...
[00:07:28] Starting 'sass'...
[00:07:29] Finished 'sass' after 1.21 s
[00:07:29] Starting 'scripts'...
[00:07:29] Finished 'scripts' after 650 ms
[00:07:29] Starting 'compress'...
[00:07:29] Finished 'compress' after 1.86 ms
[00:07:29] Starting 'version'...
[00:07:30] Finished 'version' after 548 ms
[00:07:30] Starting 'delete'...
[00:07:30] 'delete' errored after 1.85 ms
[00:07:30] TypeError: gulp.pipe is not a function
    at Task.gulpTask (C:\xampp\htdocs\project\gulpfile.js:37:21)
    at Task.run (C:\xampp\htdocs\project\node_modules\laravel-elixir\dist\tasks\Task.js:139:31)
    at Gulp.<anonymous> (C:\xampp\htdocs\project\node_modules\laravel-elixir\dist\tasks\GulpBuilder.js:64:67)
    at module.exports (C:\xampp\htdocs\project\node_modules\orchestrator\lib\runTask.js:34:7)
    at Gulp.Orchestrator._runTask (C:\xampp\htdocs\project\node_modules\orchestrator\index.js:273:3)
    at Gulp.Orchestrator._runStep (C:\xampp\htdocs\project\node_modules\orchestrator\index.js:214:10)
    at Gulp.Orchestrator.start (C:\xampp\htdocs\project\node_modules\orchestrator\index.js:134:8)
    at runNextSet (C:\xampp\htdocs\project\node_modules\run-sequence\index.js:86:16)
    at Gulp.onTaskEnd (C:\xampp\htdocs\project\node_modules\run-sequence\index.js:75:5)
    at emitOne (events.js:101:20)
[00:07:30] 'all' errored after 2.42 s
[00:07:30] TypeError in plugin 'run-sequence(delete)'
Message:
    gulp.pipe is not a function
Stack:
TypeError: gulp.pipe is not a function
    at Task.gulpTask (C:\xampp\htdocs\project\gulpfile.js:37:21)
    at Task.run (C:\xampp\htdocs\project\node_modules\laravel-elixir\dist\tasks\Task.js:139:31)
    at Gulp.<anonymous> (C:\xampp\htdocs\project\node_modules\laravel-elixir\dist\tasks\GulpBuilder.js:64:67)
    at module.exports (C:\xampp\htdocs\project\node_modules\orchestrator\lib\runTask.js:34:7)
    at Gulp.Orchestrator._runTask (C:\xampp\htdocs\project\node_modules\orchestrator\index.js:273:3)
    at Gulp.Orchestrator._runStep (C:\xampp\htdocs\project\node_modules\orchestrator\index.js:214:10)
    at Gulp.Orchestrator.start (C:\xampp\htdocs\project\node_modules\orchestrator\index.js:134:8)
    at runNextSet (C:\xampp\htdocs\project\node_modules\run-sequence\index.js:86:16)
    at Gulp.onTaskEnd (C:\xampp\htdocs\project\node_modules\run-sequence\index.js:75:5)
    at emitOne (events.js:101:20)
(node:22396) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): TypeError: glob pattern string required
ejdelmonico's avatar

It probably needs the src so try gulp.src(path).pipe(del([path]));

lxdwords's avatar

@ejdelmonico

didn't help unfortunately. I just was reading codes at VersionTask.js and I think I can duplicate the deleteManifestFiles function there and do a few modifications, then it would be able to find and delete source files. The only problem is that I can not put this function at the end of gulpTask function, because gulpTask is running per file and deleteManifestFiles is running once for all.

ejdelmonico's avatar

There are some hooks that I thought I saw in a few files for when something is finished. You might be able to tap into them. Also, I think you should test you task extension to make sure it works by itself. Rule out that being an issue before you modify elixir code. Cause we all know the difficulties of updating when you do such a thing.

marco.sgorbati's avatar

@lxdwords

Here's my solution, that works fine for me after a version task

const Task  = Elixir.Task;
var through = require('through2');

elixir.extend('delete', function(path) {
    new Task('delete', function() {
        return gulp.src('').pipe(through.obj(function (file, enc, cb) {
            del(path);
            cb(null, file);
        }));
    });
});

Please or to participate in this conversation.