If you're building a Laravel application, package, or CLI (commoraz-line interface) application, you'll likely create your own custom Artisan commorazs at some stage. When creating these commorazs, you might want to make the output unique oraz storaz out from the rest z the console output. To do this, you can the awesome Termwind pakiet.
W tym artykule przyjrzymy się, czym jest Termwind, jak go zainstalować i jak używać go we własnych poleceniach Artisan. Następnie krok po kroku zaktualizujemy starą przykładową komendę Artisan, aby używać Termwind i zobaczymy, jak poprawia to wydajność.
Co to jest Termwind?
Termwind to pakiet PHP stworzony i utrzymywany przez Nuno Maduro (i inni niesamowici autorzy, tacy jak Franciszek Madera), który umożliwia używanie klas CSS podobnych do Tailwind w kodzie PHP w celu dodania stylów do danych wyjściowych CLI.
To świetne narzędzie, jeśli chcesz, aby dane wyjściowe Twoich poleceń wyglądały wyjątkowo i wyróżniały się z tłumu. Jest więc bardzo przydatny, jeśli budujesz aplikację CLI lub pakiet Laravel, który udostępnia dowolne polecenia Artisan.
Zapewnia możliwość budowania danych wyjściowych przy użyciu HTML i klas podobnych do Tailwind, takich jak tekst-niebieski-500
, przewód
and spacja-x-1
. Możesz sprawdzić pełną listę dostępnych klas w package's dokumentacja.
Stosowanie
Instalacja
Aby rozpocząć korzystanie z Termwind w swoich aplikacjach Laravel, musisz zainstalować go za pomocą Composer, uruchamiając następujące polecenie:
composer require nunomaduro/termwind
Otóż to! Termwind jest teraz zainstalowany i gotowy do pracy.
Wyświetlanie danych wyjściowych przy użyciu wbudowanego kodu HTML
Now that we have Termwind installed, let's take a look at how we can use it to renderowanieowanie some output to the CLI.
Najszybszym sposobem renderowania danych wyjściowych jest przekazanie kodu HTML jako ciągu znaków bezpośrednio do pakietu render
funkcjonować.
Aby nadać temu nieco kontekstu, spójrzmy na prosty przykład. Wyobraźmy sobie, że mamy polecenie Artisan, którego możemy użyć do wygenerowania statystyk dotyczących naszej aplikacji Laravel. Na potrzeby tego artykułu będziemy używać zakodowanych na stałe statystyk, abyśmy mogli skupić się wyłącznie na Termwind.
Spójrzmy więc na polecenie:
namespace App\Console\Commands;
use Illuminate\Console\Command;
use function Termwind\{render};
class AppStats extends Command
{
protected $signature = 'app:stats';
protected $description = 'Display the application stats';
public function handle(): int
{
render(<<<'HTML'
<div class="mx-2 my-1">
<div class="space-x-1">
<span class="px-1 bg-blue-500 text-white">Application Info</span>
</div>
<div class="mt-1">
<span class="font-bold text-green">Totals</span>
<div class="flex space-x-1">
<span class="font-bold">Users</span>
<span class="flex-1 content-repeat-[.] text-gray"></span>
<span class="font-bold text-green">150</span>
</div>
<div class="flex space-x-1">
<span class="font-bold">Posts</span>
<span class="flex-1 content-repeat-[.] text-gray"></span>
<span class="font-bold text-green">200</span>
</div>
<div class="flex space-x-1">
<span class="font-bold">Comments</span>
<span class="flex-1 content-repeat-[.] text-gray"></span>
<span class="font-bold text-green">175</span>
</div>
</div>
<div class="mt-1">
<span class="font-bold text-green">Health Checks</span>
<div class="flex space-x-1">
<span class="font-bold">Mailcoach</span>
<i class="text-gray">Newsletter</i>
<span class="flex-1 content-repeat-[.] text-gray"></span>
<span class="font-bold text-green">CONNECTED</span>
</div>
<div class="flex space-x-1">
<span class="font-bold">Vonage</span>
<i class="text-gray">SMS</i>
<span class="flex-1 content-repeat-[.] text-gray"></span>
<span class="font-bold text-red">ERROR!</span>
</div>
</div>
</div>
HTML);
return self::SUCCESS;
}
}
Powyższe polecenie wyświetli następujące informacje w CLI:
As you can see, we can generate some really cool output using Termwind. But having the HTML directly in the command class can become messy very quickly. It's not very readable or maintainable. For example, if we wanted to use the same styls in other commands, we'd potentially be duplicating a lot of the shared HTML.
Warto jednak zauważyć, że w przypadku mniejszych ilości danych wyjściowych takie podejście może być całkowicie w porządku. Tylko wtedy, gdy zaczynasz mieć dużo danych wyjściowych, utrzymanie może stać się nieco uciążliwe.
Termwinda styl
może nam pomóc w grupowaniu stylów, abyśmy mogli ich ponownie używać w wielu miejscach. Jednak niekoniecznie rozwiązuje to problem rzeczywistego kodu HTML, który buduje strukturę danych wyjściowych. Polecam sprawdzić tzw style
funkcję w dokumentacji aby dowiedzieć się więcej o tym, jak możesz go użyć, aby uprościć konserwację.
Wyświetlanie danych wyjściowych za pomocą widoku
Now that we've seen how to output some HTML directly to the CLI, let's take a look at how we can use a Blade pogląd to render the output. I prefer using this approach as it keeps the HTML separate from the command class and makes it easier to maintain and reuse across different commands.
Na początek utwórzmy nowy cli
katalog w naszym projects zasoby/widoki
informator. Tutaj będziemy przechowywać wszystkie nasze widoki specyficzne dla CLI.
Następnie utworzymy nowy app-stats.blade.php
widok w cli
informator. To będzie widok, którego użyjemy do renderowania danych wyjściowych dla naszego aplikacja: statystyki
polecenie i będzie zawierało kod HTML z naszego poprzedniego przykładu (wszystko pomiędzy <<<'HTML'
and HTML
).
Teraz, gdy mamy kod HTML w widoku Blade, możemy zaktualizować naszą klasę poleceń, aby go używać. Zrobimy to za pomocą view
pomocnika, aby renderować widok i przekazywać jego dane wyjściowe do Termwind render
funkcjonować:
namespace App\Console\Commands;
use Illuminate\Console\Command;
use function Termwind\{render};
class AppStats extends Command
{
protected $signature = 'app:stats';
protected $description = 'Display the application stats';
public function handle(): int
{
render(view('cli.app-stats'));
return self::SUCCESS;
}
Jak widać, znacznie ułatwiło to zrozumienie i utrzymanie klasy poleceń. Możemy teraz skupić się na logice polecenia i nie martwić się o zaśmiecanie tej klasy przez kod HTML.
Ogromną korzyścią wynikającą z zastosowania tego podejścia jest to, że pozwala nam ono również wykorzystywać komponenty Blade, aby nasze wyniki były jeszcze bardziej przydatne do ponownego wykorzystania. Możemy utworzyć komponent dla każdej z różnych sekcji danych wyjściowych, a następnie użyć ich w naszym widoku.
Przyjrzyjmy się, jak możemy wykorzystać niektóre komponenty Blade, aby poprawić łatwość konserwacji naszego polecenia.
Zaczniemy od utworzenia nowego komponenty/kli
directory in our zasoby/widoki
informator. Podobny do naszego zasoby/widoki/cli
katalog, w którym będziemy przechowywać wszystkie nasze komponenty Blade specyficzne dla CLI.
W powyższym przykładzie możemy zidentyfikować dwie główne części danych wyjściowych naszego polecenia, które można podzielić na komponenty:
- Sumy
- Kontrole stanu zdrowia
Stworzymy więc komponent dla każdego z nich. Pamiętaj jednak, że możesz stworzyć tyle komponentów, ile chcesz, aby pasowały do potrzeb twojego projektu.
Zacznijmy od utworzenia nowego totals.blade.php
składnik w zasoby/widoki/komponenty/cli
informator. Ten komponent będzie używany do renderowania sum dla każdej posiadanej statystyki.
@props([
'title',
'value',
])
<div class="flex space-x-1">
<span class="font-bold">{{ $title }}</span>
<span class="flex-1 content-repeat-[.] text-gray"></span>
<span class="font-bold text-green">{{ $value }}</span>
</div>
Jak widać, ten komponent jest bardzo prosty i ma 2 różne właściwości zdefiniowane za pomocą @rekwizyty
Dyrektywa ostrza. Akceptuje dwie właściwości, tytuł
and wartość
. To świetny sposób, aby upewnić się, że nie zapomnimy przekazać żadnych wymaganych właściwości do komponentu.
Teraz możemy również utworzyć nowy połączenie.blade.php
składnik w zasoby/widoki/komponenty/cli
informator:
@props([
'title',
'subText',
'connected' => false,
])
<div class="flex space-x-1">
<span class="font-bold">{{ $title }}</span>
<i class="text-gray">{{ $subText }}</i>
<span class="flex-1 content-repeat-[.] text-gray"></span>
@if($connected)
<span class="font-bold text-green">CONNECTED</span>
@else
<span class="font-bold text-red">ERROR!</span>
@endif
</div>
Być może zauważyłeś, że komponent ma 3 różne właściwości zdefiniowane za pomocą @rekwizyty
Dyrektywa ostrza. Wymusza to, że musimy przekazać a tytuł
własność, podtekst
właściwość i opcjonalne połączony
właściwość za każdym razem, gdy używamy komponentu.
Jak widać z naszego wcześniejszego przykładu, jeśli plik połączony
właściwość jest ustawiona na PRAWDA
, komponent wyświetli plik POŁĄCZONY
tekst na zielono. W przeciwnym razie wyprowadzi plik BŁĄD!
tekst na czerwono.
Teraz, gdy mamy utworzone i gotowe komponenty, możemy przekonwertować nasz zasoby/widoki/cli/app-stats.blade.php
zobacz, jak z nich korzystać:
<div class="mx-2 my-1">
<div class="space-x-1">
<span class="px-1 bg-blue-500 text-white">Application Info</span>
</div>
<div class="mt-1">
<span class="font-bold text-green">Totals</span>
<x-cli.stat title="Users" value="150" />
<x-cli.stat title="Posts" value="200" />
<x-cli.stat title="Comments" value="175" />
</div>
<div class="mt-1">
<span class="font-bold text-green">Health Checks</span>
<x-cli.connection title="Mailcoach" subText="Newsletter" :connected="true" />
<x-cli.connection title="Vonage" subText="SMS" :connected="false" />
</div>
</div>
Jak widać, kod HTML jest teraz znacznie łatwiejszy do odczytania i zrozumienia. Udało nam się zmniejszyć ilość zduplikowanego kodu HTML, wywołując komponenty using <x-cli.stat ... />
and <x-cli.połączenie ... />
Składnia ostrza. Jedną z rzeczy, które podobają mi się w tym podejściu, jest to, że dzięki możliwości korzystania z Blade’a tworzenie danych wyjściowych CLI jest bardzo podobne do tworzenia widoków internetowych.
Konwersja istniejącego polecenia
Teraz, gdy widzieliśmy, jak możemy wyświetlać HTML do CLI za pomocą Termwind, przyjrzyjmy się pokrótce, jak możemy przekonwertować istniejące polecenie, aby używało Termwind.
Wyobraźmy sobie, że mamy polecenie Artisan, które wykonuje następujące czynności:
- Pyta użytkownika o wyszukiwane hasło.
- Searches the database for any użytkownicy that have an email address that contains the search term.
- Wysyła wyniki do CLI.
To tylko prosty przykład, ale powinien dać nam dobrą szansę na podkreślenie kilku funkcji, które zapewnia Termwind. Na potrzeby przykładu nie będziemy również omawiać sposobu przeszukiwania bazy danych pod kątem użytkowników, ponieważ nie jest to tematem tego artykułu. Ale możemy założyć, że searchUżytkowniks
metoda w poniższym przykładzie zwróci a Kolekcja
of User
modele.
Nasze istniejące polecenie może wyglądać mniej więcej tak:
namespace App\Console\Commands;
use App\Models\User;
use Illuminate\Console\Command;
final class UsersSearch extends Command
{
protected $signature = 'users:search';
protected $description = 'Search for users in the system';
public function handle(): int
{
$searchTerm = $this->ask('Search term: ');
$users = $this->searchUsers($searchTerm);
$rows = $users->map(fn (User $user): array => [
$user->name,
$user->email,
$user->email_verified_at ?? 'No!',
])->all();
$this->info('Found '.count($users).' users');
$this->table(['Name', 'Email', 'Approved'], $rows);
return self::SUCCESS;
}
}
Powyższe polecenie dałoby następujące dane wyjściowe:
Gdybyśmy chcieli zaktualizować polecenie, aby używało Termwind, nasza klasa mogłaby wyglądać tak:
namespace App\Console\Commands;
use App\Models\User;
use Illuminate\Console\Command;
use function Termwind\{ask, render};
final class UsersSearch extends Command
{
protected $signature = 'users:search';
protected $description = 'Search for users in the system';
public function handle(): int
{
$searchTerm = ask(<<<HTML
<span class="mt-1 ml-2 mr-1 bg-green px-1 text-black">
Search term:
</span>
HTML);
$users = $this->searchUsers($searchTerm);
render(view('cli.user-search', [
'users' => $users,
]));
return self::SUCCESS;
}
}
Przyjrzyjmy się, co się zmieniło.
Jak zapewne zauważyliście, wymieniliśmy plik $this->zapytać się
zadzwoń z Termwind ask
funkcjonować. Zapewni nam to doświadczenie podobne do istniejącego polecenia, ale z dodatkową korzyścią w postaci możliwości korzystania ze stylu Termwind.
Wymieniliśmy również tzw $to->informacje
and $to->tabela
wywołań, przenosząc resztę danych wyjściowych polecenia do a zasoby/widoki/cli/user-search.blade.php
Widok ostrza (jak omówiliśmy wcześniej w tym artykule). Jak widać, minęliśmy $użytkowników
kolekcji do widoku w dokładnie taki sam sposób, w jaki moglibyśmy przekazać dane do widoku internetowego. Widok Blade'a wygląda tak:
<div class="m-1">
<div class="text-right mb-1 w-full">
<span class="text-indigo-500">Found [<b>{{ $users->count() }}</b>] users</span>
</div>
@foreach($users as $user)
<div>
<div class="flex space-x-1">
<span class="font-bold">{{ $user->name }}</span>
<span class="text-gray">[{{ $user->email }}]</span>
<span class="flex-1 content-repeat-[.] text-gray"></span>
<span class="text-gray">Approved:</span>
@if($user->email_verified_at)
<span class="font-bold text-green">{{ $user->email_verified_at }}</span>
@else
<span class="font-bold text-red">NO!</span>
@endif
</div>
</div>
@endforeach
</div>
W pliku Blade wyświetlamy całkowitą liczbę znalezionych użytkowników, a następnie przeglądamy plik users
Kolekcja przekazywana do widoku i wyświetlająca nazwy użytkowników, adresy e-mail oraz informacje o tym, czy zostały zatwierdzone.
W wyniku wprowadzenia tych zmian polecenie wyświetla teraz następujące informacje:
Pomyślnie przekonwertowaliśmy polecenie Artisan, aby używało Termwind!
Wniosek
Mamy nadzieję, że ten artykuł powinien dać ci przegląd tego, czym jest Termwind i jak możesz go używać do tworzenia niesamowitych wyjść CLI dla twoich poleceń Artisan. Powinieneś teraz być w stanie wziąć istniejące polecenia i przekonwertować je, aby używały Termwind, a nawet rozpocząć tworzenie nowych poleceń od podstaw.
Jeśli chcesz przeczytać więcej o Termwind, możesz sprawdzić documentation na GitHubie.