I have been programming for the last two months in Symfony.

I use a tool for asset management, called Assetic. The only thing I was stressed about, was that after I change some files or add new ones (javascript/css/less files), I had to execute a set of commands each time to have all assets generated again:

app/console cache:clear app/console assetic:dump app/console assets:install web

My first attemp to automate this, was to build a bash script. It was good, but not perfect. I still had to execute manually a command. I then tried to create a Symfony command that overrided the “app/console assetic:dump –watch”, with no success.

That is why I gave grunt a chance.

I used two plugins:

It took me less than an hour to have a script which watched my current Symfony project and automatically executed the commands necessary to generate the static assets.

The package.json file has all the dependencies needed, so you just have to do npm install to install what is needed to execute Gruntfile.js. Keep in mind that the two files (package.json and Gruntfile.js have to be on your project root).

{
  "name": "assetic-watcher",
  "version": "0.1.0",
  "devDependencies": {
    "grunt-cli": "~0.1.11",
    "grunt": "~0.4.1",
    "grunt-contrib-watch": "~0.5.3",
    "grunt-shell": "~0.6.1",
    "shelljs": "~0.2.6"
  }
}

The Gruntfile.js is the file that will be executed each time you do grunt. In this case, to start the watch mode you have just to do grunt watch, and voilá! It will watch the baseURL we have defined. This is just the script I have created to solve my particularly problem. Feel free to change it to fill your needs.

Gruntfile.js

module.exports = function(grunt) {
    grunt.initConfig({
        baseURL: "src/MyApplication/**/Resources",
        shell: {
            clearCache: {
                options: {
                    stdout: true
                },
                command: 'app/console cache:clear'
            },
            asseticDump: {
                options: {
                    stdout: true
                },
                command: 'app/console assetic:dump <%= dir %>'
            },
            assetsInstall: {
                options: {
                    stdout: true
                },
                command: 'app/console assets:install <%= dir %>'
            }
        },
        watch: {
            options: {
                dateFormat: function(time) {
                    grunt.log.writeln('The watch finished in ' + time + 'ms at' + (new Date()).toString());
                    grunt.log.writeln('Waiting for more changes...');
                }
            },
            branchChanged: { // clear cache if the branch is changed
                files: '.git/HEAD',
                tasks: ['shell:clearCache'],
                options: {
                    spawn: true
                }
            },
            scripts: {
                files: ['<%= baseURL %>/**/*.js',
                        '<%= baseURL %>/**/*.css',
                        '<%= baseURL %>/**/*.sass',
                        '<%= baseURL %>/**/*.less',
                        '<%= baseURL %>/**/*.twig'],
                tasks: ['shell:asseticDump', 'shell:assetsInstall'],
                options: {
                    interrupt: true
                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-shell');
    grunt.registerTask('default', ['shell:asseticDump', 'shell:assetsInstall']);

    grunt.registerTask('dump', 'A task to dump all assets.', function() {
        grunt.task.run("shell:asseticDump");
        grunt.task.run("shell:assetsInstall");
    });

    grunt.registerTask('all', 'A task to dump all assets and clear cache.', function() {
        grunt.task.run("shell:clearCache");
        grunt.task.run("shell:asseticDump");
        grunt.task.run("shell:assetsInstall");
    });

    grunt.registerTask('setDir', 'A task to set the web dir of the project.', function() {
        grunt.config.set("dir", "web");        
        grunt.log.writeln("DIR: " + grunt.config.get("dir"));
        grunt.log.writeln("BASE_URL: " + grunt.config.get("baseURL"));
    });

    console.info("BASE_URL: " + grunt.config.get("watch").scripts.files[0]);
    grunt.task.run(['setDir']);
}

Conclusions

The grunt tool is great! I don’t have to execute the same commands anymore to generate assets. After it detects the change of a file, it will generate all the assets automatically.