André Figueira

Systems engineer - I write apps, I make websites, opinions are my own...

View specific Javascript or CSS in Laravel

In almost any application that you build you're going to have functionality or styling on some views which doesn't exist in others, for example a page may have a Javascript Google map being displayed, which won't be used on any other page.

In Laravel we have ViewComposers however, these are not designed to deal with frontend components such as Javascript or CSS. We could code a little helper which adds CSS or Script source links to an array which is then looped through on our layout to print the relevant script or link tags, but this can be a bit cumbersome, and a little against what the ViewComposer documentation mentions.

View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view composer can help you organize that logic into a single location.

So where it will be excellent in defining perhaps a user variable for the currently logged in user so you don't need to fetch that data in every method or controller __construct, it falls short in determining which frontend resources to use, rightly so as it wasn't really designed with this in mind.

So what's the alternative? There are a few options, but I won't be going over all of the other options, just the method I personally prefer, first let's go over what exactly are we trying to do?

1- Include Javascript script tags and CSS link tags on specific views for view specific functionality.

That was simple enough! So we know what we want to do, so script tags and links are html, they are part of our views, so it makes sense that this sort of thing should live in our views, luckily Laravel provides an awesome simple way which is also expressive, and easy to understand and works perfectly for what we're trying to acomplish, and that is Blade Stacks.

It's really simple, in your layout in the head place the following code.

<head>
    @stack('css')
</head>

Now at the bottom of your layout before the </body> tag place the following.

    @stack('scripts')
</body>

Simple enough, now, how do you get the scripts tags or link tags to go to those locations? Easy - in your views where you want to include the specific scripts or CSS simply use the push directive.

@push('scripts')
    <script src="js/dependencies/gmaps/gmap.js"></script>
@endpush

@push('css')
     <link rel="stylesheet" href="css/gmap.css">
@endpush

You could take this a step further and make it easy to include third party Javascript packages by extracting these directives to an include, so if the third party package ever changes, you can simply change it in the include. e.g.

   // resources/views/js/gmaps.blade.php

@push('scripts')
    <script src="js/dependencies/gmaps/gmap.js"></script>
@endpush

@push('css')
    <link rel="stylesheet" href="css/gmap.css">
@endpush

Then in your view in which you're using the package you've defined as an include you simply include it, and you can use the same include anywhere else.

@include('js.gmaps')

The benefits of keeping this kind of thing within the view system instead of, as some other frameworks have done allowing it to be set in the controller by using an addJs or addCss methods, are that the views are more encapsulated, you'll be able to easily interchange them without worrying about defining their Javascript or CSS dependencies anywhere else, it's all in the view and ready to go. Additionally, it keeps your HTML cleaner, without having all your dependencies, etc... included in every single page.