Skip to content

Add configurable output minification#56

Merged
samdark merged 2 commits into
masterfrom
feature/minify-output
Jun 7, 2026
Merged

Add configurable output minification#56
samdark merged 2 commits into
masterfrom
feature/minify-output

Conversation

@samdark
Copy link
Copy Markdown
Member

@samdark samdark commented Jun 7, 2026

Summary

  • add a minify site config option, enabled by default
  • minify generated HTML pages while preserving pre, textarea, script, and style contents
  • document the option, update the roadmap, and add PHPUnit coverage plus a phpbench benchmark

Tests

  • make test
  • make psalm
  • BENCH_FILTER=OutputMinifierBench make bench

Summary by CodeRabbit

Release Notes

  • New Features

    • Generated HTML pages are now minified by default, reducing file sizes by removing unnecessary whitespace.
    • Whitespace is preserved in <pre>, <textarea>, <script>, and <style> elements.
    • New minify configuration option allows disabling minification when needed.
  • Documentation

    • Configuration documentation updated with the new minify setting and behavior details.

Copilot AI review requested due to automatic review settings June 7, 2026 20:02
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 7, 2026

Review Change Stack

Warning

Review limit reached

@samdark, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 32 minutes and 32 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: efec3ef3-ef64-4784-8027-b4992760230d

📥 Commits

Reviewing files that changed from the base of the PR and between b085a32 and 5566543.

📒 Files selected for processing (3)
  • src/Build/AuthorPageWriter.php
  • src/Build/OutputMinifier.php
  • tests/Unit/Build/OutputMinifierTest.php
📝 Walkthrough

Walkthrough

This PR introduces configurable HTML output minification for the YiiPress static site generator. It adds a new OutputMinifier class that intelligently collapses whitespace while preserving content sensitivity in pre, textarea, script, and style elements. Minification is enabled by default via a new minify configuration property, integrated throughout the rendering pipeline via PageTemplateRenderer, and applied in all page writer classes and the entry rendering path.

Changes

HTML Output Minification Feature

Layer / File(s) Summary
OutputMinifier core algorithm
src/Build/OutputMinifier.php, tests/Unit/Build/OutputMinifierTest.php
New OutputMinifier class with html() and minifyHtmlFragment() methods that collapse whitespace and remove inter-tag gaps while preserving whitespace-sensitive element bodies. Unit tests validate exact minified and preserved output.
Minification configuration and parsing
src/Content/Model/SiteConfig.php, src/Content/Parser/SiteConfigParser.php, tests/Unit/Content/Parser/SiteConfigParserTest.php
SiteConfig gains a minify boolean property (default true). SiteConfigParser reads the minify YAML field. Tests verify default minification and ability to disable via config.
PageTemplateRenderer minification integration
src/Build/PageTemplateRenderer.php, tests/Unit/Build/PageTemplateRendererTest.php
PageTemplateRenderer constructor accepts minify flag (default true) and render() conditionally applies OutputMinifier::html(). Tests confirm minified output by default and unminified when disabled.
EntryRenderer minification in cache paths
src/Build/EntryRenderer.php, tests/Unit/Build/EntryRendererTest.php
EntryRenderer::render() applies minification after dispatchRenderFinished() in both cache-hit and cache-miss flows using siteConfig->minify. Test helper createSiteConfig() gains minify parameter.
Page writers minification wiring
src/Build/AuthorPageWriter.php, src/Build/CollectionListingWriter.php, src/Build/DateArchiveWriter.php, src/Build/NotFoundPageWriter.php, src/Build/RedirectPageWriter.php, src/Build/TaxonomyPageWriter.php
All page writer classes now pass siteConfig->minify when constructing PageTemplateRenderer or applying minification, ensuring consistent behavior across author pages, collection listings, date archives, not-found pages, redirects, and taxonomy pages.
Documentation and performance benchmark
docs/configuration.md, roadmap.md, benchmarks/OutputMinifierBench.php
Configuration docs updated with minify field description and new "Output minification" section explaining default behavior and whitespace preservation rules. Roadmap item marked complete. New OutputMinifierBench class benchmarks minification performance.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • yiipress/engine#37: Introduced the dispatchRenderFinished() hook that the minification PR now leverages in EntryRenderer to apply minification after render lifecycle events.

Poem

🐰 Whitespace trimmed with thoughtful care,
Pre and script tags spared from snip,
Config flows from YAML's lair,
Minified output, not a trip!
Fast builds hop through every page.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a new configurable feature for output minification, which is the primary objective across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/minify-output

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces configurable HTML output minification across YiiPress’ build pipeline, controlled via a new minify site configuration option (defaulting to enabled). It adds a dedicated OutputMinifier implementation, wires it into template rendering and page writers, and updates docs/roadmap along with PHPUnit and phpbench coverage.

Changes:

  • Add SiteConfig::$minify and parse minify: true|false from site YAML (default true).
  • Minify generated HTML by default in PageTemplateRenderer, EntryRenderer, and relevant page writers, while preserving bodies of pre, textarea, script, and style.
  • Add unit tests for the minifier and a phpbench benchmark; document the new option and update the roadmap.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/Build/OutputMinifier.php Introduces the HTML minification utility used throughout the build.
