twolfson / grunt-spritesmith

Grunt task for converting a set of images into a spritesheet and corresponding CSS variables
MIT License
1.14k stars 92 forks source link

Getting error when running basic example #52

Closed facultymatt closed 10 years ago

facultymatt commented 10 years ago

Getting the following error running the example config (with my proper paths setup of course):

    sprite:{
      all: {
        src: 'path/to/your/sprites/*.png',
        destImg: 'destination/of/spritesheet.png',
        destCSS: 'destination/of/sprites.css'
      }
    }
.../node_modules/grunt-contrib-compass/node_modules/tmp/lib/tmp.js:261
  throw err;
        ^
SyntaxError: Unexpected token o
    at Object.parse (native)
    at ChildProcess.<anonymous> (.../node_modules/grunt-spritesmith/node_modules/spritesmith/node_modules/phantomjssmith/lib/exporters.js:84:32)
    at ChildProcess.EventEmitter.emit (events.js:98:17)
    at maybeClose (child_process.js:735:16)
    at Process.ChildProcess._handle.onexit (child_process.js:802:5)
twolfson commented 10 years ago

I am confused why the error is being raised from grunt-contrib-compass. Is this error being raised when you run grunt sprite by itself? What happens when you don't load any other grunt tasks?

facultymatt commented 10 years ago

That did seem odd to me at first. Then I removed compass a grunt task, the error was thrown by: .../node_modules/grunt-google-cdn/node_modules/bower/node_modules/tmp/lib/tmp.js:261

So in both cases the error is thrown by the tmp module. This is the code around line 261:

process.addListener('uncaughtException', function _uncaughtExceptionThrown( err ) {
  _uncaughtException = true;
  _garbageCollector();

  throw err;
});

Moving on to the actual error, which is thrown by /node_modules/grunt-spritesmith/node_modules/spritesmith/node_modules/phantomjssmith/lib/exporters.js:85:32 this is line 85: var decodedPixels = JSON.parse(encodedPixels); Meaning the error is coming from attempting to parse json.

I've played around with the image src folder, limiting the images in different ways, i'm wondering if the following factors are breaking it.

twolfson commented 10 years ago

Yea, there could be a large variety of things going wrong. Can you clone the phantomjssmith repo and run the tests?

git clone https://github.com/twolfson/phantomjssmith
cd phantomjssmith
npm install
npm test
facultymatt commented 10 years ago

Getting 5 tests complete (7 seconds).

twolfson commented 10 years ago

We should make a point to fix that JSON.parse to be more graceful in telling us what the message is.

var decodedPixels;
try {
  decodedPixels = JSON.parse(encodedPixels);
} catch (e) {
  cb(new Error('Error while parsing JSON "' + encodedPixels + '".\n' + e.message));
}
twolfson commented 10 years ago

Interesting, can you run npm ls inside of your repo? I want to confirm that you are running the latest version of grunt-spritesmith and phantomjssmith.

facultymatt commented 10 years ago

Interesting, thats a bit more helpful

../../../../../../../../app/images/icons/ls_arm_overlay.png%22%7D,%22x%22:0,%22y%22:14739%7D%5D,%22options%22:%7B%22format%22:%22png%22,%22quality%22:90%7D%7D:40
null
".
Unexpected token o

not sure where that null is coming from...

facultymatt commented 10 years ago

Tree is:

├─┬ grunt-spritesmith@1.12.0
│ ├─┬ json2css@4.1.0
│ │ ├── json-content-demux@0.1.3
│ │ └── mustache@0.7.3
│ ├─┬ spritesmith@0.12.1
│ │ ├── async@0.2.9
│ │ ├─┬ layout@1.3.1
│ │ │ └── binpacking@0.0.1
│ │ └─┬ phantomjssmith@0.2.3
│ │   ├─┬ ndarray@1.0.8
│ │   │ └── iota-array@0.0.1
│ │   ├── obj-extend@0.1.0
│ │   ├─┬ save-pixels@0.3.0
│ │   │ ├── pngjs@0.4.0
│ │   │ └── through@2.3.4
│ │   ├── shell-quote@1.4.0
│ │   ├─┬ temporary@0.0.5
│ │   │ └── package@1.0.1
│ │   └── which@1.0.5
│ ├── underscore@1.4.4
│ └── url2@1.0.0
twolfson commented 10 years ago

