Integrate Grunt JS into Symfony and replace Assetic
Web agency » Digital news » Integrate Grunt JS into Symfony and replace Assetic

Integrate Grunt JS into Symfony and replace Assetic

I knew GruntJS without having ever used it but I would have had to hear from a developer symfony give me the mass so that I look into this solution. First, replace Assetic by GruntJS was for me a solution to make my projects work symfony with HHVM. Now the server PHP de Facebook works perfectly with Assetic but I find fewer and fewer reasons to continue using Assetic. Finally, the use of Grunt, a plugin based on Node JS, drives most developers to use bower, another plugin for managing dependencies. We will talk about bower lower. Let's take a quick look at the pros and cons.

Attention ! Before you start migrating your application, I advise you to version your code and do some testing. Reading the entire article before embarking on this long-term mission is strongly advised.

Introduction

Assetic, the misunderstood friend

For my part, I consider thatAssetic is misunderstood and misused. I will explain my thoughts to you. (In addition, I corrected this article following a misunderstanding on my part, thanks to Manuel Klein for his feedback).

Benefit

The use ofAssetic allows you to cancel the cache on the resources because the name of the generated JS and CSS resources changes each time you launch the command “assetic:dump”. A certain advantage!

Drawbacks
  • Assetic offers few options to configure how resources are generated.
  • It is necessary to install PHP bundles to generate exotic resources like LESS. The PHP code is installed in the vendors while this task is only useful for the client. No for the server. In addition, it increases the number of your project.
  • Code PHP is necessary in the templates Twig using Assetic or almost all of them. Whereas with Grunt, the compiled resource will be called by the name you gave it.

Really use Assetic in your templates

I often see in the templates Twig that I come across, resources linked sometimes via Assetic, sometimes via the assets de Symphony.

1
2
3
4
5
# Using Assetic
@NamespaceMyBundle/Resources/public/css/main.css
# Unused Assetic, using Assets
/bundles/namespacemy/css/main.css

In the first case, Assetic really applies. In the second case, Assetic is completely concealed so as not to use the assets de symfony. The use of assets is also a mistake in my opinion, at least for access to JS and CSS resources. End of parenthesis...

Grunt JS the Sooo flexible compiler!

GruntJS based on Node.js. It is a client-side tool that uses modules to perform many actions such as file concatenation, minification, image compression, compilation of LESS, TypeScript… Unlike Assetic, you will have to set up certain configurations but rest assured, this initial investment will pay off and in the end much faster thanAssetic.

Introduction to Bower, the composer.json of resources

GruntJS is good and comes to be placed on the same segment asAssetic. But as long as you use Node.js, as well use bower ! It is a dependency manager. To put it simply, you define the resources you need, "such library in such version" and bower takes care of getting the version you want. Of course, just like composer.json for PHP, you can add version ranges. If you want a library in version 3.3., *Bower will get you the latest version available. A solution to easily update these resources. A recurring problem on our standard projects because we have (had!) a tendency to download a version and never update it afterwards. We didn't have the minor updates that are sometimes so useful.

Technically, bower uses the bower.json file. Its syntax is very simple. I urge you to use it even if you can go on without it. The file will need to be versioned unlike the resources that bower will come download for you. To get you started, I'll give you an example below.

Versioning compiled resources

For my part, I had got into the habit of not versioning my compiled resources for Assetic but I decided to do the opposite for GruntJS. Since I do without resources to manage by bower (see Introduction to bower), I will compile my resources and gitters. In this way, I can quickly deploy my application. I have never had feedback on this practice but it seems respectable to me because two operations are canceled at the time of deployment (recovery of resources with bower and compile with GruntJS), as well as the need to have Node.js on his machine.

Remove Assetic from our Symfony project

Assetic was chosen to be the default component responsible for compiling resources. Be aware that despite everything, it is very easy to remove.

Delete Blocks Twig Type javascript et Stylesheet. They are not necessary. Keep aside the files you were using. In the future, the files you would like to use will be defined in the file gruntfile.js. We will see that a little later.

1
2
3
4
5
6
7
8
#app/config/config.yml
# Remove configuration from assetic. There will also be some in config_prod.yml, config_dev.yml and other uploaded files
assetic:
debug: “%kernel.debug%”
use_controller: false
bundles: []
filters:
cssrewrite: ~
1
2
3
4
5
#app/AppKernel.php
# Stop loading AsseticBundle by deleting the line from AppKernel
...
new SymfonyBundleAsseticBundleAsseticBundle()
...
1
2
3
4
5
# composer.json
# Remove assetic bundle
...
“symfony/assetic-bundle”: “~2.3”
...

There you go, you have deactivated Assetic globally. In this way, no longer expect to find the command assetic:dump et assetic:watch.

How will Grunt JS work within our project?

We will have to configure our project with three files:

  • package.json which will allow us to install the plugins Node.js (GruntJS and his contributions);
  • bower.json to report on dependencies to be resolved in order to compile our resources;
  • gruntfile.js which you will be working on the most. It will contain all the actions possible and/or to be carried out to compile part or all of your project.

package.json to install Grunt JS

1
2
3
4
5
6
7
8
9
10
11
{
“dependencies”:{
“grunt”: “^0.4.5”,
“grunt-contrib-less”: “~0.11.0”,
“grunt-contrib-uglify”: “^0.6.0”,
“load-grunt-tasks”: “^0.6.0”
},
“devDependencies”:{
“grunt”: “^0.4.5”
}
}

First, use this content. It requires the installation of GruntJS and contributions, two of which (grunt-contrib-less et grunt-contrib-uglify) will allow you to compile your JavaScript files and files Lesscss.

bower.json to solve my dependencies (bootstrap, font-awesome, …)

1
2
3
4
5
6
7
8
9
10
11
12
{
"ignore": [
“**/.*”,
“node_modules”,
“bower_components”,
"Test",
"testing"
],
“dependencies”:{
“bootstrap”: “3.3.*”
}
}

Here is a minimal file. In my case, I requested that the latest version of the 3.3 branch of Bootstrap be downloaded. By default, when you do a bower install your dependencies will be installed in the folder bower_components. Through the use of .bowerrc you can change the destination folder. You can find more information on Bower's website.

1
2
# Install dependencies using Bower
$ bower install

Gruntfile.js – Where it all begins

All of the commands and actions you would like to add that fact in the file gruntfile.js. Among other things, you can compile files lesscss et sass, concatenate any kind of files, compile TypeScript, minify JavaScript files, images as well as HTML files. You can also resize images and copy files (like fonts).

Today I'm just going to show you how to compile files .less and minify files . Js. Actions that I carry out every day and which allow me today to easily use this or that part of bootstrap. Rather than using all of bootstrap when all you need is glyphicons, it may be interesting to work on a custom library.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
module.exports= function (grunt) {
require('load-grunt-tasks')(grunt);
grunt.initConfig({
less:{
dist:{
options:{
compress: true,
yuicompress: true,
optimization: 2
},
files:{
“web/css/main.css”: [
“bower_components/bootsrap/dist/css/bootstrap.css”,
“src/Namespace/MyBundle/Resources/public/css/main.less”
]
}
}
},
uglify:{
options:{
mangrove: false,
sourceMap: true
},
dist:{
files:{
'web/js/main.js': [
'src/Namespace/MyBundle/Resources/public/js/main.js',
]
}
}
}
});
grunt. registerTask('default', [“less”, “uglify”]);
};

Here is a perfectly working file. I also use it on a project with little frame because it is a API. Assetic was in my case quite useless. So I preferred to do without it to use a tool external to the server and deliver the perfectly constructed resources at the time of deployment.

Let's describe the actions for Gruntfile.js

In the previous file, I configure the two contributions of GruntJS (_less _and uglify) that I installed thanks to my package.json. You will notice that the plugins are easily distinguished from each other. Take the case of the extension less.

Each contribution Grunt that you are going to use must be declared via a keyword defined for the contribution. Example, for grunt-contrib-less the key word is less. Under this part, you can define targets. Under the term target understand Subpart. In a concrete case, we could define a target bootstrap to compile the library of the same name from source less. We could define another set dist to compile the sources of our project. The use of several subsets is not a necessity but you will have the opportunity to use them later when you use the contribution watch to save time.

Then the structure of the subsets of the same extension are ISO. At Contrario, the structure of each contribution differs. Standard contributions are often presented with many examples. Official plugins are available on the GitHub repository.

Let's go back to our example and the configuration of the compilation of our files .less. In the game files we add the name of the final files as a key, and as a value, an array of input files to compile. I think it is not necessary to detail more because the syntax is quite intuitive.

Contribution uglify used for concatenation, minification and compression of JavaScript files, uses the same structure. In this case, it is quite simple to use its two contributions.

The art of compiling

And now compilons our sources. With Assetic, we run this command:

1
php app/console assetic:dump

Now we have removed AsseticBundle. We no longer have this order. So we're going to run our plugin from Node.

1
grunt

You see it's still not very complicated... In this case, the tasks that will be executed will be the one given for the profile default. It was defined in the last line.

1
grunt. registerTask('default', [“less”, “uglify”]);

You would have very well defined a profile javascript who would not have executed uglify.

1
grunt. registerTask('javascript', ['uglify']);

In case you could have run the command Grunt with the profile name after.

1
grunt javascript

You can define as many profiles as you want. In the case of my profile javascript, the interest is less because you could also have made the following call.

1
grunt uglify

Conclusion

Now you know how to compile your resources. If you haven't grasped all the subtleties, you should quickly be able to appreciate all the flexibility offered by Grunt with respect toAssetic. What's more, apart from typical resources such as javascript and css, you can also process fonts, images... An asset that quickly won me over.

The real advantage of Grunt is its flexibility its use. Grunt et bower between them embodies an alternative to Assetic. Without bower you can still work with Grunt but the experience will not be total.

I hope this article will allow you to easily understand the use of Grunt. Be brave, you're almost there!

★ ★ ★ ★ ★