Skip to content

refactor(html): minify inline CSS and JSON through renderEmbeddedSource alone - #14

Open
anurag6569201 wants to merge 1 commit into
qa/agent-webpack-webpack/pr-14-21993/basefrom
qa/agent-webpack-webpack/pr-14-21993/head
Open

anurag6569201 wants to merge 1 commit into
qa/agent-webpack-webpack/pr-14-21993/basefrom
qa/agent-webpack-webpack/pr-14-21993/head

Conversation

@anurag6569201

Copy link
Copy Markdown

Summary

The HTML printer ran its own CSS and JSON minifiers for an inline <style>, a style="" and a JSON <script>, so a caller's renderEmbeddedSource could not own those bodies — a custom minimizer had no way to minify them itself. Now the printer minifies nothing: every nested body is offered to the renderer and a declined one is left as written. builtinEmbeddedRenderer exports webpack's own CSS and JSON minifiers as such a renderer, and htmlMinify composes it behind the caller's, so a custom minimizer answers for the languages it claims and webpack's own answers for the rest.

What kind of change does this PR introduce?

refactor

Did you add tests for your changes?

Yes — test/HtmlSyntax.unittest.js covers the renderer-only path and webpack's own renderer passed behind a declining one; test/helpers/SampleEmbeddedMinifyPlugin.js composes it the way htmlMinify does, so the html and css configCases exercise it in a real build.

Does this PR introduce a breaking change?

No. htmlMinify and optimization.minimize.html produce the same output; the printer's CSS options (environment, convertLengthUnits, rewriteCustomProperties, cssTransforms, cssUnusedSymbols, cssPseudoClasses) move to builtinEmbeddedRenderer, which a direct html.syntax caller passes as renderEmbeddedSource.

If relevant, what needs to be documented once your changes are merged or what have you already documented?

html.syntax.builtinEmbeddedRenderer and html.syntax.stripJsonWhitespace are new exports worth a line where renderEmbeddedSource is documented.

Use of AI

Claude Code was used to write the change and its tests under my direction and review, and to run the unit suites, the html and css configCases in both the plain and filesystem-cache runs, and the lint chain.


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added configurable rendering for embedded CSS, JSON, JavaScript, SVG, event handlers, and nested documents.
    • Added built-in minification for embedded CSS and JSON, including inline styles.
    • Added support for configuring CSS processing options for embedded content.
  • Bug Fixes

    • Preserved original embedded content when rendering is unavailable, declined, or fails.
    • Improved handling of style merging, malformed declarations, character references, and foreign content.

Source merge-base: ee66ae80b8726db4e2b5e247a6ff89c7fbb3cab9
Source head: d851ccfc9a17a33a0cc139760ca6efc7791e0770

@shipwright-agent

Copy link
Copy Markdown

⚠️ Shipwright · Approve with conditions

Recommendation: approve PR #14 with conditions · Tier T3
Checks: 0 total · 0 needing attention

Next step: an authorized approver must satisfy the approval condition.

Findings (5)

  • HIGH The 'stripJsonWhitespace' function silently returns the input unchanged when 'JSON.parse' throws, conflating 'not JSON' with 'malformed JSON'. · lib/html/builtinEmbeddedRenderer.js:28
    • Fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.
  • HIGH The builtin renderer's block memoization is keyed only by source string, but the renderer closes over mutable 'options' and the 'sheet'/'block' objects are created once per 'builti · lib/html/builtinEmbeddedRenderer.js:78
    • Fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.
  • HIGH The new 'builtinEmbeddedRenderer' catches all errors from 'SourceProcessor().process()' and returns 'undefined', which the printer treats as 'leave as written'. · lib/html/builtinEmbeddedRenderer.js:88
    • Fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.
  • HIGH 'stripJsonWhitespace' parses and re-emits JSON without validating the result against the original semantics beyond whitespace removal. · lib/html/builtinEmbeddedRenderer.js:28
    • Fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.
  • LOW The diff removes the CSS-related options from 'HtmlPrintOptions' and 'HtmlProcessOptions' but leaves the 'environment' option documented in 'htmlMinify''s JSDoc as reaching the CSS · types.d.ts:30920
    • Fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.

Conditions

  • human approval required (T3): apply the approval label

Fireworks usage: 46,633 input · 746 output · 47,379 total tokens · $0.0108 · 17s · 0 fix iteration(s)

Open the Shipwright check for full evidence and the audit bundle. Use /shipwright rerun to verify again.


/**
* Strip the whitespace between a JSON body's tokens, every literal copied byte
* for byte. Re-serializing would round numbers, drop a duplicate key and rewrite

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Shipwright · HIGH

The 'stripJsonWhitespace' function silently returns the input unchanged when 'JSON.parse' throws, conflating 'not JSON' with 'malformed JSON'.

Impact: The 'stripJsonWhitespace' function silently returns the input unchanged when 'JSON.parse' throws, conflating 'not JSON' with 'malformed JSON'. A caller cannot distinguish a template/placeholder from a genuinely broken JSON body, and the comment says 'not ours to touch' for both. This makes debugging and downstream validation harder, and the behavior is not surfaced in the return type.

Suggested fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.

_htmlSyntax || (_htmlSyntax = require("./syntax"));
const sheet = { mode: /** @type {"minify"} */ ("minify"), ...options };
const block = { ...sheet, as: BLOCK_CONTENTS };
// A `style=""` repeats across a document far more often than it varies.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Shipwright · HIGH

The builtin renderer's block memoization is keyed only by source string, but the renderer closes over mutable 'options' and the 'sheet'/'block' objects are created once per 'builti

Impact: The builtin renderer's block memoization is keyed only by source string, but the renderer closes over mutable 'options' and the 'sheet'/'block' objects are created once per 'builtinEmbeddedRenderer()' call. If a caller mutates the options object after creating the renderer, or reuses one renderer across prints with different CSS environments, the memoized 'blocks' Map can return stale minified output from a previous…

Suggested fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.

if (isBlock) {
const memoized = blocks.get(source);
if (memoized !== undefined) return memoized;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Shipwright · HIGH

The new 'builtinEmbeddedRenderer' catches all errors from 'SourceProcessor().process()' and returns 'undefined', which the printer treats as 'leave as written'.

Impact: The new 'builtinEmbeddedRenderer' catches all errors from 'SourceProcessor().process()' and returns 'undefined', which the printer treats as 'leave as written'. This swallows not only parse failures but also programming errors (e.g., a bug in the CSS minifier or an invalid options object), making it impossible to detect regressions in production output. The old code had the same catch pattern, but the refactor expan…

Suggested fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.


/**
* Strip the whitespace between a JSON body's tokens, every literal copied byte
* for byte. Re-serializing would round numbers, drop a duplicate key and rewrite

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Shipwright · HIGH

'stripJsonWhitespace' parses and re-emits JSON without validating the result against the original semantics beyond whitespace removal.

Impact: 'stripJsonWhitespace' parses and re-emits JSON without validating the result against the original semantics beyond whitespace removal. The hand-rolled scanner tracks only string/escape state and does not account for JSON numbers, literals, or structural tokens; a body that parses as JSON but contains unusual whitespace inside a string is copied byte-for-byte, but any future change to this scanner could silently alte…

Suggested fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.

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.

1 participant