polymech-astro/packages/imagetools_x/docs/classes.md
2025-08-27 18:44:10 +02:00

6.1 KiB

Imagetools Architecture Overview

This document outlines the architecture of the imagetools package, detailing the relationships between its different modules and the data flow during image processing.

Core Concepts

The system is divided into several layers:

  1. Astro Components: User-facing components for displaying images.
  2. API Layer: JavaScript APIs that components call to get image data and attributes.
  3. Vite Plugin: The core image processing and transformation engine that hooks into Vite's build process.
  4. Astro Integration: Glues the Vite plugin into the Astro lifecycle, handling configuration and final asset generation.

Data Flow Diagram

The following diagram illustrates how a request for an image flows through the system during a production build.

graph TD
    subgraph " "
        direction LR
        subgraph "User Facing"
            A["Astro Component<br/>(e.g., Img.astro)"]
        end

        subgraph "API Layer"
            B["renderImg.js"]
            C["getImage.js"]
        end
    end
    
    subgraph "Build Process"
        direction LR
        subgraph "Astro Integration"
            I["integration/index.js"]
            J["astro:config:setup hook"]
            K["astro:build:done hook"]
            L["saveAndCopyAsset.js"]
        end

        subgraph "Vite Plugin"
            D["plugin/index.js"]
            E["load hook<br/>(load.js)"]
            F["Image Transformation<br/>(imagetools.js/codecs.js)"]
            G["Persistent Cache<br/>(@polymech/cache)"]
            H["In-memory Store"]
        end
    end

    A -- "1. Renders" --> B;
    B -- "2. Calls" --> C;
    C -- "3. Triggers image import" --> D;
    
    I -- "Registers" --> D;
    J -- "Writes config for" --> D;

    D -- "Uses" --> E;
    E -- "4. Processes import" --> F;
    E -- "Uses" --> G;
    E -- "5. Populates" --> H;

    K -- "6. Reads from" --> H;
    K -- "7. Saves assets via" --> L;

Explanation of Components

  • Astro Component (Img.astro): The entry point. A developer uses this component in their .astro or .mdx files. It receives props like src, width, etc.

  • renderImg.js: An API function called by the Astro component. It sanitizes props and prepares them for image processing.

  • getImage.js: This function is responsible for orchestrating the generation of image sources. It triggers the actual image import that will be handled by Vite.

  • Vite Plugin (plugin/index.js): The core of the image processing pipeline. It's a Vite plugin that intercepts image imports.

  • load hook (load.js): The main hook in the Vite plugin. When an image is imported (e.g., import img from './my.jpg?w=300'), this hook:

    1. Parses the query parameters.
    2. Checks a persistent cache (@polymech/cache) for the transformed image.
    3. If not cached, it uses Sharp or other codecs for transformation (imagetools.js/codecs.js).
    4. Stores the processed image buffer in an in-memory store.
    5. Returns the path for the final asset.
  • Astro Integration (integration/index.js): Manages the lifecycle of the tool within Astro.

    • astro:config:setup: Injects the Vite plugin into the Astro configuration.
    • astro:build:done: This hook runs after the build is complete. It iterates over the in-memory store populated by the load hook and writes the processed images to the final output directory using saveAndCopyAsset.js.

Recommendations for Refactoring

The current implementation is functional but has room for simplification and improved robustness. Here are the key areas to focus on in the next refactoring slice:

  1. Unify Caching Strategy:

    • Problem: Caching logic is spread across multiple files (getImage.js, load.js, saveAndCopyAsset.js) with different strategies (in-memory map, persistent file-system cache). This makes it hard to reason about and debug.
    • Recommendation: Consolidate all caching into a single, cohesive module. This module should expose clear functions for getting, setting, and clearing cached items, and manage both in-memory and persistent layers. This will centralize logic and reduce redundancy.
  2. Refactor load.js Hook:

    • Problem: The load.js file is long and handles multiple responsibilities: config parsing, caching, image transformation, and path generation. This violates the Single Responsibility Principle and makes the code hard to maintain and test.
    • Recommendation: Break down load.js into smaller, pure functions. For example:
      • parseImageQuery(searchParams)
      • transformImage(buffer, options)
      • getAssetPath(source, options) This will improve readability, testability, and maintainability.
  3. Simplify Plugin-Integration Communication:

    • Problem: The communication between the Vite plugin's load hook and the Astro astro:build:done hook relies on a shared, mutable store object. This pattern can be fragile and is an indirect way of handling assets.
    • Recommendation: Explore using Vite's standard asset handling APIs. The this.emitFile function within the load hook is the idiomatic way in Vite/Rollup plugins to generate assets and get a reference to them without managing a global store. This would eliminate the need for the store and the manual file writing in astro:build:done.
  4. Streamline Configuration:

    • Problem: Configuration is passed between the Astro integration and the Vite plugin by writing a temporary astroViteConfigs.js file. This is a workaround that can be brittle.
    • Recommendation: Leverage the Vite plugin's configResolved hook. This hook receives the final, resolved Vite configuration and is the proper place to access build-related information without needing to write temporary files. The Astro integration can pass options directly to the Vite plugin during setup.

By tackling these areas, the codebase will become simpler, more robust, and easier to extend in the future.