framework: [5.4] Blade @stack order undocumented breaking change

  • Laravel Version: 5.4
  • PHP Version: 5.6
  • Database Driver & Version: N/A

Description:

I’ve just updated from 5.3. to 5.4 and #16325 has introduced an undocumented breaking change.

Consider

// layout.blade.php
@push('js')
<script src="jquery.js"></script>
@endpush

@stack('js')
// child.blade.php
@extends('layout')

@push('js')
<script src="script-that-depends-on-jquery.js"></script>
@endpush

In 5.3, this would work. In 5.4, it does not. The 5.3 functionality is obviously what is desired: adding common scripts to the layout that are always required, such as jquery, and then pushing to the stack in the called child view to add scripts specific to that view. With this broken in 5.4, I’m not sure what the utility of the stack actually is.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 3
  • Comments: 15 (14 by maintainers)

Most upvoted comments

If we have a choice to decide either append or prepend on stack/push will be the best!

@taylorotwell Yes, perhaps that example was too simple. Here’s a better one:

// top.blade.php
<script src="jquery.js"></script>
<link href="main.css" rel="stylesheet">
@stack('test')
// middle.blade.php
@extends('top')

@push('test')
<script src="script-that-depends-on-jquery.js"></script>
<link href="css-that-overrides-main.css" rel="stylesheet">
@endpush
// bottom.blade.php
@extends('middle')

@push('test')
<script src="script-that-depends-on-script-in-middle.js"></script>
<link href="css-that-overrides-middle.css" rel="stylesheet">
@endpush
view('bottom')

Now that there are three levels, the inheritance order requirement becomes more apparent. Perhaps it could be argued that this is now less likely to be encountered, maybe even contrived, as I don’t think inheriting more than one level is super common, but it is still possible in Laravel and ocassionally useful. In this situation, I think it is clear what the developer is wanting to happen, but to achieve it, it has to be changed to:

// top.blade.php
<script src="jquery.js"></script>
<link href="main.css" rel="stylesheet">
@yield('test')
// middle.blade.php
@extends('top')

@section('test')
<script src="script-that-depends-on-jquery.js"></script>
<link href="css-that-overrides-main.css" rel="stylesheet">
@endsection
// bottom.blade.php
@extends('middle')

@section('test')
@parent
<script src="script-that-depends-on-script-in-middle.js"></script>
<link href="css-that-overrides-middle.css" rel="stylesheet">
@endsection

which is fine, works, and is what we were doing before @stack was introduced. I just feel that this inconsistency in the way @stack works depending on whether you are using @layout/@section or @component/@slot is a bit awkward. Perhaps it has to be too many things to too many people: to those using each type of inheritance model, as well as to those expecting it to facilitate the example above and to those expecting it to rigidly push in the order it is called.

Hopefully you can see where I’m coming from with this, and apologies for confusing what I’m trying to exhibit here with my over-simplified initial example.