26

I am kinda new to grunt and want to use it with Jekyll and some LESS-compiling.

My problem now is, I already have fully functioning LESS-comipiling with live reload and watch task and can build my jekyll site through grunt, but how do I run something like the jekyll serve or grunt-connect and grunt watch simultaneously? I want a grunt task that provides the watching of my LESS-files etc, builds the jekyll site and then runs a small web server with grunt-connect or whatever.

My Gruntfile.js so far:

'use strict';
module.exports = function (grunt) {

    grunt.initConfig({
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            all: [
                'Gruntfile.js',
                'js/*.js',
                '!js/scripts.min.js'
            ]
        },
        less: {
            dist: {
                files: {
                    'css/styles.min.css': [
                        'less/app.less'
                    ]
                },
                options: {
                    compress: true,
                    // LESS source map
                    // To enable, set sourceMap to true and update sourceMapRootpath based on your install
                    sourceMap: false,
                    sourceMapFilename: 'css/styles.min.css.map',
                    sourceMapRootpath: '/'
                }
            },
            dev: {
                files: {
                    'css/styles.min.css': [
                        'less/app.less'
                    ]
                },
                options: {
                    compress: false,
                    // LESS source map
                    // To enable, set sourceMap to true and update sourceMapRootpath based on your install
                    sourceMap: true,
                    sourceMapFilename: 'css/styles.min.css.map',
                    sourceMapRootpath: '/'
                }
            }
        },
        uglify: {
            dist: {
                files: {
                    'js/scripts.min.js': [
                        'vendor/bootstrap/js/transition.js',
                        'vendor/bootstrap/js/alert.js',
                        'vendor/bootstrap/js/button.js',
                        'vendor/bootstrap/js/carousel.js',
                        'vendor/bootstrap/js/collapse.js',
                        'vendor/bootstrap/js/dropdown.js',
                        'vendor/bootstrap/js/modal.js',
                        'vendor/bootstrap/js/tooltip.js',
                        'vendor/bootstrap/js/popover.js',
                        'vendor/bootstrap/js/scrollspy.js',
                        'vendor/bootstrap/js/tab.js',
                        'vendor/bootstrap/js/affix.js',
                        'vendor/*.js',
                        'js/_*.js'
                    ]
                },
                options: {
                    // JS source map: to enable, uncomment the lines below and update sourceMappingURL based on your install
                    // sourceMap: 'assets/js/scripts.min.js.map',
                    // sourceMappingURL: '/app/themes/roots/assets/js/scripts.min.js.map'
                }
            }
        },
        watch: {
            less: {
                files: [
                    'less/*.less',
                    'less/bootstrap/*.less'
                ],
                tasks: ['less:dev']
            },
            js: {
                files: [
                    '<%= jshint.all %>'
                ],
                tasks: ['jshint', 'uglify']
            },
            livereload: {
                // Browser live reloading
                // https://github.com/gruntjs/grunt-contrib-watch#live-reloading
                options: {
                    livereload: true
                },
                files: [
                    '_site/*'
                ]
            }
        },
        clean: {
            dist: [
                'css/styles.min.css',
                'css/styles.min.css.map',
                'js/scripts.min.js',
                '_site/*'
            ]
        },
        jekyll: {                             // Task
            options: {                          // Universal options
                bundleExec: true,
                src : '<%= app %>'
            },
            dist: {                             // Target
                options: {                        // Target options
                    dest: '<%= dist %>',
                    config: '_config.yml'
                }
            },
            serve: {                            // Another target
                options: {
                    serve: true,
                    drafts: true
                }
            }
        },
        connect: {
            server: {
                options: {
                    keepalive: true
                }
            }
        }
    });

    // Load tasks
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-jekyll');
    grunt.loadNpmTasks('grunt-contrib-connect');

    // Register tasks
    grunt.registerTask('default', [
        'clean',
        'less:dist',
        'uglify',
        'jekyll:dist'
    ]);
    grunt.registerTask('dev', [
        'watch'
    ]);

};
Kageetai
  • 1,268
  • 3
  • 12
  • 26

3 Answers3

37

You need to tell connect what directory to serve up in the configuration using the "base" option, in this case it would be the static _site directory. You can also change the port to whatever you want, but you end up navigating to localhost:9009 with my example

connect: {
  server: {
    options: {
      livereload: true,
      base: '_site/',
      port: 9009
    }
  }
}

You will also want to add a watch task for when you change your html templates. Something like this would work.

watch: {
  html: {
    files: ['**/*.html', '!_site/**/*.html'],
    tasks: ['jekyll:dist']
  }
}

Then create a "serve" task like Wallace suggested.

// Start web server
grunt.registerTask('serve', [
'jekyll:dist',
'connect:server',
'watch'
]);

Lastly run "grunt serve" in the command line and navigate to localhost with the port you specified.


As commented by @jiggy

The key change is to not set keepalive to true. Keepalive will block all subsequent tasks from running. So long as connect is followed by watch the server won't terminate.

sabithpocker
  • 15,274
  • 1
  • 42
  • 75
bribou
  • 792
  • 6
  • 9
  • 1
    Thanks, I didn't know connect and watch could be run simultaneously so easily :) – Kageetai Feb 18 '14 at 23:46
  • 13
    I'll piggyback on the accepted answer to highlight that the key change is to not set keepalive to true. Keepalive will block all subsequent tasks from running. So long as connect is followed by watch the server won't terminate. – jiggy Aug 18 '14 at 23:59
  • I get a 'fatal error' notice when I specify the port in addition to the config above, but it doesn't actually fail, so might be a red-herring. Something to note however. – Jesse Nov 17 '14 at 22:08
  • @jiggy mine too :-) – David Lartey Aug 04 '16 at 09:25
  • I have followed @jiggy said, but i does not reload the browser and I got errror File not found: http://0.0.0.0:35729/livereload.js?snipver=1 – Dave Jun 11 '19 at 02:12
3

I spent 2 days desperately trying every gruntfile-configuration I could find on the internet. Never worked. Then I found this https://stackoverflow.com/a/24765175/1541141. Use grunt-contrib-connect, NOT grunt-connect. grunt-connect is blocking... Hope it helps.

Community
  • 1
  • 1
OoDeLally
  • 552
  • 1
  • 5
  • 21
2

I think the heart of your solution is to create a new task or edit an existing task, like so:

// Start web server
grunt.registerTask('serve', [
    'jekyll:dist',
    'connect:livereload',
    'watch'
]);

...which you would run with a $ grunt serve. less, jshint, uglify and connect are already included under watch.

Wallace Sidhrée
  • 11,221
  • 6
  • 47
  • 58
  • Remember: you can create as many tasks as you want, and invoke them with `$ grunt `. Run any combination of anything, paying some attention to loading order if a task depends on another being run first. – Wallace Sidhrée Feb 17 '14 at 20:53