Yesterday at the university we were introduced to gulp.js. In an example we created some tasks for concatenating and minifying/uglifying JavaScript assets – quite the usual stuff you’ll use Assetic for in your Symfony projects.
But we also created a task which piped the assets through JsHint to perform code (quality) analysis. I really liked the idea of having an analysis run on your code on compilation time, so I looked for an existing JsHint filter for Assetic. Since I couldn’t find any (in an admittedly short Google search), I decided to quickly implement one on my own:
https://github.com/CodeLoversAt/assetic-jshint will pass the given asset through JsHint and throw a FilterException
if any errors occurr. Since you might be interested in the actual file that produced the error, this filter will only work with a temporary file if it cannot determine the asset’s file name (like if you pass in an instance of a StringAsset
).
As I mentioned in the first paragraph, I thought of using this filter in our Symfony projects from the beginning, so unsurprisingly I’ve also created a Symfony bundle which registers that filter:
https://github.com/CodeLoversAt/assetic-jshint-bundle
Here’s some example usage:
Lets consider the following two scripts. The first is called valid.js
and it contains – as you might have guessed already – some simple, valid JavaScript
(function() { alert('I am valid!'); })();
The second one is called invalid.js
and there we’ve forgotten a semicolon.
(function() { alert('I am invalid because I'm missing a semicolon at the end of this line!') })();
Now we want to use this scripts in a template. First the valid one:
{% javascripts '@CodeLoversDemoBundle/Resources/public/js/valid.js' output='compiled/js/demo_script.js' filter='jshint' %} <script type="text/javascript" src="{{ asset_url }}"></script> {% endjavascripts %}
When we run app/console assetic:dump
now, we won’t notice any difference, since the filter doesn’t have anything to complain about:
[email protected]:~/symfony$ app/console assetic:dump --env=prod --no-debug Dumping all prod assets. Debug mode is off. 13:26:13 [file+] /var/www/clients/client1/web65/symfony/app/../web/compiled/js/demo_script.js [email protected]:~/symfony$
Now let’s see what happens if we add the invalid file to that asset:
{% javascripts '@CodeLoversDemoBundle/Resources/public/js/valid.js' '@CodeLoversDemoBundle/Resources/public/js/invalid.js' output='compiled/js/demo_script.js' filter='jshint' %} <script type="text/javascript" src="{{ asset_url }}"></script> {% endjavascripts %}
Again, we dump the assets, and here we go: a beautiful error appears:
[email protected]:~/symfony$ app/console assetic:dump --env=prod --no-debug Dumping all prod assets. Debug mode is off. 13:26:58 [file+] /var/www/clients/client1/web65/symfony/app/../web/compiled/js/demo_script.js [Assetic\Exception\FilterException] An error occurred while running: '/usr/local/bin/jshint' '/var/www/clients/client1/web65/symfony/src/CodeLov ers/DemoBundle/Resources/public/js/invalid.js' Output: /var/www/clients/client1/web65/symfony/src/CodeLovers/DemoBundle/Resources/ public/js/invalid.js: line 3, col 84, Missing semicolon. 1 error Input: // some invalid JavaScript code (function() { alert('I am invalid because I\'m missing a semicolon at the end of this line!') })(); assetic:dump [--watch] [--force] [--period="..."] [write_to] [email protected]:~/symfony$
As you can see, the error contains the real file name, where the error occurred. This should be quite helpful in real life scenarios.