MDEx

MDEx logo
Hex VersionHex DocsMIT

Fast and Extensible Markdown for Elixir.

Features

Plugins

Installation

Add :mdex dependency:

def deps do
  [
    {:mdex, "~> 0.11"}
  ]
end

Or use Igniter:

mix igniter.install mdex

Usage

Convert to HTML

iex> MDEx.to_html!("# Hello :smile:", extension: [shortcodes: true])
"<h1>Hello πŸ˜„</h1>"

GitHub Flavored Markdown (GFM)

Mix.install([
  {:mdex_gfm, "~> 0.1"}
])

markdown = """
- [x] Set up project
- [ ] Write docs

```elixir
spawn(fn -> send(current, {self(), 1 + 2}) end)
```
"""

MDEx.new(
  markdown: markdown,
  syntax_highlight: [
    formatter: {:html_multi_themes,
      themes: [light: "github_light", dark: "github_dark"],
      default_theme: "light-dark()"}
  ]
)
|> MDExGFM.attach()
|> MDEx.to_html!()

Sigils

iex> import MDEx.Sigil
iex> ~MD[# Hello :smile:]HTML
"<h1>Hello πŸ˜„</h1>"
iex> import MDEx.Sigil
iex> assigns = %{project: "MDEx"}
iex> ~MD[# {@project}]HEEX
%Phoenix.LiveView.Rendered{...}
iex> import MDEx.Sigil
iex> ~MD[# Hello :smile:]
#MDEx.Document(3 nodes)<
β”œβ”€β”€ 1 [heading] level: 1, setext: false
β”‚   β”œβ”€β”€ 2 [text] literal: "Hello "
β”‚   └── 3 [short_code] code: "smile", emoji: "πŸ˜„"
>

Streaming

iex> MDEx.new(streaming: true)
...> |> MDEx.Document.put_markdown("**Install")
...> |> MDEx.to_html!()
"<p><strong>Install</strong></p>"

Examples and Guides

In docs you can find Livebook examples covering options and usage, and Guides for more info.

Foundation

The library is built on top of:

Used By

Are you using MDEx and want to list your project here? Please send a PR!

Sponsors

πŸ’œ Support MDEx Development

If you or your company find MDEx useful, please consider sponsoring its development.

➑️ GitHub Sponsors

Your support helps maintain and improve MDEx for the entire Elixir community!

Current and previous sponsors

<img src="assets/images/dockyard_logo.svg" width="200" alt="DockYard" />

Motivation

MDEx was born out of the necessity of parsing CommonMark files, to parse hundreds of files quickly, and to be easily extensible by consumers of the library.

Comparison

Feature MDEx Earmark md cmark
Active βœ… βœ… βœ… ❌
Pure Elixir ❌ βœ… βœ… ❌
Extensible βœ… βœ… βœ… ❌
Syntax Highlighting βœ… ❌ ❌ ❌
Code Block Decorators βœ… ❌ ❌ ❌
Streaming (fragments) βœ… ❌ ❌ ❌
Phoenix HEEx components βœ… ❌ ❌ ❌
AST βœ… βœ… βœ… ❌
AST to Markdown βœ… ⚠️² ❌ ❌
To HTML βœ… βœ… βœ… βœ…
To JSON βœ… ❌ ❌ ❌
To XML βœ… ❌ ❌ βœ…
To Manpage ❌ ❌ ❌ βœ…
To LaTeX ❌ ❌ ❌ βœ…
To Quill Delta βœ… ❌ ❌ ❌
Emoji βœ… ❌ ❌ ❌
GFMΒ³ βœ… βœ… ❌ ❌
GLFM⁴ βœ… ❌ ❌ ❌
Discord⁡ ⚠️¹ ❌ ❌ ❌
  1. Partial support
  2. Possible with earmark_reversal
  3. GitHub Flavored Markdown
  4. GitLab Flavored Markdown
  5. Discord Flavored Markdown

Benchmark

A benchmark is available to compare existing libs:

Name              ips        average  deviation         median         99th %
mdex          8983.16       0.111 ms     Β±6.52%       0.110 ms       0.144 ms
md             461.00        2.17 ms     Β±2.64%        2.16 ms        2.35 ms
earmark        110.47        9.05 ms     Β±3.17%        9.02 ms       10.01 ms

Comparison:
mdex          8983.16
md             461.00 - 19.49x slower +2.06 ms
earmark        110.47 - 81.32x slower +8.94 ms

Memory usage statistics:

Name            average  deviation         median         99th %
mdex         0.00184 MB     Β±0.00%     0.00184 MB     0.00184 MB
md              6.45 MB     Β±0.00%        6.45 MB        6.45 MB
earmark         5.09 MB     Β±0.00%        5.09 MB        5.09 MB

Comparison:
mdex         0.00184 MB
md              6.45 MB - 3506.37x memory usage +6.45 MB
earmark         5.09 MB - 2770.15x memory usage +5.09 MB

The most performance gain is using the ~MD sigil to compile the Markdown instead of parsing it at runtime, prefer using it when possible.

To finish, a friendly reminder that all libs have their own strengths and trade-offs so use the one that better suits your needs.

Acknowledgements