Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions bin/file-watcher.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const chokidar = require('chokidar');

const paths = JSON.parse(process.argv[2]);
const options = JSON.parse(process.argv[3]);

const watcher = chokidar.watch(paths, options);

watcher
.on('add', () => console.log('file added ...'))
.on('change', () => console.log('file changed ...'))
.on('unlink', () => console.log('file deleted ...'))
.on('unlinkDir', () => console.log('directory deleted ...'));
40 changes: 40 additions & 0 deletions config/laravels.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,46 @@
'log' => true,
],

'chokidar_reload' => [
// Whether enable the chokidar Reload to reload all worker processes when your code is modified.
// chokidar Reload,用于当修改代码后实时Reload所有worker进程,依赖库node js 库 chokidar,
// 默认false,建议仅开发环境开启,修改监听数上限。
'enable' => env('LARAVELS_CHOKIDAR_RELOAD', false),

// The file path that chokidar watches
// chokidar 监控的文件路径,默认有base_path()。
'watch_base_path' => base_path(),
'watch_path_files' => [
'app',
'bootstrap',
'config/**/*.php',
'database/**/*.php',
'public/**/*.php',
'resources/**/*.php',
'routes',
'composer.lock',
'.env',
],

// chokidar 监控的参数。
'watch_options' => [
//是否使用轮询方式监听文件变化。默认为 false,如果文件系统不支持事件监听,设置为 true 会强制使用轮询
'usePolling' => true,
//在使用轮询时,设置轮询的时间间隔(单位:毫秒)。默认值为 100
'interval' => 200,
//是否忽略首次读取文件时的事件(例如,文件刚开始时的“添加”或“变化”事件)。默认为 false,即不会忽略首次事件。
'ignoreInitial' => true,
],

// The excluded/ignored directories that Inotify watches
// Inotify 监控时需要排除(或忽略)的目录,默认[],示例:[base_path('vendor')]。
'excluded_dirs' => [base_path('vendor')],

// Whether output the reload log
// 是否输出Reload的日志,默认true。
'log' => true,
],

/*
|--------------------------------------------------------------------------
| Swoole Event Handlers
Expand Down
12 changes: 11 additions & 1 deletion src/LaravelS.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Hhxsv5\LaravelS\Swoole\Events\WorkerStartInterface;
use Hhxsv5\LaravelS\Swoole\Events\WorkerStopInterface;
use Hhxsv5\LaravelS\Swoole\InotifyTrait;
use Hhxsv5\LaravelS\Swoole\ChokidarWatchTrait;
use Hhxsv5\LaravelS\Swoole\Process\CustomProcessTrait;
use Hhxsv5\LaravelS\Swoole\Process\ProcessTitleTrait;
use Hhxsv5\LaravelS\Swoole\Request;
Expand All @@ -37,7 +38,7 @@ class LaravelS extends Server
/**
* Fix conflicts of traits
*/
use InotifyTrait, LaravelTrait, LogTrait, ProcessTitleTrait, TimerTrait, CustomProcessTrait;
use InotifyTrait, ChokidarWatchTrait, LaravelTrait, LogTrait, ProcessTitleTrait, TimerTrait, CustomProcessTrait;

/**@var array */
protected $laravelConf;
Expand All @@ -61,6 +62,15 @@ public function __construct(array $svrConf, array $laravelConf)
$inotifyConf['process_prefix'] = $svrConf['process_prefix'];
$this->swoole->inotifyProcess = $this->addInotifyProcess($this->swoole, $inotifyConf, $this->laravelConf);

$chokidarConf = isset($this->conf['chokidar_reload']) ? $this->conf['chokidar_reload'] : [];
if (!empty($chokidarConf['enable'])) {
if (!isset($chokidarConf['watch_path'])) {
$chokidarConf['watch_path'] = $this->laravelConf['root_path'];
}
$chokidarConf['process_prefix'] = $svrConf['process_prefix'];
$this->swoole->chokidarProcess = $this->addChokidarWatchProcess($this->swoole, $chokidarConf, $this->laravelConf);
}

$processes = isset($this->conf['processes']) ? $this->conf['processes'] : [];
$this->swoole->customProcesses = $this->addCustomProcesses($this->swoole, $svrConf['process_prefix'], $processes, $this->laravelConf);

Expand Down
51 changes: 51 additions & 0 deletions src/Swoole/ChokidarWatchTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace Hhxsv5\LaravelS\Swoole;

use Hhxsv5\LaravelS\Console\Portal;
use Swoole\Http\Server;
use Swoole\Process;
use Symfony\Component\Process\ExecutableFinder;

trait ChokidarWatchTrait
{
public function addChokidarWatchProcess(Server $swoole, array $config, array $laravelConf)
{
if (empty($config['enable'])) {
return false;
}

$watchPathFiles = isset($config['watch_path_files']) ? (array)$config['watch_path_files'] : [];
if (empty($watchPathFiles)) {
$this->warning('No file to watch by chokidar');
return false;
}

$callback = function (Process $worker) use ($config, $laravelConf, $watchPathFiles) {
$log = !empty($config['log']);
$watch_base_path = $config['watch_base_path'];
$this->setProcessTitle(sprintf('%s laravels: chokidar process', $config['process_prefix']));
$nodeExecutable = (new ExecutableFinder)->find('node');
$nodeScriptPath = realpath(__DIR__.'/../../bin/file-watcher.cjs');
$this->info(sprintf('$nodeScriptPath: %s', $nodeScriptPath));

$watchOptions = isset($config['watch_options']) ? (array)$config['watch_options'] : ['ignoreInitial' => true];
$worker->exec($nodeExecutable, [$nodeScriptPath,
json_encode(collect($watchPathFiles)->map(fn ($path) => $watch_base_path.'/'.$path)),
json_encode($watchOptions),
]);

// 获取 Node.js 脚本的输出
tap($worker->read(), function ($output) use ($log, $laravelConf) {
Portal::runLaravelSCommand($laravelConf['root_path'], 'reload');
if ($log) {
$this->info(sprintf('reloaded by chokidar, reason: %s', $output));
}
});
};

$process = new Process($callback, false, 0);
$swoole->addProcess($process);
return $process;
}
}