mix grf.build (Griffin v0.4.2)

View Source

Generates a static website from template and layout files.

$ mix grf.build [--input INPUT] [--output OUTPUT]

Template and layout files will be read from INPUT directory and sub-folders, and output generated content to the OUTPUT directory.

Options

  • -in, --input - the path to the input directory. Defaults to src.

  • -out, --output - the directory where Griffin will write files to. Defaults to _site

  • --layouts - the directory where the layout and partials files are kept. Defaults to lib/layouts.

  • --data - the directory where global data files are stored.

  • --passthrough-copies - comma separated list of directories or files to copy directly to the output directory without processing. Supports wildcard paths using Path.wildcard/1 Useful for assets files.

  • --ignore - comma separated list of directories or files to ignore inside the input directory.

  • --config - the path to the configuration file

  • --dry-run - disables writing to the file system. Useful for tests and debugging.

  • --quiet - print minimal console output

  • --debug - print additional debug information

Passthrough copy

Passthrough copy files are files that shouldn't be processed but simply copied over to the output directory. This is useful for assets like images, fonts, JavaScript and CSS. A list of comma separated file or wildcard paths may be provided via the --passthrough-copies option. Here's an example:

$ mix grf.build --passthrough-copies=assets/js,fonts,images/*.{png,jpeg}

This command will copy all files in the assets/js, fonts and all PNG and JPEG images in the images directory over to the same path relative to the output directory. In the above example and assuming the default _site output directory, Griffin would copy files to _site/assets/js, _site/fonts and _site/images directories, respectively. Wildcard paths are expanded by Path.wildcard/1 and thus all options that it supports can be used to build wildcard paths.

About passthrough copy paths

The paths mentioned in this option are not relative to the input directory, and instead are relative to the root of the Griffin project.

Ignore files

Griffin allows users to ignore specific files and/or directories via the --ignore option. This is useful for ignoring markdown files like readme and changelog files that might be in the source directory and that should not be processed. A list of comma separated file wildcard paths can be passed using this option to ignore files or directories from processing.

Here's an example:

$ mix grf.build --ignore=src/posts/drafts,src/README.md

This command will ignore all input files from the src/posts/drafts directory along with the src/README.md file. Wildcard paths are expanded by Path.wildcard/1 and thus all options that it supports can be used to build wildcard paths.

The paths mentioned in this option are not relative to the input directory, and instead are relative to the root of the Griffin project.

Default ignores

By default Griffin imports the ignores from your .gitignore file.

Quiet option

Griffin prints out information about files that it processed, including the rendering engine that processed the file (only earmark for now). For large projects or other instances where users need minimal console output, there is the --quiet option.

Config file

Griffin allows passing in ad-hoc configuration files through the --config option. This option accepts a path to a file that is then piped into Code.eval_file/2. Although this file can contain any Elixir code, it is expected to return a map with the same configuration keys as those used by Application environment. Here's an example config.ex file that returns a valid Griffin config:

%{
  # any other config key could be set here
  input: "custom_input_dir",
  output: "custom_output_dir"
}

This option simplifies configuration since it doesn't rely on Application environment, and it allows for better testing.

Dry run

If you're debugging an issue or just want to test Griffin out, you can use the --dry-run option to run Griffin without writing to the file system.

Other options

Griffin uses other configuration options that can be changed by setting specific application environment keys under the :griffin_ssg application. These other options include features that cannot be passed in as a single CLI option like hooks, shortcodes, filters, and more.

Hooks

Hooks are a way to allow user defined functions to be called at specific stages of the website generation process. The available hook events are:

  • before, executed before the build process starts
  • after, executed after Griffin finishes building.

The result from invoking these hooks is not checked.

Multiple hooks of each kind can be set under the :hooks configuration key like so:

config :griffin_ssg,
  hooks: %{
    before: [
      fn { directories, run_mode, output_mode } ->
        # Read more below about each type of event
        :ok
      end
    ],
    after: [
      fn { directories, results, run_mode, output_mode } ->
        # Read more below about each type of event
        :ok
      end
    ]
  }

Hook event arguments

These are the arguments that are passed in to the hook events:

  • directories: a map containing the current project directories
    • directories.input (defaults to src)
    • directories.output (defaults to _site)
    • directories.layouts (defaults to lib/layouts)
  • output_mode: currently hardcoded to "filesystem"
  • run_mode: currently hardcoded to "build"
  • results: (only avaiable on the after event). A list with the processed Griffin output
    • Each individual list item will have { input_path, output_path, url, content }

Shortcodes

Shortcodes are user definable functions that can be invoked inside layouts. These functions enable easily reusable content. Shortcodes can be added under the shortcodes configuration key. Here's an example shortcode for embedding YouTube videos:

config :griffin_ssg,
  shortcodes: %{
    youtube: fn slug ->
      """
      <iframe width="560" height="315" src="https://www.youtube.com/embed/#{slug}"
              title="YouTube video player" frameborder="0" allow="accelerometer;
              autoplay; clipboard-write; encrypted-media; gyroscope;
              picture-in-picture; web-share" allowfullscreen>
      </iframe>
      """
    end
  }

This will create a youtube assigns variable that can be referenced in all layouts like so:

<main>
  <p>Here's a classic YouTube video:</p>
  <%= @youtube.("dQw4w9WgXcQ") %>
</main>

Shortcodes can be defined with an arbitrary number of arguments and they are expected to return content. They can reference variables or other shortcodes. When using shortcodes users can think about them as function components.

Filters

Filters are utility functions that can be used in layouts to transform and data into a more presentable format.

Like shortcodes, they are set in the application environment and they are processed into assigns variables that can be referred in all layouts.

Here's an example of a layout that uses an uppercase filter:

<h1><%= @username |> @uppercase.() %></h1>

This filter can be defined in the configuration file under the :filters configuration key:

config :griffin_ssg,
  filters: %{
    uppercase: &String.upcase/1
  }

Filters versus Shortcodes

Both filters and shortcodes are user defined functions that generate output in some way. While shortcodes are meant to be convenient function components that generate any sort of output, filters are typically designed to be chained, so that the value returned from one filter is piped into the next filter.