# How the beforeTransform Phase Interacts with Transformer Plugins in PicList-Core

> Understand how PicList-Core's beforeTransform phase integrates with transformer plugins. Discover how built-in preprocessing ensures efficient image modifications before user transformations.

- Repository: [Kuingsmile/piclist-core](https://github.com/kuingsmile/piclist-core)
- Tags: internals
- Published: 2026-03-05

---

**The beforeTransform phase executes built-in preprocessing plugins such as compress and watermark before any user-installed transformer plugins run, ensuring image modifications are applied to the buffer prior to transformation.**

PicList-Core orchestrates image uploads through a strict lifecycle pipeline defined in [`src/core/Lifecycle.ts`](https://github.com/kuingsmile/piclist-core/blob/main/src/core/Lifecycle.ts). The **beforeTransform phase** serves as a critical preprocessing stage that executes built-in plugins immediately before the **transformer phase** handles user-defined transformations. This architecture ensures that operations like compression and watermarking modify the image buffer before base64 encoding or path manipulation occurs.

## Lifecycle Architecture and Plugin Registration

All plugins in PicList-Core are managed by the `LifecyclePlugins` container defined in [`src/lib/LifecyclePlugins.ts`](https://github.com/kuingsmile/piclist-core/blob/main/src/lib/LifecyclePlugins.ts). This class maintains a registry of plugins and tracks the current execution phase through the `setCurrentPluginName` method. When the upload process begins, the lifecycle orchestrator initializes the plugin chain and prepares the context object that carries the image buffer through each phase.

### The LifecyclePlugins Container

The `LifecyclePlugins` class provides the `register` method to add plugins and uses `setCurrentPluginName` to identify which phase is currently active. During the beforeTransform phase, the orchestrator sets the current name to `'beforeTransform'`, signaling that only plugins registered under this namespace should execute.

## Executing the beforeTransform Phase

The core lifecycle logic resides in [`src/core/Lifecycle.ts`](https://github.com/kuingsmile/piclist-core/blob/main/src/core/Lifecycle.ts). When the pipeline reaches the preprocessing stage, the code executes:

```typescript
// src/core/Lifecycle.ts
setCurrentPluginName('beforeTransform');
await this.runPlugins('beforeTransform');
setCurrentPluginName(null);

```

The `runPlugins` method iterates over all plugins whose identifiers match the current phase. For beforeTransform, this includes built-in plugins registered as `beforeTransform:compress`, `beforeTransform:watermark`, and `beforeTransform:skipProcess`. Each plugin receives the image buffer through its `handle(ctx, ...args)` method and returns the modified buffer for the next plugin in the chain.

## Built-in Before-Transformer Plugins

PicList-Core ships with three primary built-in plugins located in `src/plugins/beforetransformer/`:

- **compress** ([`compress.ts`](https://github.com/kuingsmile/piclist-core/blob/main/compress.ts)): Handles image compression, format conversion, and resizing based on `buildIn.compress` configuration.
- **watermark** ([`watermark.ts`](https://github.com/kuingsmile/piclist-core/blob/main/watermark.ts)): Applies text or image watermarks using settings stored under `buildIn.watermark`.
- **skipProcess** ([`skipProcess.ts`](https://github.com/kuingsmile/piclist-core/blob/main/skipProcess.ts)): Conditionally bypasses further processing based on user-defined rules in `buildIn.skipProcess`.

### Registration via the Build-in Module System

These plugins are registered through the CLI setting command defined in [`src/plugins/commander/setting.ts`](https://github.com/kuingsmile/piclist-core/blob/main/src/plugins/commander/setting.ts). The `BUILDIN_MODULES` constant maps module names to their configuration handlers:

```typescript
// src/plugins/commander/setting.ts
const BUILDIN_MODULES = {
  compress:    { config: compress.config,   key: 'BUILDIN_COMPRESS' },
  watermark:   { config: watermark.config,  key: 'BUILDIN_WATERMARK' },
  rename:      { config: rename.config,     key: 'BUILDIN_RENAME' },
  skipProcess: { config: skipProcess.config,key: 'BUILDIN_SKIPPROCESS' }
} as const;

```

When users run `picgo set buildin compress`, the configuration is persisted and subsequently loaded during the beforeTransform phase.

## Handoff to the Transformer Phase

After the beforeTransform phase completes, the lifecycle transitions to the transformer phase:

```typescript
setCurrentPluginName('transformer');
await this.runPlugins('transformer');
setCurrentPluginName(null);

```

This phase loads user-installed transformer plugins such as **base64** ([`src/plugins/transformer/base64.ts`](https://github.com/kuingsmile/piclist-core/blob/main/src/plugins/transformer/base64.ts)) and **path** ([`src/plugins/transformer/path.ts`](https://github.com/kuingsmile/piclist-core/blob/main/src/plugins/transformer/path.ts)). Crucially, these transformers receive the **already-modified** image buffer from the beforeTransform phase. If compression reduced the file size or watermarking altered the pixels, those changes persist into the transformation stage.

## Practical Configuration Example

To enable compression before transformation, configure the built-in plugin via CLI:

```bash

# Enable compression with quality 80

picgo set buildin compress

# Upload triggers the full lifecycle

picgo upload ./image.png

```

**Execution flow:**

1. The [`setting.ts`](https://github.com/kuingsmile/piclist-core/blob/main/setting.ts) handler writes `buildIn.compress` configuration.
2. [`Lifecycle.ts`](https://github.com/kuingsmile/piclist-core/blob/main/Lifecycle.ts) enters beforeTransform and executes the compress plugin.
3. The compressed buffer passes to the transformer phase (e.g., base64 encoding).
4. The final buffer proceeds to the uploader.

## Summary

- The **beforeTransform phase** executes in [`src/core/Lifecycle.ts`](https://github.com/kuingsmile/piclist-core/blob/main/src/core/Lifecycle.ts) before any user transformers run.
- Built-in plugins (compress, watermark, skipProcess) are registered via [`src/plugins/commander/setting.ts`](https://github.com/kuingsmile/piclist-core/blob/main/src/plugins/commander/setting.ts) and stored in [`src/lib/LifecyclePlugins.ts`](https://github.com/kuingsmile/piclist-core/blob/main/src/lib/LifecyclePlugins.ts).
- The `setCurrentPluginName('beforeTransform')` method isolates this phase's execution context.
- Image buffers modified during beforeTransform are automatically passed to the transformer phase plugins (base64, path).
- Configuration occurs through the `buildIn` namespace using `picgo set buildin <module>`.

## Frequently Asked Questions

### What is the exact execution order of phases in PicList-Core?

The lifecycle follows this strict sequence: **beforeUpload** (file preparation), **beforeTransform** (built-in preprocessing), **transformer** (user-defined transformations), **afterTransform** (post-processing), and finally **uploader** (remote transfer). This ordering ensures that built-in optimizations occur before any format conversions.

### How do I disable the beforeTransform phase for specific uploads?

You can use the **skipProcess** built-in plugin to conditionally bypass processing. Configure it via `picgo set buildin skipProcess` with rules that match your specific file patterns or conditions, allowing certain uploads to skip compression or watermarking while still proceeding to the transformer phase.

### Can I create custom plugins for the beforeTransform phase?

Yes. While PicList-Core primarily uses beforeTransform for built-in modules, the plugin architecture in [`src/lib/LifecyclePlugins.ts`](https://github.com/kuingsmile/piclist-core/blob/main/src/lib/LifecyclePlugins.ts) supports registering custom plugins under the `beforeTransform` namespace. Your plugin must implement a `handle` method that accepts the context object and returns the modified buffer, following the same pattern as [`compress.ts`](https://github.com/kuingsmile/piclist-core/blob/main/compress.ts).

### Why does my transformer plugin receive already-compressed images?

This is by design. The beforeTransform phase deliberately runs before the transformer phase to ensure that preprocessing optimizations like compression are applied early in the pipeline. If you need uncompressed data in your transformer, you must either disable the compress plugin or implement your transformation logic in the beforeUpload phase instead.