使用 Termwind 增强您的 Artisan 命令

发布于 作者:

Supercharging Your Artisan Commands With Termwind image

如果您正在构建 Laravel 应用程序、软件包或 CLI(命令行界面)应用程序,您很可能会在某个阶段创建自己的自定义 Artisan 命令。创建这些命令时,您可能希望使输出独特并从其他控制台输出中脱颖而出。为此,您可以使用很棒的 Termwind 软件包。

在本文中,我们将介绍 Termwind 是什么,如何安装它以及如何在自己的 Artisan 命令中使用它。然后,我们将逐步更新旧的示例 Artisan 命令以使用 Termwind,并了解它如何改善输出。

什么是 Termwind?

Termwind 是由 Nuno Maduro(以及其他很棒的贡献者,例如 Francisco Madeira)创建和维护的 PHP 软件包,它允许您在 PHP 代码中使用类似 Tailwind 的 CSS 类来为 CLI 输出添加样式。

如果您希望使命令的输出看起来独特并从人群中脱颖而出,这是一个非常棒的工具。因此,如果您正在构建 CLI 应用程序或提供任何 Artisan 命令的 Laravel 软件包,它非常方便使用。

它为您提供了使用 HTML 和类似 Tailwind 的类(例如 text-blue-500flexspace-x-1)构建输出的能力。您可以在 软件包的文档中查看可用类的完整列表。

用法

安装

要开始在 Laravel 应用程序中使用 Termwind,您需要使用 Composer 安装它,方法是运行以下命令

composer require nunomaduro/termwind

就是这样!Termwind 现在已安装并可以使用。

使用内联 HTML 显示输出

现在我们已经安装了 Termwind,让我们看看如何使用它将一些输出呈现到 CLI。

呈现输出的最快方法是将一些 HTML 作为字符串直接传递给软件包的 render 函数。

为了更好地理解这一点,让我们看一个简单的例子。假设我们有一个 Artisan 命令,我们可以使用它来输出有关 Laravel 应用程序的一些统计信息。为了便于本文的理解,我们将使用硬编码的统计信息,这样我们就可以专注于 Termwind 本身。

那么,让我们看一下该命令

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;
}
}

上面的命令将以下内容输出到 CLI

如您所见,我们可以使用 Termwind 生成一些非常酷的输出。但是,将 HTML 直接放在命令类中会很快变得很乱。它可读性或可维护性不强。例如,如果我们想在其他命令中使用相同的样式,我们可能会重复很多共享的 HTML。

不过,需要注意的是,对于少量输出,这种方法可能完全可以。只是当您开始拥有大量输出时,维护起来会变得有点乏味。

Termwind 的 style 函数可以帮助我们将样式分组在一起,以便我们可以在多个地方重复使用它们。但是,这并不一定解决构建输出结构的实际 HTML 的问题。我建议您查看 文档中的 style 函数,以了解如何使用它来简化维护工作。

使用视图显示输出

既然我们已经了解了如何直接将一些 HTML 输出到 CLI,让我们看看如何使用 Blade 视图来呈现输出。我更喜欢使用这种方法,因为它使 HTML 与命令类分离,并使跨不同命令的维护和重复使用变得更容易。

首先,让我们在项目的 resources/views 目录中创建一个新的 cli 目录。我们将在此处存储所有特定于 CLI 的视图。

然后,我们将在 cli 目录中创建一个新的 app-stats.blade.php 视图。这将是我们用来呈现 app:stats 命令输出的视图,它将包含我们之前示例中的 HTML(<<<'HTML'HTML 之间的所有内容)。

现在我们已经将 HTML 放置在 Blade 视图中,我们可以更新命令类以使用它。我们将通过使用 view 帮助器函数来渲染视图并将它的输出传递给 Termwind 的 render 函数来实现这一点

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;
}

如您所见,这使得命令类更容易理解和维护。我们现在可以专注于命令的逻辑,而不必担心 HTML 混乱这个类。

使用这种方法的一个巨大的好处是,它还允许我们使用 Blade 组件来使我们的输出更具可重复使用性。我们可以为输出的不同部分创建组件,然后在我们的视图中使用它们。

让我们看看如何使用一些 Blade 组件来提高命令的可维护性。

我们将从在 resources/views 目录中创建一个新的 components/cli 目录开始。类似于我们的 resources/views/cli 目录,我们将在此处保存所有特定于 CLI 的 Blade 组件。

我们可以在上面的示例中确定命令输出的两个主要部分,可以将其拆分为组件

  1. 总计
  2. 健康检查

因此,我们将为每个部分创建一个组件。请记住,您可以根据项目的需要创建尽可能少或尽可能多的组件。

让我们从在 resources/views/components/cli 目录中创建一个新的 totals.blade.php 组件开始。此组件将用于呈现我们拥有的每个统计信息的总计。

@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>

如您所见,此组件非常简单,并使用 @props Blade 指令定义了 2 个不同的属性。它接受两个属性,titlevalue。这是一种确保我们不会忘记将任何必需属性传递给组件的好方法。

我们现在还可以在 resources/views/components/cli 目录中创建一个新的 connection.blade.php 组件

@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>

您可能已经注意到,该组件使用 @props Blade 指令定义了 3 个不同的属性。这强制我们在使用该组件时必须传递一个 title 属性、subText 属性和一个可选的 connected 属性。

正如我们在之前的示例中看到的那样,如果 connected 属性设置为 true,则该组件将以绿色输出 CONNECTED 文本。否则,它将以红色输出 ERROR! 文本。

现在我们已经创建了组件并已准备就绪,我们可以将 resources/views/cli/app-stats.blade.php 视图转换为使用它们

<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>

如您所见,HTML 现在更易于阅读和理解。我们通过使用 <x-cli.stat ... /><x-cli.connection ... /> Blade 语法来调用组件,从而减少了重复 HTML 的数量。我喜欢这种方法的一点是,因为我们可以使用 Blade,它使构建 CLI 输出的感觉与构建 Web 视图非常相似。

转换现有命令

现在我们已经了解了如何使用 Termwind 将 HTML 输出到 CLI,让我们简要了解一下如何转换现有命令以使用 Termwind。

假设我们有一个 Artisan 命令,它执行以下操作

  • 询问用户搜索词。
  • 在数据库中搜索任何电子邮件地址包含搜索词的用户。
  • 将结果输出到 CLI。

这只是一个简单的示例,但它应该能让我们很好地展示 Termwind 提供的一些功能。为了便于说明,我们不会介绍如何搜索数据库以获取用户,因为这不是本文的重点。但是,我们可以假设下面示例中的 searchUsers 方法将返回一个 User 模型的 Collection

我们现有的命令可能看起来像这样

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;
}
}

上面的命令将提供以下输出

如果我们想更新命令以使用 Termwind,我们的类可能看起来像这样

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;
}
}

让我们看看发生了什么变化。

您可能已经注意到,我们已经用 Termwind 的 ask 函数替换了 $this->ask 调用。这将为我们提供与现有命令类似的体验,但额外的好处是可以使用 Termwind 的样式。

我们还通过将命令其余的输出移动到一个 resources/views/cli/user-search.blade.php Blade 视图中(就像我们在本文前面介绍的那样)来替换了 $this->info$this->table 调用。正如我们所见,我们以与向 Web 视图传递数据完全相同的方式将 $users 集合传递给视图。Blade 视图看起来像这样

<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>

在 Blade 文件中,我们显示了找到的用户的总数,然后循环遍历传递给视图的 users 集合并输出用户的姓名、电子邮件以及他们是否已获批准。

由于进行了这些更改,命令现在输出以下内容

我们现在已经成功地将 Artisan 命令转换为使用 Termwind!

结论

