Hypertool

Class: Hypertool\Html\ScriptManager

1. Overview

The ScriptManager class provides an automated and intelligent system for injecting HTMX and Hyperscript JavaScript library tags into HTML layouts or templates. Its primary purpose is to ensure these scripts are included efficiently and correctly, addressing common challenges like duplicate inclusions and environment-specific loading (CDN vs. local assets).

It acts as a central registry within a single request lifecycle to track which scripts (htmx.js, hyperscript.js) have been requested by different parts of an application (pages, components, partials) and then outputs the necessary <script> tags exactly once, typically just before the closing </body> tag.

2. API Reference

ScriptManager uses static methods and properties to maintain state throughout a single PHP request.

Static Methods

setEnv(string $env): void

requireHtmx(): void

requireHyperscript(): void

outputScripts(): string

Static Properties

(These properties are internal state and should not be accessed directly.)

3. Usage Examples

(Assumes Composer autoloader is included and use Hypertool\Html\ScriptManager;)

Example 1: Basic Layout Integration

<?php // layout.php
use Hypertool\Html\ScriptManager;

// Simulate different parts of the page requesting scripts
// Header component might require HTMX
ScriptManager::requireHtmx();

// A specific widget requires Hyperscript
ScriptManager::requireHyperscript();

// Another component also needs HTMX (won't cause duplication)
ScriptManager::requireHtmx();

?>
<!DOCTYPE html>
<html>
<head>
    <title>My App</title>
    <!-- Other head elements -->
</head>
<body>
    <!-- Page content -->
    <h1>Welcome</h1>
    <div id="widget">...</div>

    <!-- Output scripts just before closing body -->
    <?php echo ScriptManager::outputScripts(); ?>
</body>
</html>
// Expected Output (in development):
// <script src="https://unpkg.com/htmx.org@1.9.10" onerror="alert('HTMX failed to load!')"></script>
// <script src="https://unpkg.com/hyperscript.org@0.9.12" onerror="alert('Hyperscript failed to load!')"></script>
// <noscript><div class="alert alert-warning">This site works best with JavaScript enabled.</div></noscript>

Example 2: Production Environment

<?php // layout.php (in production)
use Hypertool\Html\ScriptManager;

// Set environment explicitly (or rely on APP_ENV)
ScriptManager::setEnv('production');

ScriptManager::requireHtmx();
// Only HTMX is needed for this page

?>
<!DOCTYPE html>
<html>
<body>
    <!-- Page content -->

    <?php echo ScriptManager::outputScripts(); ?>
</body>
</html>
// Expected Output (in production):
// <script src="/assets/js/htmx.min.js" onerror="alert('HTMX failed to load!')"></script>
// <noscript><div class="alert alert-warning">This site works best with JavaScript enabled.</div></noscript>
// (Assumes /assets/js/htmx.min.js exists)

Example 3: No Scripts Required

<?php // simple_page.php
use Hypertool\Html\ScriptManager;

// No calls to requireHtmx() or requireHyperscript() made for this page

?>
<!DOCTYPE html>
<html>
<body>
    <h1>Static Content</h1>
    <!-- No dynamic scripts needed -->

    <?php echo ScriptManager::outputScripts(); // Call is safe, outputs nothing ?>
</body>
</html>
// Expected Output:
// (Empty string from outputScripts())

4. Detailed Use Cases/Scenarios

  1. Standard Web Application Layout: The most common use case. Call requireHtmx() or requireHyperscript() within controllers, views, or components that depend on these libraries. Then, in the main HTML layout file (e.g., layout.php, base.html.twig), make a single call to ScriptManager::outputScripts() just before </body> to inject all necessary scripts exactly once.
  2. Component-Based Systems: In systems where pages are built from smaller, potentially reusable components (like view composers, partials, or widgets), each component can independently call requireHtmx() or requireHyperscript() if it needs them. The ScriptManager ensures that even if multiple components request the same script, it’s only included once when outputScripts() is called in the final layout.
  3. Development vs. Production Builds: Use setEnv('production') or the APP_ENV environment variable to automatically switch between loading scripts from a CDN (fast for development, no local setup needed) and loading locally bundled/minified versions (better performance, reliability, and offline capability in production).
  4. AJAX/Partial Rendering: While ScriptManager primarily works within a single PHP request, if you are rendering HTML partials via AJAX (e.g., using HTMX itself), ensure that the main page load has already included the necessary base libraries (HTMX/Hyperscript) using ScriptManager. The partials themselves wouldn’t typically call outputScripts().

5. Dependencies

6. Error Handling & Exceptions

7. Configuration

8. Best Practices & Pitfalls