Skip to content

Instantly share code, notes, and snippets.

@matthewlein
Last active April 8, 2020 07:54
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matthewlein/7742781 to your computer and use it in GitHub Desktop.
Save matthewlein/7742781 to your computer and use it in GitHub Desktop.
The simplest way to have grunt run a server, watch all the files for changes, and livereload on change. Set up to compile SASS and livereload the css on changes.Using the package.json, all you need to do is npm install and then it should work.
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-sass');
// don't watch node_modules
// used in watch files below
var excludes = [
'!**/node_modules/**'
];
grunt.initConfig({
// add excludes to the grunt object for access later
excludes : excludes,
connect: {
server: {
options: {
port: 9001,
// open a browser
open : true,
// inject livereload.js into the pages
livereload : true
}
}
},
sass: {
compile: {
options: {
// expanded for dev
style: 'expanded',
// compressed for prod
// style: 'compressed',
// if you're using compass
compass : true,
// line numbers of scss in the css for debugging
// lineNumbers : true,
// set up sourcemaps, requires SASS 3.3 and Compass 1.0alpha?
sourcemap : true
},
files: {
// list your css and corresponding scss pages here
// I usually just import all partials into style.scss
'style.css': 'style.scss'
}
}
},
watch : {
options: {
livereload: true
},
// make a subtask for each filetype to selectively run tasks and livereload
html: {
files: [
'**/*.html',
'<%= excludes %>'
],
},
js: {
files: [
'**/*.js',
'<%= excludes %>'
],
tasks: [],
},
// don't livereload sass because we livereload the css
sass: {
options: {
livereload: false
},
files: [
'**/*.scss',
'<%= excludes %>'
],
// compile on save
tasks: ['sass'],
},
css: {
files: [
'**/*.css',
'<%= excludes %>'
],
tasks: []
}
}
});
// Default task(s).
grunt.registerTask('default', [
'sass',
'connect',
'watch'
]);
};
{
"name": "grunt-server",
"version": "0.0.1",
"devDependencies": {
"grunt": "~0.4.2",
"grunt-contrib-watch": "~0.5.3",
"grunt-contrib-connect": "~0.5.0",
"grunt-contrib-sass": "~0.5.1"
}
}
@treecamp
Copy link

treecamp commented Apr 7, 2020

Thanks! This helped me allot! Only problem i am having is that the watch task isn't always seeing that my generated .css file is changed. Therefor a livereload isn't triggered everytime i edit the .scss file.

  1. I edit my .scss file.
  2. sass task kicks in and regenerates my .css file.
  3. Livereload is not triggered.
  4. I change my .scss file again.
  5. sass task kicks in and regenerates my .css file.
  6. And then livereload is triggered.
  7. And this keeps happening, step 1 to 6.

Weird thing is, it is seeing the .css file is changed in the terminal.
Any idea what is causing this?

terminal output

>> File "css/app.css" changed.
>> File "css/app.scss" changed.
Running "sass:dist" (sass) task

Done, without errors.
Completed in 7.129s at Tue Apr 07 2020 11:58:46 GMT+0200 (Central European Summer Time) - Waiting...
>> File "css/app.css" changed.
>> File "css/app.scss" changed.
Running "sass:dist" (sass) task

Done, without errors.
Completed in 3.220s at Tue Apr 07 2020 11:58:56 GMT+0200 (Central European Summer Time) - Waiting...

Grutnfile.js

module.exports = function(grunt) {

    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-contrib-htmlmin');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-sass');
    grunt.loadNpmTasks('grunt-include-source');
    grunt.loadNpmTasks('grunt-dom-munger');

    var excludes = [
        '!**/node_modules/**'
    ];

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        excludes : excludes,

        app: {
            scripts: [
                'node_modules/angular/angular.min.js',
                'js/app.js',
                'js/controllers/**/*.js',
                'js/directives/**/*.js'
            ]
        },

        connect: {
            server: {
                options: {
                    port: 9001,
                    open : true,
                    livereload : true
                }
            }
        },

        dom_munger: {
            read: {
                options: {
                    read: [
                        {selector:'script[data-build!="exclude"]',attribute:'src',writeto:'appjs'}
                    ]
                },
                src: 'index.html'
            },
            update: {
                options: {
                    remove: ['script[data-remove!="exclude"]', 'link[data-remove!="exclude"]'],
                    append: [
                        {selector:'head',html:'<link href="css/app.full.min.css" rel="stylesheet">'},
                        {selector:'body',html:'<script src="js/app.full.min.js"></script>'}
                    ]
                },
                src: 'index.html',
                dest: 'dist/index.html'
            }
        },

        concat: {
            js: {
                src: ['<%= dom_munger.data.appjs %>'],
                dest: 'dist/js/app.full.js',
                options: {
                    separator:';\n'
                },
            }
        },

        sass: {
            dist: {
                files: {
                    'css/app.css': 'css/app.scss'
                }
            }
        },

        uglify: {
            js: {
                files: {
                    'dist/js/app.full.min.js': ['<%= concat.js.dest %>']
                }
            }
        },

        cssmin: {
            css: {
                files: {
                    'dist/css/app.full.min.css': ['css/app.css']
                }
            }
        },

        htmlmin: {
            index: {
                options: {
                    collapseBooleanAttributes: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true,
                    removeComments: true,
                    removeEmptyAttributes: true,
                    removeRedundantAttributes: true,
                    removeScriptTypeAttributes: true,
                    removeStyleLinkTypeAttributes: true
                },
                files: {
                    'dist/index.html': 'dist/index.html'
                }
            },
            directives: {
                options: '<%= htmlmin.index.options %>',
                files: [{
                    expand: true,
                    src: 'js/**/*.html',
                    dest: 'dist/'
                }]
            },
        },

        qunit: {
            files: ['test/**/*.html']
        },

        jshint: {
            files: ['Gruntfile.js', 'js/**/*.js', 'test/**/*.js'],
            options: {
                globals: {
                    jQuery: true,
                    console: true,
                    module: true
                }
            }
        },

        copy: {
            main: {
                files: [
                    {
                        src: ['img/**'],
                        dest: 'dist/'
                    }
                ]
            }
        },

        includeSource: {
            options: {
                basePath: '',
                baseUrl: '',
                ordering: 'top-down'
            },
            app: {
                files: {
                    'index.html': 'index.html'
                }
            }
        },

        watch : {
            options: {
                livereload: true
            },
            html: {
                files: [
                    '**/*.html',
                    '<%= excludes %>'
                ],
            },
            js: {
                files: [
                    '**/*.js',
                    '<%= excludes %>'
                ],
                tasks: ['jshint'],
            },
            sass: {
                options: {
                    livereload: false
                },
                files: [
                    '**/*.scss',
                    '<%= excludes %>'
                ],
                tasks: ['sass'],
            },
            css: {
                files: [
                    '**/*.css',
                    '<%= excludes %>'
                ]
            }
        }
    });

    // Default
    grunt.registerTask('default', [
        'sass',
        'connect',
        'watch'
    ]);

    // Test
    grunt.registerTask('test', [
        'jshint',
        'qunit'
    ]);

    // Build
    grunt.registerTask('build', [
        'jshint',
        'qunit',
        'dom_munger',
        'concat',
        'sass',
        'cssmin',
        'uglify',
        'copy',
        'htmlmin'
    ]);
};

package.json

{
  "name": "BoltNetwork",
  "version": "0.1.0",
  "devDependencies": {
    "angular": "~1.7.9",
    "bootstrap": "~4.4.1",
    "grunt": "~0.4.5",
    "grunt-angular-file-sort": "^1.3.5",
    "grunt-contrib-concat": "^1.0.1",
    "grunt-contrib-connect": "^2.1.0",
    "grunt-contrib-copy": "^1.0.0",
    "grunt-contrib-cssmin": "^3.0.0",
    "grunt-contrib-htmlmin": "^3.1.0",
    "grunt-contrib-jshint": "^2.1.0",
    "grunt-contrib-nodeunit": "^2.1.0",
    "grunt-contrib-qunit": "^3.1.0",
    "grunt-contrib-sass": "^1.0.0",
    "grunt-contrib-uglify": "^4.0.1",
    "grunt-contrib-watch": "^1.1.0",
    "grunt-dom-munger": "^3.4.0",
    "grunt-include-source": "^1.1.0"
  },
  "dependencies": {}
}

@matthewlein
Copy link
Author

Hello,

I'm glad this was helpful to you. It looks like it's been 6 years since I wrote this 😅 so, no I don't really have any ideas. Personally, I've been using webpack's dev server for the last few years. I have seen some file watching modules not work all the time in the last few years. Sometimes deleting node_modules and package-lock.json, then reinstalling can fix some dependency issues.

That's all I got 😄

@treecamp
Copy link

treecamp commented Apr 8, 2020

Okay thank you, i have the same issue in a other project. For now i'll just remove the listen on css, and put it on the scss files, that does seems to work. And i'll have a look at webpack's dev server! Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment