Skip to content

Commit

Permalink
Simplify generator, tweak options for local node modules
Browse files Browse the repository at this point in the history
  • Loading branch information
barryvdh committed Oct 11, 2017
1 parent 2721467 commit 6739eeb
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 198 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ phpunit.xml
composer.lock
vendor
bin
node_modules/
package-lock.json
8 changes: 5 additions & 3 deletions resources/puppeteer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ const puppeteer = require('puppeteer');
const args = process.argv.slice(2);

const action = args[0];
const url = args[1];
const options = args[2] ? JSON.parse(args[2]) : {};
const inputUrl = args[1];

let options = args[3] ? JSON.parse(args[3]) : {};
options.path = args[2];

let fn = _asyncToGenerator(function* () {
let browser, page;
Expand Down Expand Up @@ -49,7 +51,7 @@ let fn = _asyncToGenerator(function* () {
yield page.setViewport(options.viewport);
}

yield page.goto(url, options);
yield page.goto(inputUrl, options);

if (action === 'screenshot') {
yield page.screenshot(options);
Expand Down
153 changes: 108 additions & 45 deletions src/Knp/Snappy/Puppeteer/AbstractGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,61 @@

namespace Knp\Snappy\Puppeteer;

use Knp\Snappy\Exception\GenerationFailed;
use Knp\Snappy\Filesystem;
use Knp\Snappy\Generator;
use Knp\Snappy\LocalGenerator;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;

/**
* Abstract puppeteer generator.
* Abstract Puppeteer generator.
*
* @author Albin Kerouanton <albin.kerouanton@knplabs.com>
* @author Barry vd. Heuvel <barry@fruitcake.nl>
*/
abstract class AbstractGenerator implements Generator, LocalGenerator
{
/** @var array */
private $options;

/** @var Backend */
private $backend;
/** @var string */
private $nodePath;

/** @var Filesystem */
private $filesystem;

/**
* @param Backend $backend Puppeteer backend used to generate PDF/screenshot files
* @param array|null $options Default options for every generation done with this instance
* If null provided: disable-gpu, incognito and window-size (1280x1696)
*/
public function __construct(Backend $backend = null, array $options = null)
/** @var LoggerInterface */
private $logger;

/** @var array */
private $env;

/** @var int */
private $timeout = false;

public function __construct(array $options = [], $nodePath = null, array $env = [])
{
$this->backend = $backend ?? new Backend();
$this->options = $options ?? [
'viewport' => ['width' => 1280, 'height' => 1696],
'fullPage' => true,
'emulateMedia' => 'screen',
'printBackground' => true,
];
$this->options = $options;
$this->nodePath = $nodePath;
$this->env = !empty($env) ? $env : null;
$this->filesystem = new Filesystem();
$this->logger = new NullLogger();
}

/**
* Run chrome to generate the output file.
*
* @param string $inputUri URI of the input document
* (e.g "file://<filename>" or "data:text/html,<urlencoded-html>").
* @param array $options Set of options specific to this generation
* Define the action used, can be 'pdf' or 'screenshot'.
*
* @throws \InvalidArgumentException When an invalid option is used
* @throws \RuntimeException When backend fails to generate the output file
* @return string
*/
abstract protected function doGenerate(string $inputUri, array $options);
abstract protected function getAction() : string;

/**
* Get the default extension for the temporary files.
*
* @return string
*/
abstract protected function getDefaultExtension(): string;

/**
Expand All @@ -65,19 +70,39 @@ protected function getOptions(): array
}

/**
* @return Backend
* @param Filesystem $filesystem
*/
protected function getBackend(): Backend
public function setFilesystem(Filesystem $filesystem)
{
return $this->backend;
$this->filesystem = $filesystem;
}

/**
* @param Filesystem $filesystem
* @param LoggerInterface $logger
*/
public function setFilesystem(Filesystem $filesystem)
public function setLogger(LoggerInterface $logger)
{
$this->filesystem = $filesystem;
$this->logger = $logger;
}

/**
* Set the Node Modules path where Puppeteer is installed.
*
* @param string $nodePath The path to the node_modules dir
*/
public function setNodePath(string $nodePath)
{
$this->nodePath = $nodePath;
}

/**
* Sets the timeout.
*
* @param int $timeout The timeout to set
*/
public function setTimeout($timeout)
{
$this->timeout = $timeout;
}

/**
Expand Down Expand Up @@ -122,11 +147,29 @@ public function setOptions(array $options)
*/
public function generate($input, string $output, array $options = [], bool $overwrite = false)
{
$this->filesystem->prepareOutput($output, $overwrite);

$options['path'] = $output;

$this->doGenerate($input, $options);
$command = $this->buildCommand($input, $output, $options);
$process = new Process($command, null, $this->env, null, $this->timeout);

$this->logger->info(sprintf('Run puppeteer command: "%s".', $command), [
'command' => $command,
'env' => $this->env,
'timeout' => $this->timeout,
]);

try {
$process->mustRun();
} catch (ProcessFailedException $e) {
$this->logger->error(sprintf('Puppeteer process failed during execution.'), [
'command' => $command,
'env' => $this->env,
'timeout' => $this->timeout,
'exitCode' => $process->getExitCode(),
'stdout' => $process->getOutput(),
'stderr' => $process->getErrorOutput(),
]);

throw new GenerationFailed('Generation failed', 0, $e);
}
}

/**
Expand All @@ -136,9 +179,7 @@ public function generateFromHtml($html, string $output, array $options = [], boo
{
$this->filesystem->prepareOutput($output, $overwrite);

$options['path'] = $output;

$this->doGenerate(sprintf('data:text/html,%s', rawurlencode($html)), $options);
$this->generate(sprintf('data:text/html,%s', rawurlencode($html)), $output, $options);
}

/**
Expand All @@ -148,9 +189,7 @@ public function getOutput($input, array $options = [])
{
$temporaryFile = $this->filesystem->createTemporaryFile(null, $this->getDefaultExtension());

$options['path'] = $temporaryFile;

$this->doGenerate($input, $options);
$this->generate($input, $temporaryFile, $options);

return $this->filesystem->getFileContents($temporaryFile);
}
Expand All @@ -162,10 +201,34 @@ public function getOutputFromHtml($html, array $options = [])
{
$temporaryFile = $this->filesystem->createTemporaryFile(null, $this->getDefaultExtension());

$options['path'] = $temporaryFile;

$this->doGenerate(sprintf('data:text/html,%s', rawurlencode($html)), $options);
$this->generate(sprintf('data:text/html,%s', rawurlencode($html)), $temporaryFile, $options);

return $this->filesystem->getFileContents($temporaryFile);
}

/**
* @param string $input URI of the input document used
* @param string $output Path to the output file
* @param array $options Options and arguments to pass to chrome (empty/false/null options are ignored)
*
* @return string
*/
protected function buildCommand(string $input, string $output, array $options): string
{
if ($this->nodePath && is_dir($this->nodePath)) {
$nodePath = escapeshellarg(realpath($this->nodePath));
} else {
$nodePath = '`npm root -g`'; // Detect root node path
}

return implode(' ', [
'NODE_PATH=' . $nodePath,
'node',
escapeshellarg(realpath(__DIR__ . '/../../../../resources/puppeteer.js')),
escapeshellarg($this->getAction()),
escapeshellarg($input),
escapeshellarg($output),
escapeshellarg(json_encode($options)),
]);
}
}
105 changes: 0 additions & 105 deletions src/Knp/Snappy/Puppeteer/Backend.php

This file was deleted.

32 changes: 0 additions & 32 deletions src/Knp/Snappy/Puppeteer/CommandBuilder.php

This file was deleted.

Loading

0 comments on commit 6739eeb

Please sign in to comment.