ericclemmons / grunt-express-server

Grunt task for running an Express Server that works great with LiveReload + Watch/Regarde

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Might be ignorance - but

dfitzhenry opened this issue · comments

Is there a ( probably obvious, I'm node-new ) way to have the express server reload when your server.js or similar file changes? I know nodemon is typically for this, but it seems within the watch context there might be a way in grunt-express-server?

I've been doing it with several projects, including this one:

https://github.com/ericclemmons/genesis-skeleton/blob/master/Gruntfile.coffee#L177-L180

It's pretty much watching the server files & re-running the express task.

When in doubt, post up your gruntfile!

Thank you much for the reply, it was ignorance on my part ( didn't have the server files(s) ) configured in the express/server config. However, I'm not sure if it's my watch config or what, but when express:dev tries to restart, I get the error : EADDRINUSE meaning the instance wasn't killed I take it. Probably something wrong with my setup, here is my gruntfile, and again, really appreciate it - I'm sort of a hands on learner, so hacking my way through grunt...

module.exports = function(grunt) {

// Project configuration.
grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    root: './',
    src: './src/web',
    target: './target/user-ux.war',

    // uglify: {
    //     options: {
    //         banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
    //     }
    //     // },
    //     // build: {
    //     //     src: '<%= src %>/js/test.js',
    //     //     dest: '<%= target %>/js/test.min.js'
    //     // }
    // },

    less: {
        prod: {
            options: {
                paths: ["<%= target %>/css"]
            },
            files: {
                "<%= target %>/css/template.css": "<%= src %>/css/template.less"
            },
            cleanCss: "true"
        }
    },

    jshint: {
        // define the files to lint
        files: ['<%= target %>/js/{,*/}*.js', '<%=root%>/test/**/*.js'],
        // configure JSHint (documented at http://www.jshint.com/docs/)
        options: {
            // more options here if you want to override JSHint defaults
            globals: {
                jQuery: true,
                console: true,
                module: true
            },
            ignores: ['<%=target %>/js/lib.js' ]
        }
    },

    copy: {
        user_ux: {
            files: [
                {
                    expand: true,
                    cwd: '<%= src %>/js',
                    src: ['**/*.js'],
                    dest: '<%= target %>/js'
                },
                {
                    expand: true,
                    cwd: '<%= src %>/css',
                    src: ['**/*.less'],
                    dest: '<%= target %>/css'
                },
                {
                    expand: true,
                    cwd: '<%= src %>/',
                    src: ['*.html'],
                    dest: '<%= target %>/'
                },
            ]
        },

        everything: {
            files: [
                {
                    expand: true,
                    cwd: "<%= src %>",
                    src: [
                        "**"
                    ],
                    dest: '<%= target %>'
                }
            ]
        }
    },

    clean: {
      //  build: ["path/to/dir/one", "path/to/dir/two"],
        user_ux: ["<%= target %>"]
    },

    // Performs rewrites based on filerev and the useminPrepare configuration
    usemin: {
        html: ['<%= target %>/{,*/}*.html'],
        css: ['<%= target %>/css/{,*/}*.css'],
        // js: ['<%= target %>/js/{,*/}*.js'],
        options: {
            assetsDirs: ['<%= target %>','<%= target %>/image']
        }
    },

    useminPrepare: {
        html: '<%= src %>/index.html',
        options: {
            root: '<%= target %>',
            dest: '<%= target %>',
            flow: {
                html: {
                    steps: {
                        js: ['concat'],
                        css: ['cssmin']
                    },
                    post: {}
                }
            }
        }
    },

    express: {
        options: {},
        dev: {
            options: {
               script: './server.js'
            },

            livereload: {
                options: {
                    server: './server.js',
                    livereload: true,
                    serverreload: true,
                    bases: ['./<%=target%>']
                }
            }
        }
    },

    connect: {
        options: {
            port: 35729,
            livereload: true,
            serverreload: true,
            open: true,
            hostname: '0.0.0.0',
            directory: "./target/user-ux.war",
            base: "./target/user-ux.war",
        },
        dev: {
            options: {
                middleware: function (connect) {
                    return [
                        require('connect-livereload')() // <--- here
                    ];
                }
            }
        }
    },

    closureCompiler: {
        options: {
            // most options here omitted for brevity
            compilerFile: 'node_modules/closure-compiler/lib/vendor/compiler.jar',

            compilerOpts: {
                // most options here omitted for brevity
                compilation_level: 'ADVANCED_OPTIMIZATIONS',
                create_source_map: true,
                warning_level: "verbose",
                summary_detail_level: 3
            }
        },

        minify: {
            files: [
                {
                    expand: true,
                    src: ['<%= target %>/js/application.js']
                    // ext: '.min.js'
                }
            ]
        }
    },

    ngmin: {
        controllers: {
            src: ['<%=src%>/js/controllers/**/*.js'],
            dest: '<%=target%>/js/controllers'
        },
        directives: {
            expand: true,
            // cwd: 'test/src',
            src: ['<%=src%>/js/directives/**/*.js'],
            dest: '<%=target%>/js/directives'
        }
    }

});

// ** Dependencies **
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks("grunt-bower-install-simple"); // Updates bower libraries prior to build or server tasks
grunt.loadNpmTasks('grunt-closure-tools');
grunt.loadNpmTasks('grunt-express-server');
grunt.loadNpmTasks('grunt-newer');
grunt.loadNpmTasks('grunt-ngmin');
grunt.loadNpmTasks('grunt-usemin');

// ** Express dev config for both watch configs **
var expressDevWatchConfig = {
    files:  [ "<%=root%>/server.js" ],
    tasks:  [ 'express:dev' ],
    options: {
        spawn: true // for grunt-contrib-watch v0.5.0+, "nospawn: true" for lower versions. Without this option specified express won't be reloaded
    }
};

// ** Less dev config for both watch configs **
var lessDevWatchConfig = {
    files: ['<%= target %>/css/*.less'],
    tasks: ['less'],
    options: {
        livereload: true
    }
};

// ** Watch Task for Quick Dev Mode **
grunt.registerTask('watch:quickdev', function() {
    // Configuration for watch:test tasks.
    var config = {
        staticWatch: {
            files: ['<%= src %>/css/**/*.less',
                    '<%= src %>/js/**/*.js',
                    '<%= src %>/*.html'],
            tasks: ['copy-newer'],
            options: {
                livereload: true
            }
        },

        lessWatch: lessDevWatchConfig,
        express: expressDevWatchConfig
    };

    grunt.config('watch', config);
    grunt.task.run('watch');
});

// ** Watch Task for Full Dev Mode **
grunt.registerTask('watch:fulldev', function() {
    // Configuration for watch:test tasks.
    var config = {
        staticWatch: {
            files: ['<%= src %>/css/**/*.less',
                    '<%= src %>/js/**/*.js',
                    '<%= src %>/*.html'],
            tasks: ['copy-newer', 'runBuild'],
            options: {
                livereload: true
            }
        },

        lessWatch: lessDevWatchConfig,
        express: expressDevWatchConfig          
    };

    grunt.config('watch', config);
    grunt.task.run('watch');
});

// ** Tasks **
grunt.registerTask('copy-newer', ['newer:copy:user_ux']);

grunt.registerTask('prepareBuild', [
    'bower-install-simple',
    'clean',
    'copy:everything'
]);

grunt.registerTask('runBuild', [
    'less',
    // 'ngmin',
    'useminPrepare',
    'concat',
    'jshint',
    'cssmin',
    'usemin',
    'closureCompiler'
]);

grunt.registerTask('build', ['prepareBuild', 'runBuild']);
grunt.registerTask('default', ['prepareBuild', 'less', 'express:dev', 'watch:quickdev' ]);
grunt.registerTask('fulldev', ['build', 'less', 'express:dev', 'watch:fulldev' ]);

};

