-
-
Notifications
You must be signed in to change notification settings - Fork 380
Feature: add bun.js runtime [WIP] #962
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e403fda
7d8eacc
6e54898
617f4db
c9a32a2
ceb26ca
adfe18c
220cb50
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| <?php | ||
|
|
||
| namespace App\Services\Bun; | ||
|
|
||
| use App\Exceptions\SSHError; | ||
| use App\Services\AbstractService; | ||
| use Closure; | ||
| use Illuminate\Validation\Rule; | ||
|
|
||
| class Bun extends AbstractService | ||
| { | ||
| public static function id(): string | ||
| { | ||
| return 'bun'; | ||
| } | ||
|
|
||
| public static function type(): string | ||
| { | ||
| return 'bun'; | ||
| } | ||
|
|
||
| public function unit(): string | ||
| { | ||
| return ''; | ||
| } | ||
|
|
||
| public function creationRules(array $input): array | ||
| { | ||
| return [ | ||
| 'type' => [ | ||
| function (string $attribute, mixed $value, Closure $fail): void { | ||
| $exists = $this->service->server->bun(); | ||
| if ($exists) { | ||
| $fail('You already have Bun installed on the server.'); | ||
| } | ||
| }, | ||
| ], | ||
| 'version' => [ | ||
| 'required', | ||
| Rule::in(config('service.services.bun.versions')), | ||
| Rule::unique('services', 'version') | ||
| ->where('type', 'bun') | ||
| ->where('server_id', $this->service->server_id), | ||
| ], | ||
| ]; | ||
| } | ||
|
|
||
| public function deletionRules(): array | ||
| { | ||
| return [ | ||
| 'service' => [ | ||
| function (string $attribute, mixed $value, Closure $fail): void { | ||
| $hasSite = $this->service->server->sites() | ||
| ->where('type', 'bun') | ||
| ->exists(); | ||
| if ($hasSite) { | ||
| $fail('Some sites are using Bun.'); | ||
| } | ||
| }, | ||
| ], | ||
| ]; | ||
| } | ||
|
|
||
| /** | ||
| * @throws SSHError | ||
| */ | ||
| public function install(): void | ||
| { | ||
| $server = $this->service->server; | ||
| $server->ssh()->exec( | ||
| view('ssh.services.bun.install-bun', [ | ||
| 'version' => $this->service->version, | ||
| ]), | ||
| 'install-bun-'.$this->service->version | ||
| ); | ||
| event('service.installed', $this->service); | ||
| $this->service->server->os()->cleanup(); | ||
| } | ||
|
|
||
| /** | ||
| * @throws SSHError | ||
| */ | ||
| public function uninstall(): void | ||
| { | ||
| $this->service->server->ssh()->exec( | ||
| view('ssh.services.bun.uninstall-bun'), | ||
| 'uninstall-bun' | ||
| ); | ||
| event('service.uninstalled', $this->service); | ||
| $this->service->server->os()->cleanup(); | ||
| } | ||
|
|
||
| public function version(): string | ||
| { | ||
| $version = $this->service->server->ssh()->exec( | ||
| 'bun --version' | ||
| ); | ||
|
|
||
| return trim($version); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,172 @@ | ||
| <?php | ||
|
|
||
| namespace App\SiteTypes; | ||
|
|
||
| use App\Actions\Worker\CreateWorker; | ||
| use App\Actions\Worker\ManageWorker; | ||
| use App\Exceptions\FailedToDeployGitKey; | ||
| use App\Exceptions\SSHError; | ||
| use App\Models\Site; | ||
| use App\Models\Worker; | ||
| use App\SSH\OS\Git; | ||
| use Illuminate\Contracts\View\View; | ||
| use Illuminate\Validation\Rule; | ||
|
|
||
| class Bun extends AbstractSiteType | ||
| { | ||
| public static function id(): string | ||
| { | ||
| return 'bun'; | ||
| } | ||
|
|
||
| public function language(): string | ||
| { | ||
| return 'bun'; | ||
| } | ||
|
|
||
| public function requiredServices(): array | ||
| { | ||
| return [ | ||
| 'bun', | ||
| 'webserver', | ||
| 'process_manager', | ||
| ]; | ||
| } | ||
|
|
||
| public static function make(): self | ||
| { | ||
| return new self(new Site(['type' => self::id()])); | ||
| } | ||
|
|
||
| public function createRules(array $input): array | ||
| { | ||
| return [ | ||
| 'source_control' => [ | ||
| 'required', | ||
| Rule::exists('source_controls', 'id'), | ||
| ], | ||
| 'repository' => [ | ||
| 'required', | ||
| ], | ||
| 'branch' => [ | ||
| 'required', | ||
| ], | ||
| 'port' => [ | ||
| 'required', | ||
| 'numeric', | ||
| 'between:1,65535', | ||
| ], | ||
| ]; | ||
| } | ||
|
|
||
| public function createFields(array $input): array | ||
| { | ||
| return [ | ||
| 'source_control_id' => $input['source_control'] ?? '', | ||
| 'repository' => $input['repository'] ?? '', | ||
| 'branch' => $input['branch'] ?? '', | ||
| 'port' => $input['port'] ?? '', | ||
| ]; | ||
| } | ||
|
|
||
| public function data(array $input): array | ||
| { | ||
| return []; | ||
| } | ||
|
|
||
| /** | ||
| * @throws FailedToDeployGitKey | ||
| * @throws SSHError | ||
| */ | ||
| public function install(): void | ||
| { | ||
| $this->isolate(); | ||
| $this->site->webserver()->createVHost($this->site); | ||
| $this->progress(15); | ||
| $this->deployKey(); | ||
| $this->progress(30); | ||
| app(Git::class)->clone($this->site); | ||
| $this->site->server->ssh($this->site->user)->exec( | ||
| __('bun install --cwd :path', [ | ||
| 'path' => $this->site->path, | ||
| ]), | ||
| 'install-bun-dependencies', | ||
| $this->site->id | ||
| ); | ||
| $this->site->server->ssh($this->site->user)->exec( | ||
| __('bun --bun run --cwd :path build', [ | ||
| 'path' => $this->site->path, | ||
| ]), | ||
| 'bun-build', | ||
| $this->site->id | ||
| ); | ||
| $this->progress(65); | ||
| $command = __('bun --bun run --cwd :path start', [ | ||
| 'path' => $this->site->path, | ||
| ]); | ||
|
Comment on lines
+104
to
+106
|
||
| $this->progress(80); | ||
| /** @var ?Worker $worker */ | ||
| $worker = $this->site->workers()->where('name', 'app')->first(); | ||
| if ($worker) { | ||
| app(ManageWorker::class)->restart($worker); | ||
| } else { | ||
| app(CreateWorker::class)->create( | ||
| $this->site->server, | ||
| [ | ||
| 'name' => 'app', | ||
| 'command' => $command, | ||
| 'user' => $this->site->user ?? $this->site->server->getSshUser(), | ||
| 'auto_start' => true, | ||
| 'auto_restart' => true, | ||
| 'numprocs' => 1, | ||
| ], | ||
| $this->site, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| public function baseCommands(): array | ||
| { | ||
| return [ | ||
| [ | ||
| 'name' => 'bun:install', | ||
| 'command' => 'bun install', | ||
| ], | ||
| [ | ||
| 'name' => 'bun:build', | ||
| 'command' => 'bun --bun run build', | ||
| ], | ||
| ]; | ||
| } | ||
|
|
||
| public function vhost(string $webserver): string|View | ||
| { | ||
| if ($webserver === 'nginx') { | ||
| return view('ssh.services.webserver.nginx.vhost', [ | ||
| 'header' => [ | ||
| view('ssh.services.webserver.nginx.vhost-blocks.force-ssl', ['site' => $this->site]), | ||
| ], | ||
| 'main' => [ | ||
| view('ssh.services.webserver.nginx.vhost-blocks.port', ['site' => $this->site]), | ||
| view('ssh.services.webserver.nginx.vhost-blocks.core', ['site' => $this->site]), | ||
| view('ssh.services.webserver.nginx.vhost-blocks.reverse-proxy', ['site' => $this->site]), | ||
| view('ssh.services.webserver.nginx.vhost-blocks.redirects', ['site' => $this->site]), | ||
| ], | ||
| ]); | ||
| } | ||
|
|
||
| if ($webserver === 'caddy') { | ||
| return view('ssh.services.webserver.caddy.vhost', [ | ||
| 'main' => [ | ||
| view('ssh.services.webserver.caddy.vhost-blocks.force-ssl', ['site' => $this->site]), | ||
| view('ssh.services.webserver.caddy.vhost-blocks.port', ['site' => $this->site]), | ||
| view('ssh.services.webserver.caddy.vhost-blocks.core', ['site' => $this->site]), | ||
| view('ssh.services.webserver.caddy.vhost-blocks.reverse-proxy', ['site' => $this->site]), | ||
| view('ssh.services.webserver.caddy.vhost-blocks.redirects', ['site' => $this->site]), | ||
| ], | ||
| ]); | ||
| } | ||
|
|
||
| return ''; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
--bunflag is typically unnecessary for modern Bun versions and may cause compatibility issues. Bun automatically uses its own runtime by default. Consider simplifying the commands tobun run buildandbun run startunless there's a specific reason to force the Bun runtime (e.g., when Node compatibility mode might otherwise be triggered). This would also make the commands more consistent with the install command which doesn't use--bun.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the
--bunflag is necessary as stated by the bun team because it forces bun to use itself instead of Nodejs for serving the application, this is especially true for Nextjs.