0

I'm developing a custom grunt extension that reloads a chrome tab. It works fine when I use it within the plugin's own folder, but then when I try to download it from NPM and use it in another project, it goes bonkers.

I included it as such:

grunt.loadNpmTasks('grunt-chrome-extension-reload');

My custom task code, located in the tasks folder of the plugin, is as such:

/*
 * grunt-chrome-extension-reload
 * https://github.com/freedomflyer/grunt-chrome-extension-reload
 *
 * Copyright (c) 2014 Spencer Gardner
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  var chromeExtensionTabId = 0;


  grunt.initConfig({

    /**
      Reloads tab in chrome with id of chromeExtensionTabId
      Called after correct tab number is found from chrome-cli binary. 
    */
    exec: {
      reloadChromeTab: {
        cmd: function() {
          return chromeExtensionTabId ? "chrome-cli reload -t " + chromeExtensionTabId : "chrome-cli open chrome://extensions && chrome-cli reload"; 
        }
      }
    },

    /**
      Executes "chrome-cli list tabs", grabs stdout, and finds open extension tabs ID's.
      Sets variable chromeExtensionTabId to the first extension tab ID
    */
    external_daemon: {
      getExtensionTabId: {
        options: {
          verbose: true,
          startCheck: function(stdout, stderr) {

            // Find any open tab in Chrome that has the extensions page loaded, grab ID of tab
            var extensionTabMatches = stdout.match(/\[\d{1,5}\] Extensions/);

            if(extensionTabMatches){
              var chromeExtensionTabIdContainer = extensionTabMatches[0].match(/\[\d{1,5}\]/)[0];

              chromeExtensionTabId = chromeExtensionTabIdContainer.substr(1, chromeExtensionTabIdContainer.length - 2);
              console.log("Chrome Extension Tab #: " + chromeExtensionTabId);
            }

            return true;
          }
        },
        cmd: "chrome-cli",
        args: ["list", "tabs"]
      }
    }

  });

  grunt.registerTask('chrome_extension_reload', function() {
    grunt.task.run(['external_daemon:getExtensionTabId', 'exec:reloadChromeTab']);
  });

};

So, when I run it in an external project with grunt watch, grunt spits out this error a few hundred times before quitting (endless loop?)

Running "watch" task
Waiting...Verifying property watch exists in config...ERROR
>> Unable to process task.
Warning: Required config property "watch" missing.
Fatal error: Maximum call stack size exceeded

Interestingly, can not even call my plugin within the watch task, and the problem persists. Only by removing grunt.loadNpmTasks('grunt-chrome-extension-reload'); can I get rid of the issue, which basically means that the code inside my task is wrong. Any ideas?

freedomflyer
  • 2,431
  • 3
  • 26
  • 38
  • What's the output when you run the watch task with the `--verbose` flag? – steveax Feb 15 '14 at 03:14
  • Registering "grunt-chrome-extension-reload" local Npm module tasks. Reading /Users/spencergardner/Google Drive/development/wordly-dev/wordly-server/wordly-extension/node_modules/grunt-chrome-extension-reload/package.json...OK Parsing /Users/spencergardner/Google Drive/development/wordly-dev/wordly-server/wordly-extension/node_modules/grunt-chrome-extension-reload/package.json...OK Initializing config...OK Loading "chrome_extension_reload.js" tasks...OK + chrome_extension_reload – freedomflyer Feb 15 '14 at 05:14

1 Answers1

1

grunt.initConfig() is intended for end users. As it will completely erase any existing config (including your watch config) and replace with the config you're initializing. Thus when your plugin is ran it replaces the entire config with the exec and external_daemon task configs.

Try using grunt.config.set() instead. As it only sets a given part of the config rather than erasing the entire thing.

But a better pattern for a plugin is to let the user determine the config. Just have a plugin handle the task. In other words, avoid setting the config for the user.

Kyle Robinson Young
  • 13,732
  • 1
  • 47
  • 38
  • My plugin doesn't really do too much in the way of exposing completely new functionality, it mostly combines a few existing plugins in a useful way that would be messy to do in a nice, organized Gruntfile. So having the user do the config would defeat the point - since I want to wrap some complicated-ish code up and abstract it away. Any solutions there? – freedomflyer Feb 15 '14 at 23:18
  • Take a look at this example: https://github.com/cowboy/wesbos/blob/master/Gruntfile.js and using `grunt.loadTasks()` to break up your Gruntfile. Config, at least from Grunt's philosophy, shouldn't be abstracted away. It's intended on being declarative or easily scannable by the user viewing the Gruntfile. – Kyle Robinson Young Feb 16 '14 at 02:01