Skip to content

Custom Build Tasks

Introduction

The Build Task API offers a simple way to hook into the build process. The build tasks are very powerful and allow for limitless customizability.

The built-in Hyde features like sitemap generation and RSS feeds are created using tasks like these. Maybe you want to create your own, to for example upload the site to FTP or copy the files to a public directory? You can also overload the built-in tasks to customize them to your needs.

Good to know before you start

Types of tasks

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.

To choose which type of task you want to create, you extend either the PreBuildTask or PostBuildTask class. 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.

About these examples

For most of these examples we will focus on the PostBuildTasks as they are the most common.

For all these examples we assume you put the file in the App/Actions directory, but you can put them anywhere.

Interacting with output

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 for the full list of available methods.

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.

Creating Build Tasks

Minimal example

Here is a minimal example to give you an idea of what we are working with.

1class SimpleBuildTask extends PostBuildTask
2{
3 public function handle(): void
4 {
5 //
6 }
7}

As you can see, at their core, build tasks are simple classes containing a handle() method, which as I'm sure you have guessed, is the method that is executed when the task is run by the build command.

If you want the task to run before the build, you would extend the PreBuildTask class instead.

Automatic output

When running the build command, you will see the following output added after the build is complete.

 Generic build task... Done in 0.26ms

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.

Full example

Here is a full example, with all the namespaces included, as well as the most common fluent output helpers.

1<?php
2 
3namespace App\Actions;
4 
5use Hyde\Framework\Features\BuildTasks\PostBuildTask;
6 
7class ExampleTask extends PostBuildTask
8{
9 public static string $message = 'Say hello';
10 
11 public function handle(): void
12 {
13 $this->info('Hello World!');
14 }
15 
16 public function printFinishMessage(): void
17 {
18 $this->line('Goodbye World!');
19 }
20}

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.

Running this task will produce the following output:

$ php hyde build
  Say hello... Hello World!
  Goodbye World!

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.

Registering the Tasks

There are a few ways to register these tasks so Hyde can find them.

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.

Autodiscovery registration

The easiest way to register build tasks is to not do it -- just let Hyde do it for you!

Any classes that end in BuildTask.php that are stored in app/Actions will be autoloaded and registered to run automatically.

For example: app/Actions/ExampleBuildTask.php.

Config file registration

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.

Filepath: config/hyde.php
1'build_tasks' => [
2 \App\Actions\SimpleTask::class,
3 \MyPackage\Tasks\MyBuildTask::class,
4],

Programmatic registration

This option assumes you are familiar with Laravel's service container and service providers.

If you are developing an extension, you can either instruct users register your tasks with the config option above, or you can register the extensions programmatically, I recommend you do this in the boot method of a service provider.

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. To actually register your task, provide the fully qualified class name of the task to the BuildTaskService::registerTask() method.

Here is an example of how to do this using 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.

1class MyServiceProvider extends ServiceProvider
2{
3 public function boot(): void
4 {
5 $this->app->make(\Hyde\Framework\Services\BuildTaskService::class)
6 ->registerTask(\MyPackage\Tasks\MyBuildTask::class);
7 }
8}

Error handling

If an exception is thrown in a build task, the build command will catch it and display the error message to the user.

Helper methods

Output helpers

When a build task is called by the site build command, it gets access to the Laravel and Symfony console output helpers through the $output property.

1public function handle(): void
2{
3 /** @var \Illuminate\Console\OutputStyle $output */
4 
5 $this->output->info('Hello World!');
6 $this->output->error('Something went wrong!');
7 $this->output->writeln('This is a line of text');
8}

Skipping tasks

This feature was added in HydePHP v1.6.0

If you for some reason need to skip the task during its execution, you can call the skip() method.

1public function handle(): void
2{
3 if ($this->someCondition() !== true) {
4 $this->skip('Some condition was not met');
5 
6 // The task will not be executed past this point
7 }
8}

This will then halt the execution of the task, and display a notice with the message you provided to the console.