Managing assets with Laravel 4

Generally assets are stored in your public directory, right? They are public, so anyone can get access to them. But nowadays the performance is a very important factor when deploying a new app. I strongly recommend you to minify and cache your assets, like CSS files, Javascript files and Images.

If you are using 11 javascript files in your app you don’t have to make 11 requests on the server, one per JS files. You can easily join all files and minify them, so you will have just one minified file. This is easy to do using Laravel 4! I’ve found four Laravel 4 assets managers:

We will work with codesleeve/asset-pipeline package. It’s easy to use and simple to understand.

Installation

Let’s suppose you already have a Laravel 4 working. First, using Composer, you have to install the package. So, open your composer.json and add the package information to install it:

{ 
    ... 
    "require": { 
        "laravel/framework": "4.0.*", 
        "codesleeve/asset-pipeline": "dev-master" 
    }, 
    ... 
}

Now on the terminal update your composer. composer update Now you have to tell Laravel you are using this asset management package. So, open your app/config/app.php and add this line inside the providers block:

'Codesleeve\AssetPipeline\AssetPipelineServiceProvider',

Creating the assets directory

Now, on the terminal type a artisan command (from the package we’ve installed):

php artisan assets:setup

This will create the app/assets folder. Inside it you will find 2 new directories: javascripts and stylesheets. Inside each one you will find a file called “application” (application.css and application.js). These are our manifest files. You will understand what a “manifest” file is later. So we have the follow structure:

  • /app
    • assets
      • javascripts
        • application.js
      • stylesheets
        • application.css

The package “logic”

In a easy way what the package does is to get the assets files content, join them, minify them and save the result. So, the package will get your “assets file list”, get the content one by one, concatenate them and run a CSS minify or JS minify algorithm, provided by some PHP class.

The base assets route

By default the package will use the route http://example.org/assets/application.(js|css). You can find it in the routes list:

php artisan routes

You can find a GET /assets/{path} route. You can change that for what you want. Let’s suppose you want /static/application.js for example. You only have to change the package config file. First you have to install this config file, so run the follow artisan command:

php artisan config:publish codesleeve/asset-pipeline

This will create the app/config/packages/codesleeve/asset-pipeline/config.php. You can change the route you want and other options inside this config file.

Testing

Now, go to http://yoursite.org/assets/application.js and see the result. ATTENTION: if you got a 404 error you are doing something wrong, check:

  1. You have a assets directory inside your public dir. If you have one, please, change its name to, for example, assets2, just for now.
  2. You are using the PHP 5.4+ built-in server the wrong way. I had a BIG problem with this. You cannot start the PHP server (with Laravel 4) this wayphp -S localhost:8000 -t public.

You MUST use the server.php file that Laravel 4 provides you, so you must start the PHP server this way: php -S localhost:8000 server.php. Now you can see the http://yoursite.org/assets/application.js file, but with the default content.

Copying your assets file you already are using

You can copy the css and js files you are using to the respective directories inside app/assets folder. Copy them, and open your website and check the code. You will se all the JS and the CSS files. If you are using your environment as “production” you will see all files concatenated in only one. The package show all files for “testing” or “development” environments and just one for the “production” one.

Setting the file ordering

We’ve talking about the MANIFEST file, right? Manifest file is the file that will control the order to load each asset file (JS or CSS). Open the app/assets/javascripts/application.js. You will see something like this:

// This is a manifest file that'll be compiled into application.js, which will include all the files 
// listed below. 
// 
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 
// can be referenced here using a relative path. 
// 
// It's not advisable to add code directly here, but if you do, it'll appear in whatever order it 
// gets included (e.g. say you have require_tree . then the code will appear after all the directories 
// but before any files alphabetically greater than 'application.js' 
// 
// The available directives right now are require, require_directory, and require_tree 
//  
//= require_tree . The line where you have

= require_tree . is telling the asset manager to load all files inside the javascripts directory in alphabetic order. If you want to set a custom order you can write something like that:

//= require ./jquery 
//= require ./some-lib 
//= require ./another-lib

Now you will have all files you specified inside the MANIFEST file minified and being managed by the package. Now, you can do the same for CSS files. The package has more options like cache, etc. You can check the package’s configuration file and found more details there. Be happy!

Published by

Junior Grossi

senior software engineer & stutterer conference speaker. happy husband & dad. maintains Corcel PHP, elePHPant.me and PHPMG. Engineering Manager @ Paddle