I am not sure that is what I would expect from encodedPixels. Is there anything else before the ../../...?

facultymatt commented 10 years ago

Yes, theres a couple hundred lines. Basically its a url string that starts with file:///Users/facultymatt/Sites/projectName/node_modules/grunt-spritesmith/node_modules/spritesmith/node_modules/phantomjssmith/lib/scripts/compose.html?%7B%22width%22:17149,%22height%22:15258,%22images%22:%5B%7B%22img%22:%7B%22height%22:7,%22width%22:7,%22_filepath%22:%22app/images/icons/bullet.png%22,%22_urlpath%22: and continues for each image.

twolfson commented 10 years ago

Ah, k. There is probably a complaint from PhantomJS somewhere in there. Can you run grunt-spritesmith with exactly one image?

sprite: {
  src: ['app/images/icons/bullet.png'],
  ...
}
facultymatt commented 10 years ago

Works fine. I can't tell if I have a corrupt image, or just too many.

facultymatt commented 10 years ago

Could phantomJS be timing out?

facultymatt commented 10 years ago

I think this might have something to do with

// Convert over all image paths to url paths
    var images = that.images;
    images.forEach(function getUrlPath (img) {
      img = img.img;
      img._urlpath = path.relative(__dirname + '/scripts', img._filepath);
    });

not building the path correctly...

twolfson commented 10 years ago

Can we try doing a binary search on this?

var images = grunt.file.expand('app/images/icons/*.png');
var len = images.length;

sprite: {
  // Adjust offset until we find the failing image
  src: images.slice(0, Math.floor(len / 2));
  // src: images.slice(Math.floor(len / 2), len));
}
facultymatt commented 10 years ago

OK, seems the magic number if 246 images. 247 and the process fails. Doesn't seem to matter which images they are - I deleted all images except the magic 246, then duplicated just one of these "valid images" and the process failed. Any ideas?

facultymatt commented 10 years ago

Could this be an issue with the length of the url here:

var page = webpage.create();
page.open(phantom.libraryPath + '/compose.html?' + encodedArg, function (status) {
  // Pluck out the data png
  var retStr = page.evaluate(function () {
    return window.retStr;
  });

  // Export the pixel values
  console.log(retStr);

  // Leave the program
  phantom.exit();
});

encodedArg is created from the images object, stringified and url encoded. In the case of 247 images (the failing number) encodedArg is 71663 characters long! Maybe this is just too long for a url?

Could we switch this to POST? That would avoid url limitations for length.

facultymatt commented 10 years ago

Got it! The url is too large. I copied the file:// url into my browser (had to switch to localhost) and got the following message:

Request-URI Too Large

The requested URL's length exceeds the capacity limit for this server.

And the following message in the console:

"NetworkError: 414 Request-URI Too Large - http://localhost:8888/.......really long string!!!..."

So this appears to be a limitation of https://github.com/twolfson/phantomjssmith. I'll open up a ticket there. As for this library it would be worth noting that large sets of images are incompatible with phantom engine, and maybe checking the length of encodedArg in some place for length.

twolfson commented 10 years ago

Great catch! I actually ran into this bug during a hackathon 2 weekends ago but I rushed passed documenting it.

https://github.com/nko4/console-log/commit/a3d408f6734edda6d577384b51038498768980aa#diff-112581bb9391749e06f525a763b72c88

I will document the fix in that ticket you opened up.

twolfson commented 10 years ago

The patch inside of phantomjssmith@0.3.0 has been released in grunt-spritesmith@1.13.0.

facultymatt commented 10 years ago

Thanks for the quick fix on this!