interitty / static-content-generator
静态内容生成器将应用输出持久化以便将来使用,节省时间和金钱。
Requires
- php: ~8.3
- dg/composer-cleaner: ~2.2
- interitty/output-buffer-manager: ~1.0
- interitty/utils: ~1.0
- league/flysystem: ~3.28
- psr/log: ~3.0
Requires (Dev)
- interitty/application: ~1.0
- interitty/code-checker: ~1.0
- interitty/di: ~1.0
- interitty/phpunit: ~1.0
README
静态内容生成器将应用输出持久化以便将来使用,节省时间和金钱。
要求
- PHP >= 8.3
安装
安装 interitty/static-content-generator 的最佳方式是使用 Composer
composer require interitty/static-content-generator
然后在 Nette 配置 文件中注册扩展
# app/config/config.neon
extensions:
staticContentGenerator: Interitty\StaticContentGenerator\Nette\DI\StaticContentGeneratorExtension
设置
还有一些其他设置,您可能需要根据需要进行调整。
Neon 参数 | 描述 |
---|---|
autoEnd | 当调用 processBegin 时,是否自动将所有相关内容捕获到存储中?默认值是 "false " |
autoStart | 在每个请求之前调用 processBegin ?默认值是 "false " |
basePath | processFileName 助手中所有生成的文件路径的前缀。默认值是 "/ " |
destination | 写入生成的静态内容的目标文件夹。默认值是 "%wwwDir% " |
productionMode | 生产模式抑制写入只读文件系统时的可能异常,并创建日志条目 |
readOnly | 标志文件系统是否处于只读模式。默认值 null 用于通过 destination 参数中的路径自动检测 |
writeFlags | 使用 file_put_contents 标志。默认值是 "LOCK_EX " |
使用方法
为了方便使用 静态内容生成器,有一个 Nette DI 扩展,该扩展注册了所有必需的服务以供将来使用。它还允许注册到 Nette 生命周期中,以自动将所有相关静态内容持久化到指定的文件夹。
示例:自动捕获所有相关静态内容
此配置捕获所有具有 HTTP 状态 200: OK
的响应,允许缓存 (这意味着 HTTP 标头 Cache-Control
或 Pragma
不包含 "no-cache
" 或 "no-store
" 值)。
extensions:
staticContentGenerator: Interitty\StaticContentGenerator\Nette\DI\StaticContentGeneratorExtension
staticContentGenerator:
autoStart: true
destination: %wwwDir%
示例:自动捕获特定静态内容
有许多情况下,可能需要设置应存储哪个 Presenter:action。为此,有一个 autoEnd
参数,表示每次手动调用 processBegin
时都捕获所有相关响应。
extensions:
staticContentGenerator: Interitty\StaticContentGenerator\Nette\DI\StaticContentGeneratorExtension
staticContentGenerator:
autoStart: false # Default behavior
autoEnd: true
processBegin
没有自动调用,因为默认情况下 autoStart
参数为 false
。这允许有任何复杂的条件,以指定应持久化哪个页面
class CmdPresenter extends \Nette\Application\UI\Presenter
{
/** @var \Interitty\StaticContentGenerator\StaticContentGenerator @inject */
protected $generator;
public function actionDefault($page)
{
if($page !== 'Admin') {
$this->staticContentGenerator->processBegin();
}
}
}
部分使用
StaticContentGenerator
类可以简单地捕获输出内容,并将它们持久化到指定的存储中。多亏了 FlySystem,生成器可以存储在几乎所有地方 本地、远程 FTP 或云存储,如 AWS S3 或 Azure。由于需要一次性持久化更多文件及其内容,如缓存预热过程中,每个部分都由 StaticContentHandler
类分开。
示例:通过 StaticContentHandler
将内容捕获到文件中
以下示例捕获所有发送到输出的内容,并将它们存储在由给定 $filename
变量指定的文件中。因为可选参数 $muteOutput
被指定为 false
,所以所有内容也将被发送到输出或另一个已注册的 输出缓冲区 处理器。
// Flysystem setup
$destination = sys_get_temp_dir();
$adapter = new \League\Flysystem\Adapter\Local($destination);
$filesystem = new \League\Flysystem\Filesystem($adapter);
// OutputBufferManager setup
$outputBufferManager = new \Interitty\OutputBufferManager\OutputBufferManager();
$filename = 'data.txt';
$muteOutput = false;
$storage = new \Interitty\StaticContentGenerator\Storage\FilesystemStorage($filesystem);
$handler = new \Interitty\StaticContentGenerator\Handler\StaticContentHandler($storage, $filename, $muteOutput);
$outputBufferManager->begin('…', [$handler, 'processManageOutput']);
$handler->processBegin();
// Any content that was sent to the output
echo 'testContent';
$outputBufferManager->end('…');
$handler->processEnd();
示例:通过 StaticContentGenerator
进行缓存预热
以下示例模拟缓存预热过程,捕获所有发送到输出的内容,并将它们存储到由给定 $filename
变量指定的文件中。因为可选参数 $muteOutput
被指定为 true
,所以将不会将任何内容发送到输出或另一个已注册的 输出缓冲区 处理器。
// Test data
$testData = [
'test1.txt' => 'Test 1',
'test2.txt' => 'Test 2',
];
// Flysystem setup
$destination = __DIR__;
$adapter = new \League\Flysystem\Adapter\Local($destination);
$filesystem = new \League\Flysystem\Filesystem($adapter);
// OutputBufferManager setup
$muteOutput = true;
$outputBufferManager = new \Interitty\OutputBufferManager\OutputBufferManager();
$storage = new \Interitty\StaticContentGenerator\Storage\FilesystemStorage($filesystem);
$generator = new \Interitty\StaticContentGenerator\StaticContentGenerator($outputBufferManager, $storage);
foreach ($testData as $filename => $content) {
$handler = $generator->createHandler($filename, $muteOutput);
$generator->setHandler($handler);
$generator->processBegin();
// Any content that was sent to the output
echo $content;
$generator->processEnd();
}
示例:从URL列表中进行缓存预热
缓存预热过程主要基于URL列表。因此,StaticContentGenerator
包含一个名为 processFileName()
的辅助方法,用于从给定URL的路径部分检测目标文件名。
// Test data
$testData = [
'/' => 'Index test',
'/test.html' => 'Test',
'/test' => 'Subfolder test',
];
// Flysystem setup
$destination = __DIR__;
$adapter = new \League\Flysystem\Adapter\Local($destination);
$filesystem = new \League\Flysystem\Filesystem($adapter);
// OutputBufferManager setup
$muteOutput = true;
$outputBufferManager = new \Interitty\OutputBufferManager\OutputBufferManager();
$storage = new \Interitty\StaticContentGenerator\Storage\FilesystemStorage($filesystem);
$generator = new \Interitty\StaticContentGenerator\StaticContentGenerator($outputBufferManager, $storage);
foreach ($testData as $path => $content) {
$filename = $generator->processFileName($path);
$handler = $generator->createHandler($filename, $muteOutput);
$generator->setHandler($handler);
$generator->processBegin();
// Any content that was sent to the output
echo $content;
$generator->processEnd();
}
示例:通过 MiddlewareStaticContentGenerator
将请求/响应内容捕获到文件中
捕获传入请求的HTTP响应内容可能很有用。
// Request/Response setup
$url = 'https:///';
$urlScript = new \Nette\Http\UrlScript($url);
$request = new \Nette\Http\Request($urlScript);
$response = new \Nette\Http\Response();
$response->setCode(\Nette\Http\IResponse::S200_OK);
// Flysystem setup
$destination = __DIR__;
$adapter = new \League\Flysystem\Adapter\Local($destination);
$filesystem = new \League\Flysystem\Filesystem($adapter);
// OutputBufferManager setup
$outputBufferManager = new \Interitty\OutputBufferManager\OutputBufferManager();
$storage = new \Interitty\StaticContentGenerator\Storage\FilesystemStorage($filesystem);
$generator = new \Interitty\StaticContentGenerator\Nette\MiddlewareStaticContentGenerator($request, $response, $outputBufferManager, $storage);
$generator->processBegin();
// Any content that was sent to the output
echo 'testContent';
$generator->processEnd();
只读文件系统(Docker支持)
如果应用程序打包在 docker 容器中,建议在生产环境中以 只读 模式运行。
在此模式下,所有静态资产应已由Web服务器(apache,nginx等)预先生成和使用,这应导致PHP应用程序根本不会被调用。因此,如果它确实被调用,则可以将其视为缺陷,并记录为此类。
默认情况下,此模式会根据由 destination
参数指定的文件夹权限和 productionMode
标志自动检测。在开发环境中,只读模式没有太多意义,但如果它仍然处于活动状态,异常不会被捕获以尽快解决这种情况。这两个参数都可以在配置中调整。
extensions:
staticContentGenerator: Interitty\StaticContentGenerator\Nette\DI\StaticContentGeneratorExtension
staticContentGenerator:
productionMode: %productionMode% # Default behavior
readOnly: null # Default behavior