Grunt connect not starting with error "root path must be a string"

2.7k views Asked by At

I'm trying to set up my Gruntfile to use the grunt connect npm module. I'm having an issue when trying to start up my server with the command grunt clean server. It errors with the line:

Warning: root path must be a string Use --force to continue.

I'm really not sure what configuration I've messed up and could use another set of eyes. This is my Gruntfile:

/* global module, conf */
var modRewrite = require('connect-modrewrite');
var mountFolder = function(connect, dir) {
    return connect.static(require('path').resolve(dir));
};
module.exports = function(grunt) {

    grunt.initConfig({
        copy: {
            base: {
                files: [
                    {src: "index.html", dest: "BUILD/index.html"},
                    {expand: true, src: "app/**", dest: "BUILD/"},
                    {expand: true, src: "assets/**", dest: "BUILD/"}
                ]
            }
        },

        connect: {
            proxies: [
                {
                    context: "/wwff",
                    host:  "localhost",
                    port: "8080"
                }
            ],

            /**
            * Task defines a server at 9000,
            * watching the BUILD directory
            */
            dev: {
                options: {
                    port: "9000",
                    hostname: '*',
                    base: "BUILD",
                    middleware: function(connect, options) {
                        var proxySnippet = require('grunt-connect-proxy/lib/utils').proxyRequest;

                        return [
                            // include the proxy first
                            proxySnippet,
                            modRewrite([
                                '!\\.html|\\.js|\\.swf|\\.json|\\.xml|\\.css|\\.png|\\.jpg|\\.gif|\\.ico|\\.aff|\\.msi|\\.zip|\\.dic$ /index.html [L]'
                            ]),
                            // serve static files
                            connect.static(options.base),
                            // make empty directories browsable
                            connect.directory(options.base)
                        ];
                    }
                }
            }
        },

        /*
        * This task watches the application and asset directories and
        * deploys any changes to the dev server
        */
        watch: {
            static: {
                files: [ "app/**/*.js", "app/**/*.html"],
                tasks: ["build"]
            }
        },

        clean: {
            build: ["BUILD/"],
            temp: ["tmp"]
        }
    });

    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-connect-proxy');
    grunt.loadNpmTasks('grunt-contrib-clean');

    /*
    * Main BUILD Task
    */
    grunt.registerTask("build", "Copies app and asset files to the BUILD directory.", function() {
        grunt.task.run("copy:base");
    });

    grunt.registerTask("server", "Stand up a node server for development.", function() {
        grunt.task.run(["build", "configureProxies:dev", "connect:dev", "watch"]);
    });

    grunt.event.on('watch', function(action, filepath, target) { 
        grunt.log.writeln(target + ': ' + filepath + ' has ' + action);
    });

};

When I use the --verbose flag I get the following lines:

Verifying property connect.dev exists in config...OK
File: [no files]
Options: protocol="http", port="9000", hostname="*", base="BUILD", directory=null, keepalive=false, debug=false, livereload=false, open=false, useAvailablePort=false, onCreateServer=null, middleware=undefined

It seems to me like the issue is that the middleware is undefined but I have no idea why it is.

Any help is appreciated.

3

There are 3 answers

0
Jon Rubins On BEST ANSWER

Well, I don't understand how, but it seems like my options.base in my middleware function was becoming an array with the first value being my BUILD directory.

So the following snippet for my middleware function works:

middleware: function(connect, options) {
    var proxySnippet = require('grunt-connect-proxy/lib/utils').proxyRequest;

    return [
        // include the proxy first
        proxySnippet,
        modRewrite(['!\\.html|\\.js|\\.swf|\\.json|\\.xml|\\.css|\\.png|\\.jpg|\\.gif|\\.ico|\\.aff|\\.msi|\\.zip|\\.dic$ /index.html [L]']),
        // serve static files
        connect.static(options.base[0]),
        // make empty directories browsable
        connect.directory(options.base[0])
    ];
}

The important part in the above snippet is that my options.base is now options.base[0]. If someone has an explanation for why this is the case, that would be much appreciated.

0
Dominic On

Bit late to the game but in newer version of grunt-connect base is always an array. You can make your middleware compatible with either versions like so:

middleware: function (connect, options) {
    // Older versions of grunt-connect.
    if (!Array.isArray(options.base)) {
        options.base = [options.base];
    }

    var middlewares = [
        require('connect-livereload')()
    ];

    // Serve static files.
    options.base.forEach(function(base) {
        middlewares.push(connect.static(base));
    });

    return middlewares;
}

For an example with grunt-connect-proxy see the docs at https://github.com/drewzboto/grunt-connect-proxy

This is better than just mounting the first base at options.base[0].

0
Charles Loflin On

The reason is that options.base is an array. options.base[0] refers to the first (and in this case only) item in the array (which is a string representing the root path).