希望这篇文章能让你对 Termwind 是什么以及如何使用它为你的 Artisan 命令构建出色的 CLI 输出有一个了解。你现在应该能够使用 Termwind 转换现有的命令,甚至从头开始构建新的命令。

如果你想了解更多关于 Termwind 的信息,你可以查看 GitHub 上的 文档

Ashley Allen photo

我是一位自由职业的 Laravel Web 开发人员,热衷于为开源项目做贡献,构建令人兴奋的系统,并帮助他人学习 Web 开发。

Cube

Laravel 新闻

加入 40,000 多名其他开发人员,绝不错过新的提示、教程等等。

Laravel Forge logo

Laravel Forge

轻松创建和管理服务器,并在几秒钟内部署您的 Laravel 应用程序。

Laravel Forge
Tinkerwell logo

Tinkerwell

Laravel 开发人员必备的代码运行器。使用 AI、自动完成和对本地和生产环境的即时反馈进行调试。

Tinkerwell
No Compromises logo

No Compromises

来自 No Compromises 播客的两位经验丰富的开发者 Joel 和 Aaron 现已开放接洽您的 Laravel 项目。⬧ 固定费率为 7500 美元/月。⬧ 没有冗长的销售流程。⬧ 没有合同。⬧ 100% 返款保证。

No Compromises
Kirschbaum logo

Kirschbaum

提供创新和稳定性,以确保您的 Web 应用程序取得成功。

Kirschbaum
Shift logo

Shift

运行旧版 Laravel 版本?即时、自动化的 Laravel 升级和代码现代化,让您的应用程序保持新鲜。

Shift
Bacancy logo

Bacancy

只需 2500 美元/月,即可使用经验丰富的 Laravel 开发人员(拥有 4-6 年的经验)为您的项目增效。获得 160 小时的专业知识和 15 天的无风险试用。立即安排通话!

Bacancy
Lucky Media logo

Lucky Media

立即获得好运 - Laravel 开发的理想选择,拥有超过十年的经验!

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel 电子商务

Laravel 电子商务。一个开源软件包,将现代无头电子商务功能的强大功能带到 Laravel。

Lunar: Laravel 电子商务
LaraJobs logo

LaraJobs

官方 Laravel 职位板

LaraJobs
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS 启动工具包

SaaSykit 是一款 Laravel SaaS 启动工具包,它包含运行现代 SaaS 所需的所有功能。付款、精美结账、管理面板、用户仪表板、身份验证、现成组件、统计数据、博客、文档等等。

SaaSykit: Laravel SaaS 启动工具包
Rector logo

Rector

您无缝进行 Laravel 升级、降低成本和加速创新以帮助企业成功的合作伙伴

Rector
MongoDB logo

MongoDB

使用 MongoDB 和 Laravel 的强大集成来增强您的 PHP 应用程序,使开发人员能够轻松高效地构建应用程序。支持事务性、搜索、分析和移动用例,同时使用熟悉的 Eloquent API。了解灵活、现代的 MongoDB 数据库如何改变您的 Laravel 应用程序。

MongoDB
Maska is a Simple Zero-dependency Input Mask Library image

Maska 是一个简单的零依赖输入掩码库

阅读文章
Add Swagger UI to Your Laravel Application image

将 Swagger UI 添加到您的 Laravel 应用程序

阅读文章
Assert the Exact JSON Structure of a Response in Laravel 11.19 image

在 Laravel 11.19 中断言响应的精确 JSON 结构

阅读文章
Build SSH Apps with PHP and Laravel Prompts image

使用 PHP 和 Laravel 提示构建 SSH 应用程序

阅读文章
Building fast, fuzzy site search with Laravel and Typesense image

使用 Laravel 和 Typesense 构建快速、模糊的网站搜索

阅读文章
Add Comments to your Laravel Application with the Commenter Package image

使用 Commenter 包向您的 Laravel 应用程序添加评论

阅读文章