Nevermind I got it, not sure what the implications are, but I changed spawn to false on the express watch config, and it worked. Thanks again for the help though...

I think the "problem" is, that grunt-express-server spawns the server in a child task, but watch also offers this functionality, but when both are turned on, watch spawns a child of grunt-express-server which also spawns a child and somehow the grandchild isn't killed properly on a kill of the child.
Maybe because the child is killed before the grandchild ;)
sounds macabre..

actually we could and should change this..
grunt-contrib-watch is killing with SIGINT
So this:

process.on('SIGINT', this.finished)
process.on('SIGINT', this.stop)

additional to this
could do the trick, I will test it

nope, no way getting this to work.
With

spawn: true
atBegin: true

my grunt-express-server tasks doesn't even live long enough to start the server ;)

I think the grunt.util.spawn isn't designed for nesting..

Not sure if it's relevant, but grunt-watch specifically is not meant for nesting per their site, but I'm not sure if that's relevant to multiple configs, or how it spawns processes ( or both ). Do you think there is any harm in changing spawn to false, which worked for me to fix this, even though my grunt watch is v0.6.1? Maybe I read it wrong, but they want spawn to be true for > 0.5.0 I believe...

There is no harm ;) they just defined it as default.. but it is simply not compatible with grunt-express-server.
Thats probably the reason why spawn:false is mentioned in the readme.

Sweet, thanks to ya'll for handholding :)