NimblePublisher Documentation

repository·master·Indexed 20 days ago

https://github.com/dashbitco/nimble_publisher

A minimal, filesystem-based publishing engine for Elixir that transforms Markdown files with frontmatter into structured Elixir data and HTML. It supports custom parsers, custom HTML converters, and syntax highlighting via Makeup.

Tokens
2.2K
Snippets
9
Records
12
Agent score
67%

What's inside NimblePublisher

  1. Best practice: Avoid duplicating module attributes

    master

    When using the module attribute generated by :as (e.g., @posts), avoid injecting it directly into multiple functions. Each time you reference the attribute in a function body, it may cause a complete copy of the collection to be made.

    Incorrect:

    def all_posts, do: @posts
    def recent_posts, do: Enum.take(@posts, 3)

    Correct: Define a single function to access the attribute and have other functions call that function.

    def all_posts, do: @posts
    def recent_posts, do: Enum.take(all_posts(), 3)
  2. Configure NimblePublisher using `use NimblePublisher`

    master

    Integrate NimblePublisher into a module using the use macro. This will scan files matching the :from pattern, process them using the :build module, and store the results in a module attribute named after :as.

    Example configuration:

    use NimblePublisher,
      build: Article,
      from: Application.app_dir(:app_name, "priv/articles/**/*.md"),
      as: :articles,
      highlighters: [:makeup_elixir, :makeup_erlang]
  3. Install NimblePublisher and highlighters

    master

    To use NimblePublisher, add it to your deps along with the desired Makeup highlighters. Note that these should be set with runtime: false as they are used during compilation/build time.

    def deps do
      [
        {:nimble_publisher, "~> 1.0", runtime: false},
        {:makeup_elixir, ">= 0.0.0", runtime: false},
        {:makeup_erlang, ">= 0.0.0", runtime: false}
      ]
    end
  4. Enable live reloading for NimblePublisher in Phoenix

    master

    To enable live reloading when files in your articles directory change, add the directory pattern to the live_reload configuration in config/dev.exs.

    Example for a posts directory:

    live_reload: [
      patterns: [
        ...,
        ~r"posts/*/.*(md)$"
      ]
    ]
  5. Define the expected file format for the default parser

    master

    If you do not provide a custom :parser, NimblePublisher expects each file to contain an Elixir map representing attributes, followed by a --- separator, and then the body of the content.

    Example file content:

    %{
      title: "Hello World",
      date: ~D[2023-01-01]
    }
    ---
    Hello world!
    %{
      title: "Hello World"
    }
    ---
    Hello world!
  6. Implement a custom parser with `parse/2`

    master

    If the default parsing logic is insufficient, provide a :parser option to use NimblePublisher. The custom module must implement a parse/2 function that receives the file path and the raw content.

    The function must return either:

    • A 2-element tuple: {attrs, body}
    • A list of 2-element tuples: [{attrs, body} | _]
    use NimblePublisher,
      ...
      parser: Parser,
    
    defmodule Parser do
      def parse(path, contents) do
        [attrs, body] = :binary.split(contents, ["\n---\n"])
        {Jason.decode!(attrs), body}
      end
    end
  7. Implement a custom HTML converter with `convert/4`

    master

    To use an alternative Markdown parser (like MDEx), provide an :html_converter option. The custom module must implement a convert/4 function.

    Signature: convert(filepath, body, attrs, opts)

    • filepath: The path to the file.
    • body: The parsed body content.
    • attrs: The parsed attributes from the file.
    • opts: The options passed to NimblePublisher.

    Return value: The converted body as a string.

    Note: If your converter doesn't include syntax highlighting, call NimblePublisher.highlight(html) on the result.

    use NimblePublisher,
      ...
      html_converter: MarkdownConverter,
      highlighters: [:makeup_elixir]
    
    defmodule MarkdownConverter do
      def convert(filepath, body, _attrs, opts) do
        if Path.extname(filepath) in ~w(.markdown .md .livemd) do
          MDEx.to_html!(body)
        end
      end
    end
  8. Configure NimblePublisher using `use NimblePublisher/1`

    master

    To use NimblePublisher in your module, call use NimblePublisher(opts). This macro triggers the extraction process, which parses files in a specified directory, builds entries using a builder module, and stores the results in a module attribute.

    Required Options

    • from: A glob pattern (e.g., `
  9. Reference NimblePublisher configuration options

    master

    When calling use NimblePublisher, you can provide the following options:

    • :build - The name of the module that will build each entry (must implement build/3).
    • :from - A wildcard pattern where to find all entries. Files with .md or .markdown extensions are converted to HTML via Earmark by default.
    • :as - The name of the module attribute to store all built entries.
    • :comrak_options - A keyword list of options accepted by MDExNative.Comrak.markdown_to_html to customize Markdown rendering.
    • :highlighters - A list of code highlighters to use (e.g., [:makeup_elixir]). Requires adding the corresponding .css classes to your project.
    • :parser - A custom module with a parse/2 function for custom file parsing.
    • :html_converter - A custom module with a convert/4 function for custom HTML conversion.
  10. Highlight code blocks in HTML with NimblePublisher.Highlighter.highlight/2

    master

    The NimblePublisher.Highlighter.highlight/2 function processes an existing HTML document to find and apply syntax highlighting to code blocks. It searches for <pre><code> patterns and replaces them with highlighted versions using the Makeup library.

    Usage

    Pass the HTML string as the first argument. You can optionally pass an options keyword list to override the default regex used to identify code blocks.

    Options

    • :regex: A regular expression used to match code blocks. The default regex is: ~r/<pre><code(?:\s+class="([^"]*)")?>([^<]*)<\/code><\/pre>/
    # Example usage:
    html_content = "<pre><code class=\"language-elixir\">def hello, do: :world</code></pre>"
    
    # Highlight the HTML
    ින්highlighted_html = NimblePublisher.Highlighter.highlight(html_content)
  11. Configure the `__using__` macro options

    master

    When calling use NimblePublisher(opts), you can provide several configuration options to control how articles are parsed, converted, and built:

    OptionDescription
    :fromRequired. A glob pattern specifying the files to be processed (e.g., "posts/*.md").
    :asRequired. The name of the module attribute where the parsed entries will be stored.
    :buildRequired. A module that implements a build/3 function to handle the final entry creation.
    :parserAn optional module implementing a parse/2 function. If omitted, the default parser expects a map in Elixir syntax followed by a --- separator.
    :html_converterAn optional module implementing a convert/4 function for custom HTML conversion.
    :highlightersA list of applications to start. If provided, the engine will automatically call NimblePublisher.Highlighter.highlight/2 on generated HTML.
    :comrak_optionsOptions passed to the underlying Comrak markdown engine (used when no custom :html_converter is provided).

    Default Markdown Behavior

    If no :html_converter is provided, NimblePublisher supports .md, .markdown, and .livemd files using Comrak with these default settings:

    • extension: [table: true, autolink: true, strikethrough: true]
    • render: [hardbreaks: false, unsafe: true]
    use NimblePublisher(
      from: "posts/*.md",
      as: :posts,
      build: MyBuilder,
      highlighters: [Makeup]
    )
  12. Highlight code blocks in HTML with `highlight/2`

    master

    You can manually highlight code blocks in an existing HTML string using NimblePublisher.Highlighter.highlight/2. This function expects the Makeup application (or similar highlighters) to be already started.

    By default, it uses the following regex to find code blocks: ~r/<pre><code(?:\s+class="([^")\s]*)")?>([^<]*)<\/code><\/pre>/

    Options:

    • :regex: A custom regex with two capture groups. The first group must be the language name and the second must be the code content.
    NimblePublisher.Highlighter.highlight(html_string, [regex: my_custom_regex])