src/Build/PageTemplateRenderer.php Adds a minify toggle and applies output minification by default after rewriteHtml().
src/Build/EntryRenderer.php Applies minification to entry page output (including cached paths) based on SiteConfig::$minify.
src/Build/RedirectPageWriter.php Minifies redirect HTML output when enabled (or when config is absent).
src/Build/AuthorPageWriter.php Passes the site minify setting through to PageTemplateRenderer.
src/Build/CollectionListingWriter.php Passes the site minify setting through to PageTemplateRenderer.
src/Build/DateArchiveWriter.php Passes the site minify setting through to PageTemplateRenderer.
src/Build/NotFoundPageWriter.php Passes the site minify setting through to PageTemplateRenderer.
src/Build/TaxonomyPageWriter.php Passes the site minify setting through to PageTemplateRenderer.
src/Content/Model/SiteConfig.php Adds public bool $minify = true to the site configuration model.
src/Content/Parser/SiteConfigParser.php Parses minify from YAML with a default of true.
tests/Unit/Build/OutputMinifierTest.php Adds unit tests for the new minifier behavior.
tests/Unit/Build/PageTemplateRendererTest.php Verifies default minification and opt-out behavior in template rendering.
tests/Unit/Build/EntryRendererTest.php Updates site-config construction helper to include the new minify argument.
tests/Unit/Content/Parser/SiteConfigParserTest.php Asserts default minify behavior and verifies minify: false disables it.
benchmarks/OutputMinifierBench.php Adds a phpbench benchmark for minification performance.
docs/configuration.md Documents the minify option and its whitespace-preservation behavior.
roadmap.md Marks configurable output minification as completed.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Build/OutputMinifier.php Outdated
Comment on lines +24 to +26
$protectedParts = preg_split(
'~(<(?:pre|textarea|script|style)\b[^>]*>.*?</(?:pre|textarea|script|style)>)~is',
$html,
Comment thread src/Build/OutputMinifier.php Outdated
Comment on lines +66 to +67
$tokens = preg_split('~(<[^>]+>)~', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
if ($tokens === false) {
Comment on lines +64 to +65
}
}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
tests/Unit/Build/OutputMinifierTest.php (1)

32-64: ⚡ Quick win

Consider adding test coverage for textarea element preservation.

The OutputMinifier protects four element types (pre, textarea, script, style), but only pre, script, and style are tested. Adding a textarea case would ensure complete coverage of the protected elements.

🧪 Suggested additional assertion
public function testPreservesTextareaWhitespace(): void
{
    $html = '<div><textarea>  spaced
    content  </textarea></div>';

    assertSame(
        '<div><textarea>  spaced
    content  </textarea></div>',
        OutputMinifier::html($html),
    );
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/Unit/Build/OutputMinifierTest.php` around lines 32 - 64, Add a new unit
test method in the OutputMinifierTest class to cover textarea preservation:
create a test (e.g., testPreservesTextareaWhitespace) that feeds a small HTML
string containing a <textarea> with leading/trailing spaces and newlines to
OutputMinifier::html and assert that the output exactly equals the original
(preserving whitespace inside the textarea); place the test alongside
testPreservesWhitespaceSensitiveElementBodies so it exercises the same
preservation logic for the textarea element.

Source: Learnings

src/Build/OutputMinifier.php (1)

66-69: 💤 Low value

Regex tokenizer may mis-split tags containing > in attributes.

The pattern <[^>]+> doesn't account for > appearing inside quoted attribute values (e.g., <div onclick="if(x>y){}">). While rare in static site output, this could cause incorrect minification.

A more robust pattern would skip quoted sections:

♻️ Suggested improvement
-        $tokens = preg_split('~(<[^>]+>)~', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
+        $tokens = preg_split('~(<[^>]*(?:"[^"]*"|\'[^\']*\')*[^>]*>)~', $html, -1, PREG_SPLIT_DELIM_CAPTURE);

Alternatively, document this as a known limitation if attributes with > are not expected in the generated output.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Build/OutputMinifier.php` around lines 66 - 69, The preg_split call that
builds $tokens using the pattern '<[^>]+>' can mis-split when a '>' appears
inside quoted attribute values; update the tokenizer in OutputMinifier.php (the
preg_split(...) that assigns $tokens) to use a safer regex that ignores '>'
inside single- or double-quoted attributes (e.g., a pattern that matches tags
while skipping quoted strings) or, if you prefer not to change the regex, add a
clear comment/documentation next to the preg_split to mark this limitation;
ensure the change targets the preg_split call that creates $tokens so tags like
<div onclick="if(x>y){}"> are not broken by the tokenizer.
src/Build/AuthorPageWriter.php (1)

43-43: 💤 Low value

Consider extracting repeated PageTemplateRenderer instantiation.

The pattern new PageTemplateRenderer($this->templateResolver, $siteConfig->theme, $this->assetManifest, $siteConfig->minify) is repeated three times (lines 43, 68, 92). While not critical, extracting this to a private helper method would reduce duplication.

♻️ Optional refactor to reduce duplication
+    private function createRenderer(SiteConfig $siteConfig): PageTemplateRenderer
+    {
+        return new PageTemplateRenderer(
+            $this->templateResolver,
+            $siteConfig->theme,
+            $this->assetManifest,
+            $siteConfig->minify
+        );
+    }
+
     public function write(
         SiteConfig $siteConfig,
         array $authors,
         array $entriesByAuthor,
         array $collections,
         string $outputDir,
         ?Navigation $navigation = null,
         bool $noWrite = false,
     ): int {
         if ($authors === []) {
             return 0;
         }
 
-        $renderer = new PageTemplateRenderer($this->templateResolver, $siteConfig->theme, $this->assetManifest, $siteConfig->minify);
+        $renderer = $this->createRenderer($siteConfig);

Apply similar changes at lines 68 and 92.

Also applies to: 68-68, 92-92

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Build/AuthorPageWriter.php` at line 43, Extract the repeated
PageTemplateRenderer construction into a private helper on AuthorPageWriter
(e.g., private function createPageTemplateRenderer()) that returns new
PageTemplateRenderer($this->templateResolver, $siteConfig->theme,
$this->assetManifest, $siteConfig->minify); then replace the three inline
instantiations in methods that currently call new PageTemplateRenderer(...)
(lines referenced in the review) with a call to
$this->createPageTemplateRenderer() to remove duplication and keep behavior
identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Build/OutputMinifier.php`:
- Around line 24-29: The regex used in OutputMinifier.php when building
$protectedParts with preg_split can mis-pair opening/closing tags (e.g., a
literal string containing </pre> inside a <script>), so update the pattern to
capture the tag name for the opening element and use a backreference for the
closing tag (i.e., capture the element name and close with </\2>) and keep the
same flags (/is) so only matching pairs are protected; after changing the
pattern, adjust any downstream handling of the preg_split result to account for
the changed capture groups (the variable $protectedParts and any code that
iterates or filters it should be updated accordingly).

---

Nitpick comments:
In `@src/Build/AuthorPageWriter.php`:
- Line 43: Extract the repeated PageTemplateRenderer construction into a private
helper on AuthorPageWriter (e.g., private function createPageTemplateRenderer())
that returns new PageTemplateRenderer($this->templateResolver,
$siteConfig->theme, $this->assetManifest, $siteConfig->minify); then replace the
three inline instantiations in methods that currently call new
PageTemplateRenderer(...) (lines referenced in the review) with a call to
$this->createPageTemplateRenderer() to remove duplication and keep behavior
identical.

In `@src/Build/OutputMinifier.php`:
- Around line 66-69: The preg_split call that builds $tokens using the pattern
'<[^>]+>' can mis-split when a '>' appears inside quoted attribute values;
update the tokenizer in OutputMinifier.php (the preg_split(...) that assigns
$tokens) to use a safer regex that ignores '>' inside single- or double-quoted
attributes (e.g., a pattern that matches tags while skipping quoted strings) or,
if you prefer not to change the regex, add a clear comment/documentation next to
the preg_split to mark this limitation; ensure the change targets the preg_split
call that creates $tokens so tags like <div onclick="if(x>y){}"> are not broken
by the tokenizer.

In `@tests/Unit/Build/OutputMinifierTest.php`:
- Around line 32-64: Add a new unit test method in the OutputMinifierTest class
to cover textarea preservation: create a test (e.g.,
testPreservesTextareaWhitespace) that feeds a small HTML string containing a
<textarea> with leading/trailing spaces and newlines to OutputMinifier::html and
assert that the output exactly equals the original (preserving whitespace inside
the textarea); place the test alongside
testPreservesWhitespaceSensitiveElementBodies so it exercises the same
preservation logic for the textarea element.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: abdf98d8-70fe-416e-aff8-14cee42a9e8a

📥 Commits

Reviewing files that changed from the base of the PR and between a72a660 and b085a32.

📒 Files selected for processing (18)
  • benchmarks/OutputMinifierBench.php
  • docs/configuration.md
  • roadmap.md
  • src/Build/AuthorPageWriter.php
  • src/Build/CollectionListingWriter.php
  • src/Build/DateArchiveWriter.php
  • src/Build/EntryRenderer.php
  • src/Build/NotFoundPageWriter.php
  • src/Build/OutputMinifier.php
  • src/Build/PageTemplateRenderer.php
  • src/Build/RedirectPageWriter.php
  • src/Build/TaxonomyPageWriter.php
  • src/Content/Model/SiteConfig.php
  • src/Content/Parser/SiteConfigParser.php
  • tests/Unit/Build/EntryRendererTest.php
  • tests/Unit/Build/OutputMinifierTest.php
  • tests/Unit/Build/PageTemplateRendererTest.php
  • tests/Unit/Content/Parser/SiteConfigParserTest.php

Comment thread src/Build/OutputMinifier.php Outdated
@samdark samdark merged commit d59d48e into master Jun 7, 2026
7 checks passed
@samdark samdark deleted the feature/minify-output branch June 7, 2026 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants