Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Markdown Laravel Package

tempest/markdown

A fast, extensible server-side Markdown parser for PHP that uses a simple lexer instead of regex. Built-in support for code highlighting, tables, divs, responsive images, and frontmatter, with benchmarks well ahead of commonmark and Parsedown Extra.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. tempest/markdown is a framework-agnostic, near-zero-dependency PHP library — not a Laravel package. There is no service provider, facade, config file, publishable assets, or Blade directive. Consumption is new Markdown() → parse() → a result object exposing html and frontmatter. That neutrality is an asset (it can live in a domain service, an Artisan command, a queue worker, or a CI static-site step without dragging framework coupling along) and a cost (every Laravel-shaped convenience — singleton binding, Blade directive, config, HTML caching — is ~30–50 lines we write and own). Treat the adapter as a known line item, not a surprise.

Integration feasibility. High. One Composer dependency, no external services, no Node toolchain, no build step. The surface area is a single class plus a result object, which makes a wrapper-and-swap strategy cheap. The main feasibility questions are not "can we call it" but "does its output match what our templates, CSS, and downstream consumers expect."

Technical risk.

  • Maturity and sustainability (high). 44 stars, 0 known dependents, an explicit "work in progress" banner, and a small maintainer pool. There is no vendor, no SLA, and no long CVE history to point at during architecture or security review. We are effectively the support contract.
  • Spec compliance (medium–high). The custom lexer intentionally diverges from CommonMark. The 1.3.0 changelog — fixes for setext headings, short headings, bullet markers and lazy list continuations, thematic breaks, unmatched tildes — is a clear signal that edge-case behavior is still being stabilized. If any downstream consumer assumes spec-exact HTML, validate before committing.
  • Security (medium). 1.2.1 shipped XSS fixes for HTML attributes and code blocks plus a parser cache-leak fix and a configurable maxNestingDepth. Good that the knobs exist; the implication is that this class of bug has occurred. Markdown → HTML with untrusted input is an XSS surface regardless of parser, so budget an HTML sanitizer and our own adversarial test corpus as part of the integration, not as a later hardening task.
  • API stability (medium). Pre-1.0 → 1.x with a WIP banner. The parse() result shape and frontmatter semantics could shift. Pin versions and treat upgrades as reviewed changes.
  • Performance claims (low–medium). The benchmark table (~5x faster, ~3x lower memory vs league/commonmark on the Tempest docs corpus) is vendor-run on a vendor corpus. Directionally credible given the lexer-vs-regex design, but must be re-measured on our content, our PHP version, and our runtime (FPM vs queue worker vs serverless).
  • License (low). MIT — forkable, removable, low exit cost.

Key questions.

  1. What is our actual CommonMark compliance requirement — contractual, interoperability, or "looks right in the browser"?
  2. Is the Markdown input trusted (our own repo docs, changelogs) or untrusted (user-authored content, comments, imported CMS data)? This determines whether we need a sanitizer and a security review gate.
  3. Which features do we need that are not listed — footnotes, autolinks, definition lists, custom containers, syntax-highlight themes?
  4. Who owns the wrapper, the upgrade cadence, and upstream contributions? (Name a person.)
  5. What is the measurable success bar for the spike — parity diff threshold, p95 render latency, memory ceiling, dependency count reduction?
  6. What is the documented fallback path and its cost if the pilot fails after one sprint?

Integration Approach

Stack fit. Laravel (10/11/12) on modern PHP — verify the package's PHP constraint against our runtime before anything else; the 1.0.0 changelog includes a "Fix PHP version" entry, so confirm from composer.json rather than the README. Because the package pulls in almost nothing, dependency-conflict risk with the existing composer.lock is low. It does not integrate with Blade, Eloquent, queues, or caching on its own; all of that is our adapter's job.

Migration path.

  1. Define the seam first. Introduce an internal MarkdownRenderer interface (render(string $markdown): ParsedDocument exposing html and frontmatter). Ship two implementations: incumbent (league/commonmark or current renderer) and TempestMarkdownRenderer. Nothing in application code should reference Tempest\Markdown\Markdown directly.
  2. Shadow mode. Add a config flag that renders through both implementations, returns the incumbent's output to users, and logs a structured diff (normalized HTML, frontmatter keys, anchor IDs, code-block classes). Run this against the real content corpus in staging for a defined period.
  3. Parity triage. Classify every diff: acceptable (whitespace, attribute ordering), fixable in our layer (CSS class mapping, anchor normalization), or upstream-blocking. Upstream-blocking items get issues/PRs filed before any production flip.
  4. Security gate. Run a payload corpus (raw HTML in attributes, code fences, link/image URLs, deeply nested lists, javascript: schemes) through the new renderer and through the sanitizer. No passing the gate without sanitizer coverage.
  5. Performance validation. Benchmark on our corpus in our runtime: p50/p95 parse time, peak memory, behavior under maxNestingDepth limits. Compare against the incumbent on identical hardware.
  6. Progressive rollout. Flip the lowest-risk surface first (internal docs, changelog, static pages generated in CI), then marketing/blog content, then user-generated content last — and only after the sanitizer and security tests are proven.
  7. Retire the incumbent after a defined clean period (e.g., 4 weeks of zero unexplained diffs), not immediately after the first green deploy.

Compatibility considerations. Frontmatter is parsed by the package, not by a separate YAML step — validate and default every key our templates read, because malformed frontmatter will surface as template errors rather than parse errors. Manual header IDs are supported (1.2.0), which matters for anchor stability and deep links. Custom syntax (mentions, callouts, embeds) is addable via the lexer's rule set, but every custom rule we add is an upstream-divergence we now maintain.

Sequencing. One sprint: adapter + shadow diff + security corpus + benchmark, ending in a written go/no-go. Do not start with user-generated content. Pin the exact version in composer.json and commit the lock file at every step so rollback is a one-line revert.

Operational Impact

Maintenance. We own the adapter, the sanitizer configuration, the caching layer, and the upgrade cadence. Upstream is a small team shipping frequently and fixing real issues — healthy, but not a contract. Assign a named owner and a monthly release-review ritual; with a pinned version and a parity test in CI, upgrades are low-drama.

Support. No vendor, no SLA, no paid tier. Support is GitHub issues, and escalation realistically means "we write the fix and open the PR." Budget a small contingency (a few engineer-days per quarter) for upstream contributions and for keeping our fork-ability intact (i.e., keeping our changes in the adapter, not patched into vendor/).

Scaling. Parsing is CPU-bound and near-linear in input size; the memory advantage is the more operationally interesting number because it improves density on queue workers, container memory limits, and serverless PHP runtimes. For high-traffic public pages, do not parse per request — cache rendered HTML keyed by content hash and renderer version, and invalidate on content change. For moderate traffic, per-request rendering at ~10ms for a docs-sized corpus is defensible. Always set maxNestingDepth and an input-size cap on any endpoint accepting user content.

Failure modes and mitigations.

  • Output divergence → broken layout, lost anchors, malformed tables. Mitigate with shadow-mode diffing, a golden-file test suite per content type, and a feature flag for instant rollback to the incumbent.
  • XSS regression (upstream or in our custom rules) → security incident. Mitigate with an HTML sanitizer on output, a pinned version, a standing adversarial test corpus in CI, and a documented disclosure path.
  • Upstream abandonment → frozen dependency. Mitigate with MIT licensing and a pre-agreed fork plan; the small surface area makes a fork genuinely viable.
  • Adversarial input → memory/CPU exhaustion via deep nesting or huge documents. Mitigate with maxNestingDepth, request size limits, timeouts, and rate limiting on any user-facing render endpoint.
  • Frontmatter parse failures → template exceptions on malformed content. Mitigate with schema validation and safe defaults in the adapter.

Ramp-up. Low for a PHP developer: half a day to read the docs and render a file, two to three days to build the adapter, shadow diff, and test scaffolding. The real learning curve is not the API — it is edge-case behavior and the taxonomy of acceptable vs. unacceptable output differences, which is exactly what the spike is designed to surface. Document our custom rules and our diff-triage decisions in the repo so the next engineer inherits judgment, not archaeology.

Recommendation. Fund a one-sprint pilot with a written exit criterion, gated on the parity diff, sanitizer coverage, and measured performance in our runtime. Treat this as a high-upside, low-switching-cost adoption — not a platform bet.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log