jmreidy/grunt-browserify

Watching sass and browserify js files at the same time

Opened this issue · 6 comments

dsge commented

How can I watch sass files with grunt-browserify and grunt-contrib-watch at the same time?

I tried setting browserify's keepAlive to false but that disables browserify's watch option too.

Running the browserify task with grunt-contrib-watch is not really an option because my bundle is too big for that. I tried a workaround by splitting it into 2 bundles but that isn't a real solution.

Compiling sass in an IDE is not really an option because we have way too many collaborators to make sure that everyone uses the same config for compiling.

If I remove the comment from //'watch' then browserify:frontend_bundle_watch never runs. Moving watch down does not help either.

Using grunt-concurrent makes both of them run once but none of them actually responds to changed files.

Versions:

$ npm list -i --depth=0

├── angular@1.4.8
├── angular-ui-bootstrap@1.0.3
├── bootstrap-sass@3.3.6
├── browserify-ng-html2js@1.1.5
├── console-polyfill@0.2.2
├── font-awesome@4.5.0
├── grunt@0.4.5
├── grunt-browserify@4.0.1
├── grunt-concurrent@2.1.0
├── grunt-contrib-copy@0.8.2
├── grunt-contrib-uglify@0.11.0
├── grunt-contrib-watch@0.6.1
├── grunt-ng-annotate@1.0.1
├── grunt-sass@1.1.0
├── load-grunt-tasks@3.4.0
└── node.normalize.scss@3.0.3

Gruntfile (removed potentially irrelevant lines)

module.exports = function(grunt) {
    require('load-grunt-tasks')(grunt);
    /* ... folder variables ... */
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        browserify: {
          options: {
                "watch": true,
                "keepAlive": true,
          },
          frontend_bundle_watch: {
            src: frontendAppFolder + "/frontend.js",
            dest: compiledFolder + "/app.js",
          },
        },
        /* ... */
        sass: {
            options: {
                sourceMap: false,
                includePaths: [vendorFolder],
            },
            site_frontend: {
                options: {
                    outputStyle: 'nested',
                },
                src: frontendAppFolder+'/frontend.scss',
                dest: compiledFolder+"/app.css"
            }
        },
        watch: {
            options: {
                spawn: false,
                debounceDelay: 100
            },
            sass_frontend: {
                files: frontendAppFolder+"/**/scss/**/*.scss",
                tasks: ['sass:site_frontend'],
            }
        }
});
/* ... */
var buildTasks = [
        'browserify:frontend_bundle_watch',
        'sass:site_frontend',
        /* ... */
];
grunt.registerTask('default', buildTasks.concat([ 
        //'watch',
        'browserify:frontend_bundle_watch',
]));

Hello

Parts of my config:

# order is important
grunt.registerTask 'default', ['browserify:dev', 'less:dev', 'connect', 'watch']

grunt.initConfig {
  # ...
  # dev static server with livereload
  connect:
    dev:
      options:
        # no keepalive!
        debug     : false
        port      : 9000
        hostname  : '*'
        livereload: true
        base      : ['.', 'dist']

  watch:
    options:
      atBegin   : false
      livereload: true
    less:
      options:
        livereload: false # no reload page after update
        interrupt : true
      files: ['src/**/*.less']
      tasks: ['less:dev']
    css: # for hotreload styles
      files: ['dist/styles.css']
      tasks: []
      spawn: false
    js: # for autoreload page
      files: ['dist/*.js']
      tasks: []
    # ...

  browserify:
    dev:
      options:
        # ...
        # no keepalive!
        watch: true
      files:
        'dist/lib.js': ['src/lib.coffee']
        'dist/app.js': ['src/app.coffee']

  less:
    dev:
      files:
        'dist/styles.css': ['src/**/*.less', '!src/less/import/**/*.less']
}

@ovcharik does your console output when a file is built include the text Watchifying...? If your output is just Bundle foo/bar.js created. then it's not running with watchify (which should be considerably faster).

Running the browserify task with grunt-contrib-watch is not really an option because my bundle is too big for that.

I believe @dsge is trying to get it to run with watchify. I'm also looking for a solution as my build is a little slower than I'd like it to be but I need to run grunt-contrib-watch for other assets.

@wesvetter this solution for combining watchify and grunt-contrib-watch.

From documentation:

watch

Type: Boolean If true, invoke watchify instead of browserify.

For watchify to work properly, you have to keep the process running. The option keepAlive can help you do that, or you can use another grunt-watch task.

I'm turn on watch option for browserify task and turn off keepAlive, because watch task will keep process.

While browserify may be running, unless you see the text Watchifying... in your output, it is not running with watchify (just browserify).

If you don't see it that's likely because there is an issue where watchify doesn't run unless keepAlive is set. See #345, #352

Option watch determines that will be used watchify vs browserify.

https://github.com/jmreidy/grunt-browserify/blob/master/lib/runner.js#L33

//determine watchify or browserify
var b = options.watch ? this.watchify(this.browserify(bOpts), wOpts) : this.browserify(bOpts);

Although option keepAlive affects display Watchifying... in console, but it does not affect the choice between browserify and watchify. With keepAlive callback of the task not happening, without option it called once. This is the only important difference.

https://github.com/jmreidy/grunt-browserify/blob/master/lib/runner.js#L161

self.logger.log.ok('Bundle ' + destination.cyan + ' created. ' + (options.keepAlive ? 'Watchifying...' : ''));
self.writer.write(destination, buf);

e. g. grunt output with similar config:

# from grunt-browserify with options.watch == true
>> /home/mov/dev/project/lib/mixins/property.coffee changed, updating bundle.
>> Bundle dist/lib.js created.

# from grunt-contrib-watch
>> File "dist/lib.js" changed.
Completed in 0.000s at Wed Apr 06 2016 21:00:36 GMT+0500 (YEKT) - Waiting...

String >> <file> changed, updating bundle is inserted here. It's reaction on update event from watchify.

By the way it works well with persistent cache in my project.

And in my project with similarly configuration, the first build via grunt-browserify lasts about 15 seconds, further bundle updating takes few milliseconds. With persistent cache for browserify, duration of the first build is reduced to 3-4 seconds. Not sure that the presence or absence of the text Watchifying ... in console output is important, when there is a performance.


To successfully build is necessary to set grunt-browserify before grunt-contrib-watch. Turn off keepAlive, turn on watch in the grunt-browserify. Isolate source files, so that they are not used at the same time in different tasks. And don't include grunt-browserify in grunt-contrib-watch.

In this case, after completion of the first build, grunt-browserify will remain in the background for monitoring changes in files and updating bundles (using watchify) parallel with the grunt-contrib-watch, which will keep alive the process.

ps: sorry for my English.

@ovcharik Sorry for the delay (was on holiday), turns out you are correct. The watch option does work without the keepAlive function. There is a dependency issue with watchify (browserify/watchify#260), so I had to manually install a watchify version prior to 3.3. After doing that, the watch option started working properly and I was able to remove browserify from my grunt-contrib-watch task (which I'm guessing negated the benefits of the watch option). Subsequent builds are now in the miliseconds range, as you stated.

Thanks for your help, I owe you a beer!

ps: your English is fine 😄