Wednesday, May 25, 2016

usemin wrongly includes scritps.js inside Html's conditional comments, what to do?

Since I've started working on awesome Node.js and all relevant technologies, I've been challenged to lot of things. Technologies like npm, grunt, gulp, bower are performing well in the era of front-end development and changing the working style. Everyone's typical goal is "Automation". Javascript development is not excluded from that.

So, what is the problem which I want to describe here and give solution which can be useful to some beginners like me ? Let me explain.

To work with angular js, you might use build tools like grunt or gulp and you might heard name "Yeoman". In your index.html file, you might configured lot of things like bower build, Google analytics script, and HTML's conditional comments which include some scripts. 

<!--[if lt IE 9]>
<script src="bower_components/es5-shim/es5-shim.js"></script>
<script src="bower_components/json3/lib/json3.min.js"></script>
<![endif]-->
Those scripts are there to support HTML5 tags for browser IE <= 9.

For beginners, who just wanna start their angular project, I would suggest to use template which is get provided by eclise-che. You can it access here.

Now after you visit the link, you can see index.html in app folder and it's easy for me to explain the thing. If you see Gruntfile.js, look at code of usemin

In short and sweet terms, usemin will optimize your all assets (which includes <!-- build:type ... --> into one target file. So, usemin is work based on those blocks in html file.

So, in index.html file, after you run useminPrepare and usemin, following two lines will be added:

<script src="scripts/vendor.js"></script>
<script src="scripts/scripts.js"></script>
In big project, large number of people may work on same file. There are chances of mistake in this case. So suppose that index.html files was changed by someone mistakenly and after you issue useminPrepare and usemin commands, the output will be like this:

<script src="scripts/vendor.js"></script> 
<!--[if lt IE 9]> 
<script src="scripts/scripts.js"></script> 
<![endif]-->
Oh God! My required scripts will not be executed by browser in all IE > 9 browsers and non-IE browsers! What happened here? I checked Gruntfile.js, it's perfect. No problem there. Then what's exactly a problem? Why usemin is considering our required scripts.js to use only for IE <= 9 ?

Beginners might get stuck in problem and not able to find problem. So here is problem:


<!-- bower:js -->
<script src="bower_components/jquery/jquery.js"></script>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/sass-bootstrap/dist/js/bootstrap.js"></script>
<script src="bower_components/angular-resource/angular-resource.js"></script>
<script src="bower_components/angular-cookies/angular-cookies.js"></script>
<script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
<script src="bower_components/angular-route/angular-route.js"></script>
<!-- endbower -->
<!-- endbuild -->
<!-- build:js({.tmp,app}) scripts/scripts.js -->
<script src="scripts/app.js"></script>
<script src="scripts/controllers/main.js"></script> <!--[if lt IE 9]> <script src="bower_components/es5-shim/es5-shim.js"></script> <script src="bower_components/json3/lib/json3.min.js"></script> <![endif]-->
<!-- endbuild -->

Can you see the problem? 
Someone added that conditional code which states "execute it if this browser is IE <=9" insdie <!-- build:js({.tmp,app}) scripts/scripts.js --> <!-- endbuild --> block.

usemin wrongly do some process and it considers our scripts app.js and main.js as if lt IE 9 and put whole generated scripts.js inside conditional comments. And so, browser will not be able to execute our most important scripts! So, remove it from usemin block and put outside somewhere.

I hope it will be useful for some one. Please again note that this post is for beginners only. Experts obviously won't do such silly mistake!