-
-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature #61 New preload option to automatically set preload Link head…
…er for rendered scripts/styles (weaverryan) This PR was merged into the master branch. Discussion ---------- New preload option to automatically set preload Link header for rendered scripts/styles Fixes #14 This adds a new configuration option: ```yml webpack_encore: # ... preload: true ``` When enabled, it automatically adds a `preload` entry to the Link header for every JavaScript and CSS file that was rendered - for example: <img width="1225" alt="Screen Shot 2019-04-11 at 11 51 36 AM" src="https://user-images.githubusercontent.com/121003/55983583-4cf87080-5c50-11e9-9305-92998ab47d93.png"> What I need is just some validation on this approach and that the Link header looks right ;). Cheers! Commits ------- 0778950 New preload option to automatically set preload Link header for rendered scripts/styles
- Loading branch information
Showing
10 changed files
with
342 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony WebpackEncoreBundle package. | ||
* (c) Fabien Potencier <[email protected]> | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\WebpackEncoreBundle\EventListener; | ||
|
||
use Fig\Link\GenericLinkProvider; | ||
use Fig\Link\Link; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent; | ||
use Symfony\WebpackEncoreBundle\Asset\TagRenderer; | ||
|
||
/** | ||
* @author Ryan Weaver <[email protected]> | ||
*/ | ||
class PreLoadAssetsEventListener implements EventSubscriberInterface | ||
{ | ||
private $tagRenderer; | ||
|
||
public function __construct(TagRenderer $tagRenderer) | ||
{ | ||
$this->tagRenderer = $tagRenderer; | ||
} | ||
|
||
public function onKernelResponse(FilterResponseEvent $event) | ||
{ | ||
if (!$event->isMasterRequest()) { | ||
return; | ||
} | ||
|
||
$request = $event->getRequest(); | ||
|
||
if (null === $linkProvider = $request->attributes->get('_links')) { | ||
$request->attributes->set('_links', new GenericLinkProvider()); | ||
} | ||
|
||
/** @var GenericLinkProvider $linkProvider */ | ||
$linkProvider = $request->attributes->get('_links'); | ||
$defaultAttributes = $this->tagRenderer->getDefaultAttributes(); | ||
$crossOrigin = $defaultAttributes['crossorigin'] ?? false; | ||
|
||
foreach ($this->tagRenderer->getRenderedScripts() as $href) { | ||
$link = (new Link('preload', $href))->withAttribute('as', 'script'); | ||
|
||
if (false !== $crossOrigin) { | ||
$link = $link->withAttribute('crossorigin', $crossOrigin); | ||
} | ||
|
||
$linkProvider = $linkProvider->withLink($link); | ||
} | ||
|
||
foreach ($this->tagRenderer->getRenderedStyles() as $href) { | ||
$link = (new Link('preload', $href))->withAttribute('as', 'style'); | ||
|
||
if (false !== $crossOrigin) { | ||
$link = $link->withAttribute('crossorigin', $crossOrigin); | ||
} | ||
|
||
$linkProvider = $linkProvider->withLink($link); | ||
} | ||
|
||
$request->attributes->set('_links', $linkProvider); | ||
} | ||
|
||
public static function getSubscribedEvents() | ||
{ | ||
return [ | ||
// must run before AddLinkHeaderListener | ||
'kernel.response' => ['onKernelResponse', 50], | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony WebpackEncoreBundle package. | ||
* (c) Fabien Potencier <[email protected]> | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\WebpackEncoreBundle\Tests\Asset; | ||
|
||
use Fig\Link\GenericLinkProvider; | ||
use Fig\Link\Link; | ||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\HttpFoundation\Response; | ||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent; | ||
use Symfony\Component\HttpKernel\HttpKernelInterface; | ||
use PHPUnit\Framework\TestCase; | ||
use Symfony\WebpackEncoreBundle\Asset\TagRenderer; | ||
use Symfony\WebpackEncoreBundle\EventListener\PreLoadAssetsEventListener; | ||
|
||
class PreLoadAssetsEventListenerTest extends TestCase | ||
{ | ||
public function testItPreloadsAssets() | ||
{ | ||
$tagRenderer = $this->createMock(TagRenderer::class); | ||
$tagRenderer->expects($this->once())->method('getDefaultAttributes')->willReturn(['crossorigin' => 'anonymous']); | ||
$tagRenderer->expects($this->once())->method('getRenderedScripts')->willReturn(['/file1.js']); | ||
$tagRenderer->expects($this->once())->method('getRenderedStyles')->willReturn(['/css/file1.css']); | ||
|
||
$request = new Request(); | ||
$response = new Response(); | ||
$event = new FilterResponseEvent( | ||
$this->createMock(HttpKernelInterface::class), | ||
$request, | ||
HttpKernelInterface::MASTER_REQUEST, | ||
$response | ||
); | ||
$listener = new PreLoadAssetsEventListener($tagRenderer); | ||
$listener->onKernelResponse($event); | ||
$this->assertTrue($request->attributes->has('_links')); | ||
/** @var GenericLinkProvider $linkProvider */ | ||
$linkProvider = $request->attributes->get('_links'); | ||
$this->assertInstanceOf(GenericLinkProvider::class, $linkProvider); | ||
/** @var Link[] $links */ | ||
$links = array_values($linkProvider->getLinks()); | ||
$this->assertCount(2, $links); | ||
$this->assertSame('/file1.js', $links[0]->getHref()); | ||
$this->assertSame(['preload'], $links[0]->getRels()); | ||
$this->assertSame(['as' => 'script', 'crossorigin' => 'anonymous'], $links[0]->getAttributes()); | ||
|
||
$this->assertSame('/css/file1.css', $links[1]->getHref()); | ||
$this->assertSame(['preload'], $links[1]->getRels()); | ||
$this->assertSame(['as' => 'style', 'crossorigin' => 'anonymous'], $links[1]->getAttributes()); | ||
} | ||
|
||
public function testItReusesExistingLinkProvider() | ||
{ | ||
$tagRenderer = $this->createMock(TagRenderer::class); | ||
$tagRenderer->expects($this->once())->method('getDefaultAttributes')->willReturn(['crossorigin' => 'anonymous']); | ||
$tagRenderer->expects($this->once())->method('getRenderedScripts')->willReturn(['/file1.js']); | ||
$tagRenderer->expects($this->once())->method('getRenderedStyles')->willReturn([]); | ||
|
||
$request = new Request(); | ||
$linkProvider = new GenericLinkProvider([new Link('preload', 'bar.js')]); | ||
$request->attributes->set('_links', $linkProvider); | ||
|
||
$response = new Response(); | ||
$event = new FilterResponseEvent( | ||
$this->createMock(HttpKernelInterface::class), | ||
$request, | ||
HttpKernelInterface::MASTER_REQUEST, | ||
$response | ||
); | ||
$listener = new PreLoadAssetsEventListener($tagRenderer); | ||
$listener->onKernelResponse($event); | ||
/** @var GenericLinkProvider $linkProvider */ | ||
$linkProvider = $request->attributes->get('_links'); | ||
$this->assertCount(2, $linkProvider->getLinks()); | ||
} | ||
|
||
public function testItDoesNothingOnSubRequest() | ||
{ | ||
$tagRenderer = $this->createMock(TagRenderer::class); | ||
$tagRenderer->expects($this->never())->method('getDefaultAttributes'); | ||
$tagRenderer->expects($this->never())->method('getRenderedScripts'); | ||
|
||
$request = new Request(); | ||
$response = new Response(); | ||
$event = new FilterResponseEvent( | ||
$this->createMock(HttpKernelInterface::class), | ||
$request, | ||
HttpKernelInterface::SUB_REQUEST, | ||
$response | ||
); | ||
$listener = new PreLoadAssetsEventListener($tagRenderer); | ||
$listener->onKernelResponse($event); | ||
} | ||
} |
Oops, something went wrong.