Created
May 11, 2022 11:58
-
-
Save stefanfisk/bb4e045f3d15829a377916dc5fee9acc to your computer and use it in GitHub Desktop.
PHP parser for `@wordpress/dependency-extraction-webpack-plugin` / `'webpack-bundle-analyzer`
This file contains hidden or 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
<?php | |
namespace App\Support\Assets; | |
use Illuminate\Support\Str; | |
use InvalidArgumentException; | |
use RuntimeException; | |
use function base64_encode; | |
use function file_exists; | |
use function file_get_contents; | |
use function json_decode; | |
use function rtrim; | |
use function sprintf; | |
/** | |
* Adapter for /public/build/manifest.json. | |
* | |
* Resolves entrypoints to chunk filenames. | |
*/ | |
class AssetManifest | |
{ | |
private string $dir; | |
private string $dirUrl; | |
protected array $entrypoints = []; | |
protected array $chunks = []; | |
protected array $assets = []; | |
/** | |
* @param string $buildDir | |
* @param string $buildDirUrl | |
*/ | |
public function __construct($buildDir, $buildDirUrl) | |
{ | |
$this->dir = rtrim($buildDir, '/'); | |
$this->dirUrl = rtrim($buildDirUrl, '/'); | |
$manifestFile = "$this->dir/manifest.json"; | |
if (! file_exists($manifestFile)) { | |
throw new InvalidArgumentException('Asset manifest not found.'); | |
} | |
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents | |
$manifest = json_decode(file_get_contents($manifestFile), true); | |
if (! $manifest) { | |
throw new RuntimeException('Failed to load asset manifest.'); | |
} | |
foreach ($manifest['chunks'] as $chunk) { | |
$this->chunks[ $chunk['id'] ] = $chunk; | |
} | |
$this->entrypoints = $manifest['entrypoints']; | |
foreach ($manifest['assets'] as $asset) { | |
$sourceFilename = $asset['info']['sourceFilename'] ?? null; | |
if (! $sourceFilename) { | |
continue; | |
} | |
$this->assets[$sourceFilename] = $asset; | |
} | |
} | |
/** | |
* @param string $handle | |
* @return string | |
*/ | |
public function getStyleFilename($handle) | |
{ | |
$filename = null; | |
$entrypoint = $this->entrypoints[ $handle ] ?? null; | |
if (! $entrypoint) { | |
throw new RuntimeException("No entrypoint found for style $handle"); | |
} | |
foreach ($entrypoint['chunks'] as $chunkId) { | |
$chunk = $this->chunks[ $chunkId ]; | |
foreach ($chunk['files'] as $file) { | |
if (! Str::endsWith($file, '.css')) { | |
continue; | |
} | |
$filename = $file; | |
break; | |
} | |
} | |
return $filename; | |
} | |
/** | |
* @param string $sourceFilename | |
* @return string | |
*/ | |
public function getStylePath($sourceFilename) | |
{ | |
return $this->dir . '/' . $this->getStyleFilename($sourceFilename); | |
} | |
/** | |
* @param string $handle | |
* @return string | |
*/ | |
public function getStyleUrl($handle) | |
{ | |
return $this->dirUrl . '/' . $this->getStyleFilename($handle); | |
} | |
/** | |
* @param string $entrypointName | |
* @return array<array{handle:string,url:string,deps:string[]}> | |
*/ | |
public function getStyles($entrypointName) | |
{ | |
if (empty($this->entrypoints[ $entrypointName ])) { | |
throw new InvalidArgumentException("Entrypoint $entrypointName not found"); | |
} | |
$entrypoint = $this->entrypoints[ $entrypointName ]; | |
$styles = []; | |
foreach ($entrypoint['chunks'] as $chunkId) { | |
$chunk = $this->chunks[ $chunkId ]; | |
$i = 0; | |
foreach ($chunk['files'] as $file) { | |
if (! Str::endsWith($file, '.css')) { | |
continue; | |
} | |
$fileHandle = 'berghs-' . sanitize_title($chunk['names'][0]); | |
if (0 !== $i) { | |
$fileHandle .= "-$i"; | |
} | |
$styles[] = [ | |
'handle' => $fileHandle, | |
'file' => "$this->dir/$file", | |
'url' => "$this->dirUrl/$file", | |
'deps' => [], | |
]; | |
$i++; | |
} | |
} | |
return $styles; | |
} | |
/** | |
* Gets all scripts for the entrypoint. | |
* | |
* Includes deps as provided by `@wordpress/dependency-extraction-webpack-plugin`. | |
* | |
* @param string $entrypointName | |
* @return array<array{handle:string,url:string,deps:string[]}> | |
*/ | |
public function getScripts($entrypointName) | |
{ | |
$entrypoint = $this->entrypoints[ $entrypointName ] ?? null; | |
if (! $entrypoint) { | |
throw new InvalidArgumentException("Entrypoint $entrypointName not found"); | |
} | |
$assetFilename = null; | |
foreach ($entrypoint['assets'] as $asset) { | |
if (! Str::endsWith($asset['name'], '.asset.php')) { | |
continue; | |
} | |
$assetFilename = $asset['name']; | |
break; | |
} | |
if (! $assetFilename) { | |
throw new InvalidArgumentException("Asset file not found for entrypoint $entrypointName."); | |
} | |
$asset = require "$this->dir/$assetFilename"; | |
$deps = $asset['dependencies']; | |
$entrypoint = $this->entrypoints[ $entrypointName ]; | |
$scripts = []; | |
foreach ($entrypoint['chunks'] as $chunkId) { | |
$chunk = $this->chunks[ $chunkId ]; | |
$i = 0; | |
foreach ($chunk['files'] as $file) { | |
if (! Str::endsWith($file, '.js')) { | |
continue; | |
} | |
$fileHandle = 'berghs-' . sanitize_title($chunk['names'][0]); | |
if (0 !== $i) { | |
$fileHandle .= "-$i"; | |
} | |
$scripts[] = [ | |
'handle' => $fileHandle, | |
'file' => "$this->dir/$file", | |
'url' => "$this->dirUrl/$file", | |
'deps' => $deps, | |
'version' => null, | |
]; | |
$i++; | |
} | |
} | |
return $scripts; | |
} | |
/** | |
* @param string $sourceFilename | |
* @return string | |
*/ | |
public function getAssetFilename($sourceFilename) | |
{ | |
$asset = $this->assets[$sourceFilename] ?? null; | |
if (! $asset) { | |
throw new InvalidArgumentException("Asset $sourceFilename not found."); | |
} | |
return $asset['name']; | |
} | |
/** | |
* @param string $sourceFilename | |
* @return string | |
*/ | |
public function getAssetPath($sourceFilename) | |
{ | |
return $this->dir . '/' . $this->getAssetFilename($sourceFilename); | |
} | |
/** | |
* @param string $sourceFilename | |
* @return string | |
*/ | |
public function getAssetUrl($sourceFilename) | |
{ | |
return $this->dirUrl . '/' . $this->getAssetFilename($sourceFilename); | |
} | |
/** | |
* @param string $sourceFilename | |
* @param string $mediaType | |
* @return string | |
*/ | |
public function getAssetDataUri($sourceFilename, $mediaType = 'application/octet-stream') | |
{ | |
$filename = $this->getAssetFilename($sourceFilename); | |
$data = file_get_contents($this->dir . '/' . $filename); | |
return sprintf('data:%s;base64,%s', $mediaType, base64_encode($data)); | |
} | |
} |
This file contains hidden or 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
<?php | |
function enqueueScript(string $entrypoint, bool $inFooter = true) | |
{ | |
$scripts = $this->getManifest()->getScripts($entrypoint); | |
foreach ($scripts as $script) { | |
wp_enqueue_script( | |
$script['handle'], | |
$script['url'], | |
$script['deps'], | |
null, | |
$inFooter | |
); | |
} | |
} | |
function enqueueStyle(string $entrypoint, array $deps = []): void | |
{ | |
$styles = $this->getManifest()->getStyles($entrypoint); | |
foreach ($styles as $style) { | |
wp_enqueue_style( | |
$style['handle'], | |
$style['url'], | |
array_merge( | |
$deps, | |
$style['deps'], | |
), | |
null | |
); | |
} | |
} |
This file contains hidden or 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
module.exports = { | |
..., | |
plugins: [ | |
new DependencyExtractionWebpackPlugin({ | |
outputFilename: `[name].asset.php`, | |
}), | |
// Used by App\Support\Assets\AssetManifest | |
new BundleAnalyzerPlugin({ | |
analyzerMode: 'disabled', | |
generateStatsFile: true, | |
statsFilename: 'manifest.json', | |
statsOptions: { | |
all: false, | |
ids: true, | |
entrypoints: true, | |
chunks: true, | |
assets: true, | |
}, | |
}), | |
], | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment