wikimedia/remex-html
RemexHTML is a pure PHP HTML5 parser and serializer from Wikimedia. It implements the WHATWG tokenizer and tree construction algorithms, builds a lightweight document tree, and supports serialization and tree mutation, powering robust HTML processing in MediaWiki and other projects.
Architecture fit. wikimedia/remex-html is a pure-PHP, dependency-free implementation of the WHATWG HTML5 tokenizer, tree-construction algorithm, and serializer. For a Laravel codebase that currently relies on DOMDocument::loadHTML / libxml for ingesting, normalizing, or re-emitting HTML (CMS content, email templates, RSS/Atom payloads, scraped pages, markdown-adjacent pipelines), it is a drop-in conceptual replacement with materially better conformance: libxml implements an HTML4-era parser with non-spec recovery behavior, while Remex follows the HTML5 error-recovery rules that browsers use. The package exposes composable layers rather than one facade — Tokenizer, TreeBuilder, DOMBuilder, DOMSerializer, Serializer, and tree-mutation/filtering helpers — which suits a Laravel service class or container-bound interface, but it is not Laravel-shaped: no service provider, no config, no facade. Expect to write a thin adapter (Html5Parser / Html5Serializer contracts) yourself.
Integration feasibility. Low friction mechanically. Composer install, PSR-4 namespace RemexHtml\, no extension requirements beyond a reasonably modern PHP (verify the package's PHP constraint against your floor — the 4.x line tracks MediaWiki's supported PHP versions, so pin deliberately). The absence of transitive dependencies is a genuine supply-chain positive versus pulling in a larger HTML toolkit. The real integration work is architectural, not mechanical: defining where parsing happens (request path vs. queued job), imposing input size and nesting limits, and deciding whether you need tokenizer-only streaming (cheap, for extraction/rewriting) or full tree construction (expensive, for DOM-style manipulation).
Technical risk. Three risks dominate.
onerror/javascript: payloads that libxml-based filtering often accidentally neutralizes. Any team that swaps it in expecting XSS reduction will regress. Sanitization must be a separate, explicit allow-list layer (HTMLPurifier or equivalent) applied to the parsed tree, or built on Remex's tree-mutation API with a rigorously reviewed rule set.gerrit.wikimedia.org, not GitHub. The code is battle-tested at Wikipedia scale inside MediaWiki, but the support surface is MediaWiki's release cadence and security process, not a responsive GitHub maintainer. Plan for that: you will read source and the spec, not Stack Overflow.Key questions.
DOMDocument::loadHTML or regex-based HTML manipulation, and what is the document-size P95/P99 on each?Stack fit. Composer-native, framework-agnostic, PSR-4 — it slots into Laravel as a library behind your own abstraction. Recommended shape: an Html5Parser interface bound in a service provider, with RemexHtml\Tokenizer\Tokenizer + TreeBuilder + DOMBuilder composing the implementation, and a separate Html5Serializer for output. Keep Remex types out of controllers, jobs, and domain code so the dependency remains replaceable. Serialization output is spec-compliant and therefore normalizes — attribute quoting, void-element syntax, entity re-encoding, and tree repair will change byte output. Any downstream consumer doing string comparison, diffing, or signature verification on HTML must be audited.
Migration path. Shadow-mode migration, not a big-bang swap:
Compatibility. Two areas to verify early. First, PHP version constraints against your runtime matrix and CI. Second, character encoding: Remex expects UTF-8 and does not guess legacy encodings the way libxml does — if your corpus contains Windows-1252 or Shift-JIS payloads, add an explicit transcoding step (mb_convert_encoding with detection) upstream, or you will silently corrupt content. Also confirm behavior against your existing HTMLPurifier rules, since the tree shape feeding the sanitizer changes.
Sequencing. (1) Spike: parse-and-serialize 100 real documents, measure time/memory. (2) Adapter + contract tests. (3) Input guardrails: max bytes, max nesting depth, max attributes, execution timeout. (4) Shadow deployment with diff metrics. (5) Migrate low-risk extraction paths. (6) Migrate content-write/normalization paths behind a feature flag with instant rollback. (7) Remove libxml fallback only after a full release cycle of clean telemetry.
Maintenance. Low code-churn dependency (specification-driven, mature), but unconventional maintenance: releases and security advisories flow through Wikimedia's Gerrit and MediaWiki security process, and the GitHub repo is explicitly a mirror. Budget for a named owner who monitors mediawiki-libs-RemexHtml tags and MediaWiki security announcements rather than Dependabot PRs. Pin exact versions; avoid ^ ranges on a library whose release cadence you don't control.
Support. No commercial support, thin documentation (README plus source plus the WHATWG spec). Internal runbooks and a documented "why we use this" decision record are essential — the next engineer will otherwise re-litigate the choice on seeing 12 stars. Escalation path is upstream patch or local fork; MIT license permits the latter, and vendoring is a reasonable hedge given the mirror-only GitHub presence.
Scaling. CPU-bound and single-threaded per document. Horizontal scaling means more workers, not more cores per request. Keep parsing off web workers: route through queued jobs with a dedicated queue and its own concurrency/autoscale policy so a burst of large documents cannot starve user-facing traffic. Cache parse results keyed by content hash — content normalization is highly repetitive in CMS-style workloads. Watch memory: pathological nesting and huge attribute values are spec-handled (parser recovers) but can still consume unbounded memory, so enforce hard limits before the parser sees input.
Failure modes.
Ramp-up. Two to three engineer-days for a competent PHP developer to be productive with the tokenizer/tree-builder/serializer layering; considerably more to be confident with HTML5 tree-construction semantics (foster parenting, active formatting elements, insertion modes), which are the source of most subtle bugs. Expect a half-day of team knowledge transfer on "parser ≠ sanitizer," and treat the shadow-diff corpus as the durable organizational asset — it is what makes future upgrades cheap and safe.
How can I help you explore Laravel packages today?