diff --git a/composer.json b/composer.json index 75de367..7314d60 100644 --- a/composer.json +++ b/composer.json @@ -17,14 +17,14 @@ } ], "require": { - "php" : "^7.0|^8.0", - "illuminate/support": "~6.0|~7.0|~8.0", - "illuminate/http": "~6.0|~7.0|~8.0", - "symfony/dom-crawler": "^2.7|^3.0|^4.0|^5.0", - "symfony/css-selector": "^2.7|^3.0|^4.0|^5.0" + "php" : "^7.0|^8.0|^8.1|^8.2", + "illuminate/support": "~6.0|~7.0|~8.0|~9.0|~10.0", + "illuminate/http": "~6.0|~7.0|~8.0|~9.0|~10.0", + "symfony/dom-crawler": "^2.7|^3.0|^4.0|^5.0|^6.0", + "symfony/css-selector": "^2.7|^3.0|^4.0|^5.0|^6.0" }, "require-dev": { - "phpunit/phpunit": "^8.5", + "phpunit/phpunit": "^9.5", "scrutinizer/ocular": "^1.1" }, "autoload": { @@ -39,5 +39,12 @@ }, "scripts": { "test": "phpunit" + }, + "extra": { + "laravel": { + "providers": [ + "JacobBennett\\Http2ServerPush\\ServiceProvider" + ] + } } } diff --git a/src/Middleware/AddHttp2ServerPush.php b/src/Middleware/AddHttp2ServerPush.php index 23db2ee..06b31e2 100644 --- a/src/Middleware/AddHttp2ServerPush.php +++ b/src/Middleware/AddHttp2ServerPush.php @@ -54,9 +54,15 @@ protected function generateAndAttachLinkHeaders(Response $response, $limit = nul { $excludeKeywords = $excludeKeywords ?? $this->getConfig('exclude_keywords', []); $headers = $this->fetchLinkableNodes($response) - ->flatten(1) - ->map(function ($url) { - return $this->buildLinkHeaderString($url); + ->flatMap(function ($element) { + list($src, $href, $data, $rel, $type) = $element; + $rel = $type === 'module' ? 'modulepreload' : $rel; + + return [ + $this->buildLinkHeaderString($src ?? '', $rel ?? null), + $this->buildLinkHeaderString($href ?? '', $rel ?? null), + $this->buildLinkHeaderString($data ?? '', $rel ?? null), + ]; }) ->unique() ->filter(function($value, $key) use ($excludeKeywords){ @@ -69,7 +75,8 @@ protected function generateAndAttachLinkHeaders(Response $response, $limit = nul } return !preg_match('%('.$exclude_keywords->implode('|').')%i', $value); }) - ->take($limit); + ->take($limit) + ->merge($this->getConfig('default_headers', [])); $sizeLimit = $sizeLimit ?? max(1, intval($this->getConfig('size_limit', 32*1024))); $headersText = trim($headers->implode(',')); @@ -112,7 +119,7 @@ protected function fetchLinkableNodes($response) { $crawler = $this->getCrawler($response); - return collect($crawler->filter('link:not([rel*="icon"]), script[src], img[src], object[data]')->extract(['src', 'href', 'data'])); + return collect($crawler->filter('link:not([rel*="icon"]):not([rel="preconnect"]):not([rel="canonical"]):not([rel="manifest"]):not([rel="alternate"]), script[src], *:not(picture)>img[src]:not([loading="lazy"]), object[data]')->extract(['src', 'href', 'data', 'rel', 'type'])); } /** @@ -122,18 +129,21 @@ protected function fetchLinkableNodes($response) * * @return string */ - private function buildLinkHeaderString($url) + private function buildLinkHeaderString($url, $rel = 'preload') { $linkTypeMap = [ - '.CSS' => 'style', - '.JS' => 'script', - '.BMP' => 'image', - '.GIF' => 'image', - '.JPG' => 'image', - '.JPEG' => 'image', - '.PNG' => 'image', - '.SVG' => 'image', - '.TIFF' => 'image', + '.CSS' => 'style', + '.JS' => 'script', + '.BMP' => 'image', + '.GIF' => 'image', + '.JPG' => 'image', + '.JPEG' => 'image', + '.PNG' => 'image', + '.SVG' => 'image', + '.TIFF' => 'image', + '.WEBP' => 'image', + '.WOFF' => 'font', + '.WOFF2' => 'font', ]; $type = collect($linkTypeMap)->first(function ($type, $extension) use ($url) { @@ -148,8 +158,12 @@ private function buildLinkHeaderString($url) $basePath = $this->getConfig('base_path', '/'); $url = $basePath . ltrim($url, $basePath); } + + if(!in_array($rel, ['preload', 'modulepreload'])) { + $rel = 'preload'; + } - return is_null($type) ? null : "<{$url}>; rel=preload; as={$type}"; + return is_null($type) ? null : "<{$url}>; rel={$rel}; as={$type}" . ($type == 'font' ? '; crossorigin' : ''); } /** diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 2f37cea..ee93eb6 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -1,4 +1,4 @@ -publishes([ - __DIR__ . '/config.php' => config_path('http2serverpush.php'), - ]); + $this->mergeConfigFrom(__DIR__.'/config.php', 'http2serverpush'); + + // Register paths to be published by 'vendor:publish' Artisan command + $this->publishes([ + __DIR__ . '/config.php' => config_path('http2serverpush.php'), + ], 'config'); } } diff --git a/src/config.php b/src/config.php index 28e0206..2998a36 100644 --- a/src/config.php +++ b/src/config.php @@ -4,5 +4,8 @@ return [ 'size_limit' => '6000', // in bytes 'base_path' => '/', - 'exclude_keywords' => [] + 'exclude_keywords' => [], + 'default_headers' => [ + // '; rel=preload; as=style', + ], ];