Skip to content

Commit 2782fc4

Browse files
authored
Merge pull request #1152 from hydephp/finalize-build-tasks-api
Finalize the BuildTasks API
2 parents 99cab56 + ce2e3cf commit 2782fc4

27 files changed

+867
-383
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# Custom Build Tasks
2+
3+
## Introduction
4+
5+
The Build Task API offers a simple way to hook into the build process.
6+
The build tasks are very powerful and allow for limitless customizability.
7+
8+
The built-in Hyde features like sitemap generation and RSS feeds are created using tasks like these.
9+
Maybe you want to create your own, to for example upload the site to FTP or copy the files to a public directory?
10+
You can also overload the built-in tasks to customize them to your needs.
11+
12+
13+
## Good to know before you start
14+
15+
### Types of tasks
16+
17+
There are two types, PreBuildTasks and PostBuildTasks. As the names suggest, PreBuildTasks are executed before the site is built, and PostBuildTasks are executed after the site is built.
18+
19+
To choose which type of task you want to create, you extend either the `PreBuildTask` or `PostBuildTask` class.
20+
Both of these have the exact same helpers and API available, so the only difference between them is when they are executed. The classes are otherwise identical.
21+
22+
### About these examples
23+
24+
For most of these examples we will focus on the PostBuildTasks as they are the most common.
25+
26+
For all these examples we assume you put the file in the `App/Actions` directory, but you can put them anywhere.
27+
28+
### Interacting with output
29+
30+
In a way, build tasks are like micro-commands, as they can interact directly with the build commands I/O. Please take a look at the [Laravel Console Documentation](https://laravel.com/docs/10.x/artisan#command-io) for the full list of available methods.
31+
32+
In addition, there are some extra helpers available in the base BuildTask class that allow you to fluently format output to the console, which you will see in the examples below.
33+
34+
## Creating build tasks
35+
36+
37+
### Minimal example
38+
39+
Here is a minimal example to give you an idea of what we are working with.
40+
41+
```php
42+
class SimpleBuildTask extends PostBuildTask
43+
{
44+
public function handle(): void
45+
{
46+
//
47+
}
48+
}
49+
```
50+
51+
As you can see, at their core, build tasks are simple classes containing a `handle()` method,
52+
which as I'm sure you have guessed, is the method that is executed when the task is run by the build command.
53+
54+
If you want the task to run before the build, you would extend the `PreBuildTask` class instead.
55+
56+
#### Automatic output
57+
58+
When running the build command, you will see the following output added after the build is complete.
59+
60+
<pre>
61+
<span style="color: gold">Generic build task...</span> <span style="color: gray">Done in 0.26ms</span>
62+
</pre>
63+
64+
As you can see, some extra output including execution time tracking is added for us. We can of course customize all of this if we want, as you will learn a bit further down.
65+
66+
### Full example
67+
68+
Here is a full example, with all the namespaces included, as well as the most common fluent output helpers.
69+
70+
```php
71+
<?php
72+
73+
namespace App\Actions;
74+
75+
use Hyde\Framework\Features\BuildTasks\PostBuildTask;
76+
77+
class ExampleTask extends PostBuildTask
78+
{
79+
public static string $message = 'Say hello';
80+
81+
public function handle(): void
82+
{
83+
$this->info('Hello World!');
84+
}
85+
86+
public function printFinishMessage(): void
87+
{
88+
$this->line('Goodbye World!');
89+
}
90+
}
91+
```
92+
93+
You can see a full API reference further below. But in short, the `$message` property is the message that runs before the task is executed, and the `printFinishMessage()` method is the message that runs after the task is executed.
94+
95+
Running this task will produce the following output:
96+
97+
<pre>
98+
<small style="color: gray">$ php hyde build</small>
99+
<span style="color: gold">Say hello...</span> <span style="color: green">Hello World!</span>
100+
Goodbye World!
101+
</pre>
102+
103+
As you can see, there is no execution time tracking here, since we overrode the `printFinishMessage()` method that normally prints this. You can of course call the `withExecutionTime()` method to add this back in. See more in the API reference below.
104+
105+
106+
## Registering the tasks
107+
108+
There are a few ways to register these tasks so Hyde can find them.
109+
110+
They are shown here in order of presumed convenience, but you are free to choose whichever you prefer. The latter options are more suited for extension developers.
111+
112+
### Autodiscovery registration
113+
114+
The easiest way to register build tasks, is to not do it. Just let Hyde do it for you!
115+
116+
Any classes that end in `BuildTask.php` that are stored in `app/Actions` will be autoloaded and registered to run automatically.
117+
118+
For example: `app/Actions/ExampleBuildTask.php`.
119+
120+
121+
### Config file registration
122+
123+
If you want, you can also register build tasks of any namespace in the convenient `build_tasks` array which is in the main configuration file, `config/hyde.php`.
124+
125+
```php
126+
// filepath config/hyde.php
127+
'build_tasks' => [
128+
\App\Actions\SimpleTask::class,
129+
\MyPackage\Tasks\MyBuildTask::class,
130+
],
131+
```
132+
133+
### Programmatic registration
134+
135+
>info This option assumes you are familiar with Laravel's service container and service providers.
136+
137+
If you are developing an extension, you can either instruct users register your tasks with the config option above,
138+
or you can register the extensions programmatically, I recommend you do this in the `boot` method of a service provider.
139+
140+
The build tasks are registered in an internal array of the `BuildService` class, which is bound as a singleton in the underlying Laravel service container.
141+
To actually register your task, provide the fully qualified class name of the task to the `BuildTaskService::registerTask()` method.
142+
143+
Here is an example of how to do this using in a service provider. Though you could technically do it anywhere using the `app()` helper, just as long as it's done early enough in the application lifecycle so it's registered before the build command is executed.
144+
145+
```php
146+
class MyServiceProvider extends ServiceProvider
147+
{
148+
public function boot(): void
149+
{
150+
$this->app->make(\Hyde\Framework\Services\BuildTaskService::class)
151+
->registerTask(\MyPackage\Tasks\MyBuildTask::class);
152+
}
153+
}
154+
```

docs/digging-deeper/advanced-customization.md

Lines changed: 0 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -96,81 +96,3 @@ return [
9696
### Setting an absolute path
9797

9898
Since Hyde v0.64.0-beta, the site output directory will always be resolved within the project root. If you want to compile the site to an absolute path outside your project, it's instead recommended that you use a build task to copy the files to the desired location automatically after the site has been compiled.
99-
100-
## Adding custom post-build tasks
101-
102-
These tasks are code that is executed automatically after the site has been built using the `php hyde build` command. The built-in features in Hyde like sitemap generation and RSS feeds are created using tasks like these.
103-
104-
Maybe you want to create your own, to for example upload the site to FTP or copy the files to a public directory? It's easy to do, here's how!
105-
106-
### Minimal example
107-
108-
Here is a minimal example to get you started. For all these examples we assume you put the file in the `App/Actions` directory, but you can put them anywhere.
109-
110-
```php
111-
class SimpleTask extends BuildTask
112-
{
113-
public function run(): void
114-
{
115-
$this->info('Hello World!');
116-
}
117-
}
118-
```
119-
120-
This will then output the following, where you can see that some extra output, including execution time tracking is added for us. We can of course customize this if we want, as you can see in the next example.
121-
122-
<pre>
123-
<small style="color: gray">$ php hyde build</small>
124-
<span style="color: gold">Generic build task...</span> Hello World! <span style="color: gray">Done in 0.26ms</span>
125-
</pre>
126-
127-
128-
### Full example
129-
130-
You can also set the message, and an optional `then()` method to run after the main task has been executed. The then method is great if you want to display a status message.
131-
132-
```php
133-
<?php
134-
135-
namespace App\Actions;
136-
137-
use Hyde\Framework\Features\BuildTasks\BuildTask;
138-
139-
class ExampleTask extends BuildTask
140-
{
141-
public static string $message = 'Say hello';
142-
143-
public function run(): void
144-
{
145-
$this->info('Hello World!');
146-
}
147-
148-
public function then(): void
149-
{
150-
$this->line('Goodbye World!');
151-
}
152-
}
153-
```
154-
155-
<pre>
156-
<small style="color: gray">$ php hyde build</small>
157-
<span style="color: gold">Say hello...</span> <span style="color: green">Hello World!</span>
158-
Goodbye World!
159-
</pre>
160-
161-
162-
### Registering the tasks
163-
164-
There are a few ways to register these tasks so Hyde can find them. There is a convenient place to do this, which is in the main configuration file, `config/hyde.php`.
165-
166-
```php
167-
// filepath config/hyde.php
168-
'post_build_tasks' => [
169-
\App\Actions\SimpleTask::class,
170-
\App\Actions\ExampleTask::class,
171-
],
172-
```
173-
174-
If you are developing an extension, I recommend you do this in the `boot` method of a service provider so that it can be loaded automatically. Do this by adding the fully qualified class name to the `BuildTaskService::$postBuildTasks` array.
175-
176-
Hyde can also autoload them if you store the files in the `app/Actions` directory and the names end in `BuildTask.php`. For example `app/Actions/ExampleBuildTask.php`.

packages/framework/src/Console/Commands/BuildRssFeedCommand.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Hyde\Console\Commands;
66

7-
use Hyde\Framework\Features\BuildTasks\PostBuildTasks\GenerateRssFeed;
7+
use Hyde\Framework\Actions\PostBuildTasks\GenerateRssFeed;
88
use LaravelZero\Framework\Commands\Command;
99

1010
/**
@@ -22,6 +22,6 @@ class BuildRssFeedCommand extends Command
2222

2323
public function handle(): int
2424
{
25-
return (new GenerateRssFeed($this->output))->handle();
25+
return (new GenerateRssFeed())->run($this->output);
2626
}
2727
}

packages/framework/src/Console/Commands/BuildSearchCommand.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Hyde\Console\Commands;
66

7-
use Hyde\Framework\Features\BuildTasks\PostBuildTasks\GenerateSearch;
7+
use Hyde\Framework\Actions\PostBuildTasks\GenerateSearch;
88
use LaravelZero\Framework\Commands\Command;
99

1010
/**
@@ -22,6 +22,6 @@ class BuildSearchCommand extends Command
2222

2323
public function handle(): int
2424
{
25-
return (new GenerateSearch($this->output))->handle();
25+
return (new GenerateSearch())->run($this->output);
2626
}
2727
}

packages/framework/src/Console/Commands/BuildSiteCommand.php

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@
55
namespace Hyde\Console\Commands;
66

77
use Hyde\Console\Concerns\Command;
8-
use Hyde\Facades\Features;
9-
use Hyde\Framework\Features\BuildTasks\PostBuildTasks\GenerateRssFeed;
10-
use Hyde\Framework\Features\BuildTasks\PostBuildTasks\GenerateSearch;
11-
use Hyde\Framework\Features\BuildTasks\PostBuildTasks\GenerateSitemap;
128
use Hyde\Framework\Services\BuildService;
139
use Hyde\Framework\Services\BuildTaskService;
1410
use Hyde\Hyde;
@@ -34,6 +30,7 @@ class BuildSiteCommand extends Command
3430
protected $description = 'Build the static site';
3531

3632
protected BuildService $service;
33+
protected BuildTaskService $taskService;
3734

3835
public function handle(): int
3936
{
@@ -43,9 +40,10 @@ public function handle(): int
4340

4441
$this->service = new BuildService($this->output);
4542

46-
$this->runPreBuildActions();
43+
$this->taskService = app(BuildTaskService::class);
44+
$this->taskService->setOutput($this->output);
4745

48-
$this->service->cleanOutputDirectory();
46+
$this->runPreBuildActions();
4947

5048
$this->service->transferMediaAssets();
5149

@@ -73,11 +71,13 @@ protected function runPreBuildActions(): void
7371
$this->newLine();
7472
Config::set(['hyde.pretty_urls' => true]);
7573
}
74+
75+
$this->taskService->runPreBuildTasks();
7676
}
7777

7878
public function runPostBuildActions(): void
7979
{
80-
$service = new BuildTaskService($this->output);
80+
$this->taskService->runPostBuildTasks();
8181

8282
if ($this->option('run-prettier')) {
8383
$this->runNodeCommand(
@@ -94,12 +94,6 @@ public function runPostBuildActions(): void
9494
if ($this->option('run-prod')) {
9595
$this->runNodeCommand('npm run prod', 'Building frontend assets for production!');
9696
}
97-
98-
$service->runIf(GenerateSitemap::class, $this->canGenerateSitemap());
99-
$service->runIf(GenerateRssFeed::class, $this->canGenerateFeed());
100-
$service->runIf(GenerateSearch::class, $this->canGenerateSearch());
101-
102-
$service->runPostBuildTasks();
10397
}
10498

10599
protected function printFinishMessage(float $timeStart): void
@@ -142,21 +136,6 @@ protected function runNodeCommand(string $command, string $message, ?string $act
142136
));
143137
}
144138

145-
protected function canGenerateSitemap(): bool
146-
{
147-
return Features::sitemap();
148-
}
149-
150-
protected function canGenerateFeed(): bool
151-
{
152-
return Features::rss();
153-
}
154-
155-
protected function canGenerateSearch(): bool
156-
{
157-
return Features::hasDocumentationSearch();
158-
}
159-
160139
protected function hasWarnings(): bool
161140
{
162141
return BuildWarnings::hasWarnings() && BuildWarnings::reportsWarnings();

packages/framework/src/Console/Commands/BuildSitemapCommand.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Hyde\Console\Commands;
66

7-
use Hyde\Framework\Features\BuildTasks\PostBuildTasks\GenerateSitemap;
7+
use Hyde\Framework\Actions\PostBuildTasks\GenerateSitemap;
88
use LaravelZero\Framework\Commands\Command;
99

1010
/**
@@ -22,6 +22,6 @@ class BuildSitemapCommand extends Command
2222

2323
public function handle(): int
2424
{
25-
return (new GenerateSitemap($this->output))->handle();
25+
return (new GenerateSitemap())->run($this->output);
2626
}
2727
}

0 commit comments

Comments
 (0)