38 thoughts on “Managing assets with Laravel 4”

  1. How to avoid browser cache after updating some css/javascript? There is no way to pass ‘version’ parameter to stylesheet_link_tag or javascript_include_tag functions. It could send assets in this way ‘application.css?v=1.0.0’ instead of ‘application.css’.

    1. Hi Karolis!

      I’ve had problems with Nginx and Vagrant environment, with “sendfiles on” inside Nginx configuration file. Except that I have no problem with browser cache, just refreshing the page. But you can change the file name, generating a random filename everytime you make some change, but I think there are better options instead of that.

      Thanks for the comment!

      1. You can’t ask your website visitors to disable their cache on your site. This needs to have built-in cache-busting to be effective.

  2. How do you choose which file to add, for example: I have two html files admin and home, in admin I want to add just admin.css and in home just home.css, how do I do that? If I add both css files in application.css and then add them with {{ stylesheet_link_tag() }} they both will appear in admin.html and home.html.

    1. hey! check out the package docs. you can inform the files you want as function parameter: stylesheet_link_tag('file1', 'file2')

      thanks for the comment.

  3. Do you happen to know if there’s an easy way to make the application.css and application.js files cache in the browser? I can’t for the life of me get it to work.

    1. @matt, I think it is done by default, but you can cache using your webserver, like apache or nginx.

      you can find interesting blog posts about cache using webservers on the web.

      thanks for the comment

  4. Hi, I set up assets-pipeline and everything is working correctly…well except that changes i make to my css and javascript does not show up till I run php artisan assets:clean command.

    Do i really have to do this for every single change made to my .css or .js?

    1. Hi Tochie! Thank you for the comment.

      The idea behind the assets-pipeline is to join, minify the files and cache them inside app/storage/cache/assets-pipeline. So every change you do to your assets file you have to clean the cache ๐Ÿ™‚

      Thank you again. Cheers!

  5. Thanks for the article! Would be nice if you could cross out or add a note about Basset since it’s no longer maintained and will not fully work with Laravel 4.1.

    Including Basset in the composer.json will do fine but will crash if run the artisan command “basset:build –production”. That could really throw people off successfully configuring everything up with Basset, only to realize that it crashes when doing a production build.

    Cheers!

  6. Thank you for this!
    For some reason i cant get to require jquery-ui as unminified, it load the minified version well but why it does not load the unminified version?

    1. Hi!!!

      Thank you for the comment and welcome to the blog. I think when you add the jquery-ui it is loading the unminified version, unless you explicit you want the minified one. The package will minified everything, css and js files.

      Best regards!

  7. Found this post looking for a solution on how to marry my front-end with my back-end workflows and I also found that there’s a new (really, like 2 months) kid on the block: https://github.com/AndreasH

    Still can’t tell if it’s good or not, though.

    Cheers!

    1. Thank you Matheus! Thanks for the comment and for sharing the new package.

      I’ll take a look on it! Cheers!

  8. my laravel version is 4.1,

    D:webmyproj>php artisan assets:generate

    [InvalidArgumentException]
    Command “assets:generate” is not defined.

    Did you mean one of these?
    key:generate
    assets:clean
    assets:setup
    asset:publish

    why?

    1. Hi Byron!

      Have you updated composer with the assets package? Try php artisan list to see the commands you have installed. If the assets:generate is not listed there maybe you’ve not installed the packages correctly!

      Thanks and welcome to the blog.

      1. assets:generate has been changed to assets:setup

        This is because assets:generate is going to be used to create static files in your /public/assets directory for those who just want static assets.

  9. thanks for the post. A couple of comments (realizing that this was posted +2 months ago)

    the PHP web server can be started in a much easier way than you show.

    php artisan.phar serve

    (of course even easier if you rename and alias artisan.phar)

    @Ivan there are Nginx instructions in the Git readme.md now. I use Nginx and it works fine with these instructions

    Basset is no longer being maintained. The author wants you to use grunt

    Installing asset-pipeline via Composer is easier now, you don’t need to manually enter other packages. Do check out https://github.com/CodeSlee… for a problem with php-min, though. You can solve it by changing your composer.json options or by adding php-min before asset-pipeline in your require

  10. I tried to make asset-pipeline work with shared hosts using apache (copy the public folder to www, move the apps in seperate folder, and link the paths, works fine till the assets not found). Can you help me ?

    1. the path refer to “/assets/application.css”, but I can access the file “index.php/assets/application.css”. I use .htaccess to hide index.php in the address, but if I delete .htaccess, still the same ๐Ÿ™

      1. Hi Oizawa!

        I think this is a .htaccess error. You can try to check the Laravel routes php artisan routes. Maybe the route is not working.

        Thank you for the comment. []s

          1. Maybe it’s your Apache production server configuration. If it’s working on local environment, if you have the same configuration in the production server it should be working.

    2. I am having the same problem…except I can’t view the file through index.php either. Debugbar says the action is : CodesleeveAssetPipelineAssetPipelineController@file

      It just gives me a 404 error though…

      1. Hi John. Check your routes first. You must have an assets route defined. Check it with php artisan routes. Cheers

  11. I couldn’t install this package at first, as it seems it depends on two other packages, codesleeve/sprockets & nitra/php-min which need to be installed first. As per the readme.md at the github page, I have also used the latest version (v1.4.4 atow). When I updated my composer.json file to the following:

    "require": {
    "laravel/framework": "4.1.*",
    "codesleeve/sprockets": "dev-master",
    "nitra/php-min": "dev-master",
    "codesleeve/asset-pipeline": "v1.4.4"
    },

    …it works ๐Ÿ™‚

  12. Why would you want every request for an asset to run through Laravel using the routes? For better performance it would make more sence to have it serve up static, already packaged and minified, assets using Apache or Nginx and not have it run through Laravel. Like what Basset does.

    1. Hi Torann!

      The asset-pipeline package does like Rails does, making the assets dynamic, but cached. I totally agree with you that make the file static is better because of performance issues.

      Thank you so much for the contribution!

      Best regards!

    1. Hi Ivan! I am currently running Nginx and it works! Maybe you need some special configuration but it works ๐Ÿ˜‰

      Best regards!

  13. Thanks for the post, this saved me some time. I am new to Laravel, moving over from CodeIgniter and my base .htaccess did not do a rewrite for requests heading for the assets folder. It took a minute to figure it out but starting up the Laravel server.php and having it work in there helped to pinpoint the problem. Keep up the great posts!

Leave a Reply

Your email address will not be published. Required fields are marked *