WebStorm, Three.JS, Source Maps and ARRRRRGHHHHHHHH


So, as you may be able to tell from the title, I’ve run into a bit of a bug moment.  I am in the process of getting Blender exported models to work with the Three.JS library, as a follow up to this post.  As with all things programming related you are going to run into your share of problems.  This post actually walks through the process of identifying and fixing a bug.


The first lesson of bug hunting is always simplify.  Try to replicate the problem in as little code as possible.  What follows below is a blow by blow of  the debugging process.


First off, it’s a Three.JS project using TypeScript authored in WebStorm.  All of these points are important to this story.  Not to ruin an upcoming post with too much code, I’ll just give the applicable code.  The problem is in this code… if it’s in code at all that is.  Yeah, that’s a bit of a hint.


        var modelLoader = new THREE.JSONLoader();            modelLoader.load("dice.jsm", function(geometry,materials){              var mesh = new THREE.SkinnedMesh(geometry,new THREE.MeshFaceMaterial(                         materials));              mesh.position. x = mesh.position.y = mesh.position.z = 0;              this.scene.add(mesh);          });


Anyways, I started off by trying to load this model:


Exported from Blender to Three.JS JSON format.


When I run the code however I get the following in WebStorm:



Unexpected token /?


Hmmm, looks like something went wrong in the export process.  This is never a fun thing to debug, as the output of the above model is a JSON file 1.5MB in size.


So, it’s time to simplify.  I need a model with a texture, nothing more.  Let’s make something about as basic as possible.  So I hack together a quick textured model in Blender and export it.  This is the new model:



Ok, that is definitely simpler.  Now when I run it I get the exact same error.  Ok, this file should be a hell of a lot easier to debug.  Let’s take a look at the generated JSON file.  Oh, top type… right click the js file and tell Webstorm to treat it as plain text, otherwise it will clobber your CPU trying to parse the javascript!



{    	"metadata" :  	{  		"formatVersion" : 3.1,  		"generatedBy"   : "Blender 2.7 Exporter",  		"vertices"      : 8,  		"faces"         : 6,  		"normals"       : 2,  		"colors"        : 0,  		"uvs"           : [24],  		"materials"     : 1,  		"morphTargets"  : 0,  		"bones"         : 0  	},    	"scale" : 1.000000,    	"materials" : [	{  		"DbgColor" : 15658734,  		"DbgIndex" : 0,  		"DbgName" : "Material",  		"blending" : "NormalBlending",  		"colorAmbient" : [0.6400000190734865, 0.6400000190734865, 0.6400000190734865],  		"colorDiffuse" : [0.6400000190734865, 0.6400000190734865, 0.6400000190734865],  		"colorEmissive" : [0.0, 0.0, 0.0],  		"colorSpecular" : [0.5, 0.5, 0.5],  		"depthTest" : true,  		"depthWrite" : true,  		"mapDiffuse" : "crate.jpg",  		"mapDiffuseWrap" : ["repeat", "repeat"],  		"shading" : "Lambert",  		"specularCoef" : 50,  		"transparency" : 1.0,  		"transparent" : false,  		"vertexColors" : false  	}],    	"vertices" : [1,-1,0,1,0,1,-1,0,0,0,-1,0,1,0,0,0,1,1,-1,1,0,0,0,0],    	"morphTargets" : [],    	"normals" : [0.577349,0.577349,0.577349,0.577349,0.577349,-0.577349],    	"colors" : [],    	"uvs" : [[0.988679,0.99767,0.988677,0.016243,0.007251,0.016244,0.007252,0.  	997671,0.989755,0.017099,0.989755,0.998526,0.008328,0.998526,0.008328,0.017099,  	0.990714,0.989755,0.009287,0.989755,0.009286,0.008328,0.990713,0.008328,0.  	000516,0.993662,0.981943,0.993661,0.981942,0.012235,0.000516,0.012235,0.987766,  	0.997568,0.987766,0.016141,0.006339,0.016141,0.006339,0.997568,0.986807,0.  	986807,0.986807,0.005381,0.00538,0.00538,0.00538,0.986807]],    	"faces" : [43,0,3,2,1,0,0,1,2,3,0,0,1,1,43,4,7,6,5,0,4,5,6,7,0,0,1,1,43,0,4,5,1,  	0,8,9,10,11,0,0,1,1,43,1,2,6,5,0,12,13,14,15,1,1,1,1,43,2,3,7,6,0,16,17,18,19,1,  	0,0,1,43,3,0,4,7,0,20,21,22,23,0,0,0,0],    	"bones" : [],    	"skinIndices" : [],    	"skinWeights" : [],      "animations" : []      }


Well, first obvious thing is to look for an offending / in this code.

Hmmm… there is none.  Well we wouldn’t make the big bucks if this was easy now would we?


Let’s go back to our error for a second:



Well, other than the fact we know we have a / where we shouldn’t, we also have the line of code that is going all explodey.  Let’s start there.  This is one of those things that makes WebStorm so freaking cool.  Just click the link “three.js:11960” and it will automatically download that script file and go to that position.  Let’s take a look at the resulting code:



Ok, that’s some pretty straight forward code.  Basically it’s a XML response function handler.  As we can tell from the above code, the callback executed all nice and dandy.  As you can see on line 11960 I’ve set a breakpoint to pause execution before our exception, let’s see if that gives us any insight.  If you don’t know about breakpoints and debugging, drop everything and learn.  You will literally become a better programmer overnight.


So… to the debugger!  Let’s see what the value of responseText is:


By hovering over it, everything looks fine, seems to match the file we are expecting:



That said, let’s take a look at the whole thing.  Now we are going to use a feature called “Evaluate Expression”.  Again, if you don’t know what this is, drop everything and go learn.  I really need to write a debugging tutorial…. 




Copy the value and paste it into your editor of choice.  Then scroll to the very bottom:



Oh son of a bi….


That my friend, is our bug.  See, Webstorm has the ability to generate something called a SourceMap, which helps the debugger translate your running code to the code you created, especially useful if you, like me, are working in a JavaScript generating language like TypeScript.  As you can see, sometimes this is not ideal however.  Basically when run, Webstorm was appending a source map to the bottom of our js file, rendering into invalid JSON and causing the parser to puke.


There are two immediate solutions to this problem.  First, we can disable source map generation.  This unfortunately is a project wide setting as far as I can tell, and I rather like the ability to debug.  The easier solution is to change it from a .js file to something different.  However, once deployed to a server this can have unintended side effects.  For example, IIS will not, by default, serve files without a registered mime type.


Oh, and for the astute, once I got past the problem be renaming the file extension, I did in fact discover two errors in my code.  The proper TypeScript code is;


        var modelLoader = new THREE.JSONLoader();            modelLoader.load("dice.jsm", (geometry,materials) => {              var mesh = new THREE.SkinnedMesh(geometry,new THREE.MeshFaceMaterial(                         materials));              mesh.position.x = 0; mesh.position.y = mesh.position.z = 0;              this.scene.add(mesh);          });


Why is an exercise for the reader. 🙂


Scroll to Top