I'm finding the execute javascript middleware to be extremely useful but sometimes it doesn't wait long enough and activity is still happening in the DOM.
I ended up having to copy over the middleware and chain on ->waitUntilNetworkIdle() in the constructor
In order for me to be able get the markup from the DOM otherwise lots of critical data doesn't get rendered.
I might have missed this as an option somewhere - there is likely a better way to indicate this as an option rather than an entirely separate middleware file.
<?phpdeclare(strict_types=1);
/** * Copyright (c) 2022 Kai Sassnowski * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. * * @see https://github.com/roach-php/roach */namespaceApp\Roach\Middleware;
usePsr\Log\LoggerInterface;
useRoachPHP\Http\Response;
useRoachPHP\Downloader\Middleware\ResponseMiddlewareInterface;
useRoachPHP\Support\Configurable;
useSpatie\Browsershot\Browsershot;
useThrowable;
finalclass ExecuteJavascriptNetworkIdleMiddleware implements ResponseMiddlewareInterface
{
use Configurable;
/** * @var callable(string): Browsershot */private$getBrowsershot;
/** * @param null|callable(string): Browsershot $getBrowsershot */publicfunction__construct(
privateLoggerInterface$logger,
?callable$getBrowsershot = null,
) {
$this->getBrowsershot = $getBrowsershot ?: staticfn (string$uri): Browsershot => Browsershot::url($uri)->waitUntilNetworkIdle();
}
publicfunctionhandleResponse(Response$response): Response
{
$browsershot = $this->configureBrowsershot(
$response->getRequest()->getUri(),
);
try {
$body = $browsershot->bodyHtml();
} catch (Throwable$e) {
$this->logger->info('[ExecuteJavascriptMiddleware] Error while executing javascript', [
'message' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
return$response->drop('Error while executing javascript');
}
return$response->withBody($body);
}
/** * @psalm-suppress MixedArgument, MixedAssignment */privatefunctionconfigureBrowsershot(string$uri): Browsershot
{
$browsershot = ($this->getBrowsershot)($uri);
if (!empty($this->option('chromiumArguments'))) {
$browsershot->addChromiumArguments($this->option('chromiumArguments'));
}
if (null !== ($chromePath = $this->option('chromePath'))) {
$browsershot->setChromePath($chromePath);
}
if (null !== ($binPath = $this->option('binPath'))) {
$browsershot->setBinPath($binPath);
}
if (null !== ($nodeModulePath = $this->option('nodeModulePath'))) {
$browsershot->setNodeModulePath($nodeModulePath);
}
if (null !== ($includePath = $this->option('includePath'))) {
$browsershot->setIncludePath($includePath);
}
if (null !== ($nodeBinary = $this->option('nodeBinary'))) {
$browsershot->setNodeBinary($nodeBinary);
}
if (null !== ($npmBinary = $this->option('npmBinary'))) {
$browsershot->setNpmBinary($npmBinary);
}
return$browsershot;
}
privatefunctiondefaultOptions(): array
{
return [
'chromiumArguments' => [],
'chromePath' => null,
'binPath' => null,
'nodeModulePath' => null,
'includePath' => null,
'nodeBinary' => null,
'npmBinary' => null,
];
}
}Thank you!
I'm finding the execute javascript middleware to be extremely useful but sometimes it doesn't wait long enough and activity is still happening in the DOM.
I ended up having to copy over the middleware and chain on ->waitUntilNetworkIdle() in the constructor
In order for me to be able get the markup from the DOM otherwise lots of critical data doesn't get rendered.
I might have missed this as an option somewhere - there is likely a better way to indicate this as an option rather than an entirely separate middleware file.
Thank you!