8000 [Asset] Add support for preloading with links and HTTP/2 push by dunglas · Pull Request #21478 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Asset] Add support for preloading with links and HTTP/2 push #21478

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 16 commits into from
Closed
Prev Previous commit
Next Next commit
Make the preload manager independant of HTTP Foundation
  • Loading branch information
dunglas committed Feb 7, 2017
commit 9c11a0fd25fc25774867b0c1e4d0fe357cccd262
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

use Symfony\Bridge\Twig\Extension\AssetExtension;
use Symfony\Component\Asset\Packages;
use Symfony\Component\Asset\Preload\HttpFoundationPreloadManager;
use Symfony\Component\Asset\Preload\PreloadManager;

/**
* @author Kévin Dunglas <dunglas@gmail.com>
Expand All @@ -22,7 +22,7 @@ class AssetExtensionTest extends \PHPUnit_Framework_TestCase
{
public function testGetAndPreloadAssetUrl()
{
$preloadManager = new HttpFoundationPreloadManager();
$preloadManager = new PreloadManager();
$extension = new AssetExtension(new Packages(), $preloadManager);

$this->assertEquals('/foo.css', $extension->preload('/foo.css', 'style', true));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use Doctrine\Common\Annotations\Reader;
use Symfony\Bridge\Monolog\Processor\DebugProcessor;
use Symfony\Component\Asset\EventListener\PreloadListener;
use Symfony\Component\Asset\Preload\HttpFoundationPreloadManager;
use Symfony\Component\Asset\Preload\PreloadManager;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\Alias;
Expand Down Expand Up @@ -766,8 +766,8 @@ private function registerAssetsConfiguration(array $config, ContainerBuilder $co
$defaultVersion = $this->createVersion($container, $config['version'], $config['version_format'], '_default');
}

if (class_exists(HttpFoundationPreloadManager::class)) {
$preloadManagerDefinition = $container->register('assets.preload_manager', HttpFoundationPreloadManager::class);
if (class_exists(PreloadManager::class)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing class existence resource (or you could just conflict with asset < 3.3, and have all this in the XML file directly)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get what you mean. But if it's ok to bump the dependency, I'll move this definition to the XML, it's cleaner.

$preloadManagerDefinition = $container->register('assets.preload_manager', PreloadManager::class);
$preloadManagerDefinition->setPublic(false);

$preloadListener = $container->register('asset.preload_listener', PreloadListener::class);
Expand Down
8 changes: 4 additions & 4 deletions src/Symfony/Component/Asset/EventListener/PreloadListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,28 @@

namespace Symfony\Component\Asset\EventListener;

use Symfony\Component\Asset\Preload\HttpFoundationPreloadManager;
use Symfony\Component\Asset\Preload\PreloadManager;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
* Adds preload's Link HTTP headers to the response.
* Adds the preload Link HTTP header to the response.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class PreloadListener implements EventSubscriberInterface
{
private $preloadManager;

public function __construct(HttpFoundationPreloadManager $preloadManager)
public function __construct(PreloadManager $preloadManager)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the typehint must use the interface

{
$this->preloadManager = $preloadManager;
}

public function onKernelResponse(FilterResponseEvent $event)
{
$this->preloadManager->setLinkHeader($event->getResponse());
$event->getResponse()->headers->set('Link', $this->preloadManager->getLinkValue());

// Free memory
$this->preloadManager->setResources(array());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@
namespace Symfony\Component\Asset\Preload;

use Symfony\Component\Asset\Exception\InvalidArgumentException;
use Symfony\Component\HttpFoundation\Response;

/**
* Preload manager for the HttpFoundation component.
* Manages preload HTTP headers.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class HttpFoundationPreloadManager implements PreloadManagerInterface
class PreloadManager implements PreloadManagerInterface
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be final

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would forbid decoration for no reason imho - see comments on the interface: building a profiler panel could require decorating this class

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant decoration by inheritance of course.
My root issue is that final here would be only forbidding use cases while providing no benefit for us.
"final" should only used on method/classes that are not bound by any contract - like data objects.
When an interface covers the said methods, the contract is already enforced and inheritance should not be prevented.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My root issue is that final here would be only forbidding use cases while providing no benefit for us.

There are 2 benefits:

When an interface covers the said methods, the contract is already enforced and inheritance should not be prevented.

I don't see connection between contract enforcing and "inheritance should not be prevented". I'd say the opposite. See similar opinion, for example: http://ocramius.github.io/blog/when-to-declare-classes-final/ /cc @Ocramius

{
private $resources = array();

Expand Down Expand Up @@ -62,14 +61,12 @@ public function setResources(array $resources)
}

/**
* Sets preload Link HTTP header.
*
* @param Response $response
* {@inheritdoc}
*/
public function setLinkHeader(Response $response)
public function getLinkValue()
{
if (!$this->resources) {
return;
return null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

$parts = array();
Expand All @@ -86,6 +83,6 @@ public function setLinkHeader(Response $response)
$parts[] = $part;
}

$response->headers->set('Link', implode(',', $parts));
return implode(',', $parts);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,11 @@ public function getResources();
* @param array $resources
*/
public function setResources(array $resources);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have any use case for replacing all resources, except for clearing ? If no, we could simplify the code by allowing only clearing


/**
* Gets the value of the preload Link HTTP header.
*
* @return string|null
*/
public function getLinkValue();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think getLinkHeader (or buildLinkHeader) might be a better name

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace Symfony\Component\Asset\Tests\EventListener;

use Symfony\Component\Asset\EventListener\PreloadListener;
use Symfony\Component\Asset\Preload\HttpFoundationPreloadManager;
use Symfony\Component\Asset\Preload\PreloadManager;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
Expand All @@ -25,7 +25,7 @@ class PreloadListenerTest extends \PHPUnit_Framework_TestCase
{
public function testOnKernelResponse()
{
$manager = new HttpFoundationPreloadManager();
$manager = new PreloadManager();
$manager->addResource('/foo');

$subscriber = new PreloadListener($manager);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class HttpFoundationPreloadManagerTest extends \PHPUnit_Framework_TestCase
class PreloadManagerTest extends \PHPUnit_Framework_TestCase
{
public function testManageResources()
{
$manager = new HttpFoundationPreloadManager();
$manager = new PreloadManager();
$this->assertInstanceOf(PreloadManagerInterface::class, $manager);

$manager->setResources(array('/foo/bar.js' => array('as' => 'script', 'nopush' => false)));
Expand All @@ -33,10 +33,7 @@ public function testManageResources()
'/foo/bat.png' => array('as' => 'image', 'nopush' => true),
), $manager->getResources());

$response = new Response();
$manager->setLinkHeader($response);

$this->assertEquals('</foo/bar.js>; rel=preload; as=script,</foo/baz.css>; rel=preload,</foo/bat.png>; rel=preload; as=image; nopush', $response->headers->get('Link'));
$this->assertEquals('</foo/bar.js>; rel=preload; as=script,</foo/baz.css>; rel=preload,</foo/bat.png>; rel=preload; as=image; nopush', $manager->getLinkValue());
}

/**
Expand All @@ -45,7 +42,7 @@ public function testManageResources()
*/
public function testInvalidResources($resources)
{
$manager = new HttpFoundationPreloadManager();
$manager = new PreloadManager();
$manager->setResources($resources);
}

Expand Down
0