All Projects → diecast → diecast

diecast / diecast

Licence: other
static site generator infrastructure for Rust

Programming Languages

rust
11053 projects
shell
77523 projects

Projects that are alternatives of or similar to diecast

Kotsu
✨ Clean, opinionated foundation for new projects — to boldly go where no man has gone before
Stars: ✭ 48 (+300%)
Mutual labels:  static-site-generator
eleventy-plugin-cloudinary
An Eleventy shortcode that allows you to add an image from your cloudinary account
Stars: ✭ 28 (+133.33%)
Mutual labels:  static-site-generator
chili
Dropbox powered static site generator
Stars: ✭ 27 (+125%)
Mutual labels:  static-site-generator
11straps
11straps is a static website boilerplate. It combines Eleventy with Bootstrap 5. 🎉
Stars: ✭ 85 (+608.33%)
Mutual labels:  static-site-generator
twenty-twenty-hugo
Twenty Twenty Hugo is forked from WordPress Twenty Twenty theme. It's fully functional like the WordPress theme.
Stars: ✭ 48 (+300%)
Mutual labels:  static-site-generator
hyperdraft
Turn your notes into a website.
Stars: ✭ 59 (+391.67%)
Mutual labels:  static-site-generator
acblog
An open source extensible static & dynamic blog system. (an alternative tool with same features at StardustDL/paperead)
Stars: ✭ 60 (+400%)
Mutual labels:  static-site-generator
internetguzeldir
Source code of https://internetguzeldir.com. Static site generator that takes a Google spreadsheet and builds dmoz like website from it. Written with Python3.
Stars: ✭ 33 (+175%)
Mutual labels:  static-site-generator
md-site-reader
a very lightweight markdown docs site reader
Stars: ✭ 16 (+33.33%)
Mutual labels:  static-site-generator
contentful-hugo
A CLI tool that pulls data from Contentful and turns it into markdown files for Hugo and other static site generators. It also includes an express server that can be used for local development and content previews
Stars: ✭ 31 (+158.33%)
Mutual labels:  static-site-generator
angular-prerender
A command line tool to prerender Angular Apps.
Stars: ✭ 123 (+925%)
Mutual labels:  static-site-generator
gridsome-source-sanity
Sanity source plugin for Gridsome
Stars: ✭ 18 (+50%)
Mutual labels:  static-site-generator
liva-hugo
Liva is a personal blog template powered by Hugo.
Stars: ✭ 192 (+1500%)
Mutual labels:  static-site-generator
go-slate
A CLI tool to generate API documentation using Slate layout by Robert Lord
Stars: ✭ 19 (+58.33%)
Mutual labels:  static-site-generator
ob
A Blog & RSS system written in Rust based on Luke Smith's LB.
Stars: ✭ 19 (+58.33%)
Mutual labels:  static-site-generator
polyglot
Create websites using any mix of programming languages or workflows 💎
Stars: ✭ 79 (+558.33%)
Mutual labels:  static-site-generator
hagel
Single Makefile static page generator. Mostly meant as a joke.
Stars: ✭ 24 (+100%)
Mutual labels:  static-site-generator
gatsby-reactstrap
Adding Bootstrap 4 to an Gatsby React App and serve generated the static site with Express.js
Stars: ✭ 25 (+108.33%)
Mutual labels:  static-site-generator
hugofy-vscode
Hugofy is a plugin for Visual Studio Code to make life easier to use Hugo static site generator
Stars: ✭ 27 (+125%)
Mutual labels:  static-site-generator
neofeed-theme
A personal feed for Neocities, GitHub Pages, or anywhere else, built with Hugo. #IndieWeb friendly and all yours. It's better than Twitter.
Stars: ✭ 62 (+416.67%)
Mutual labels:  static-site-generator

Work in Progress

Diecast is a parallel, modular, and middleware-oriented static site generator infrastructure for Rust which enables the creation of custom static site generators.

Documentation and examples are forthcoming, but here's a taste of what it's like. For a full working example see my setup.

Primitives

The set of core Diecast primitives starts with Rule, which is used to associated behavior with particular input files. Each Rule is essentially bound to a set of matching files. This set is represented using the Bind type, which consists of one Item for every file in the input directory that is matched by the Rule in some way, e.g. a glob pattern. An Item is a representation of an input file and/or its artifacts.

A Rule defines how its corresponding Bind should be processed by associating it with a handler, which is any type that implements the Handle trait. There can be Bind-level and Item-level handlers, corresponding to traits Handle<Bind> and Handle<Item> respectively, meaning that they operate either on an entire Bind at a time or a single Item at a time.

Example

Here's a rule that matches static assets and simply copies them to the output directory:

let statics =
    Rule::named("statics")
    .handler(chain![
        bind::select(or!(
            glob!("images/**/*"),
            glob!("images/**/*"),
            glob!("static/**/*"),
            glob!("js/**/*"),
            "favicon.png",
            "CNAME")),
        bind::each(chain![
            route::identity,
            item::copy])])
    .build();

The example above defines a rule called "statics" and associates with a Bind-level handler. This handler is called Chain and it's simply a handler that chains together multiple handlers into one. Note that chain! is simply a helper macro for defining handlers of type Chain. In this case, it chains together the bind::select and bind::each handlers, both of which are Bind-level handlers.

bind::select is a handler that takes a path pattern and creates an Item in the Bind for each matching file in the input directory. This handler is useful because it helps to populate a Bind with Items.

bind::each is a handler that takes an Item-level handler and applies it to each Item in the Bind. In this case, the handler being applied to each Item is itself a chain of Item-level handlers: route::identity and item::copy. The first simply routes the input path to an output path, while the second performs a file-system copy of the file.

In plain English, the above rule essentially means:

  1. define a rule named "statics"
  2. find all files in the input directory matching the specified pattern and add a corresponding Item for each one into this rule's Bind
  3. for each Item in the Bind:
    1. route the file from the input directory directly to the output directory. e.g input/a/b/c.txt would route to output/a/b/c.txt
    2. copy the file represented by the Item from the input directory to the output directory

In Depth

The example below defines a rule called "posts" which will match any file in the input directory that matches the glob pattern posts/*.md. The rule then does the following:

  1. reads each match
  2. parses its metadata
  3. prunes away drafts
  4. parses the date
  5. renders the markdown
  6. saves a version of the content under the name "rendered" for future use (e.g. in an RSS feed)
  7. routes the output file
  8. renders the post template
  9. renders that into the site layout
  10. writes the result to the target file
  11. sorts each post by date (useful for things like the post index that follows)

Notice that it depends on the templates rule, which guarantees that it will be processed only after the templates have been processed.

let posts =
    Rule::named("posts")
    .depends_on(&templates)
    .handler(chain![
        bind::select(glob!("posts/*.markdown"))
        bind::each(chain![item::read, metadata::toml::parse]),
        bind::retain(helpers::publishable),
        bind::each(chain![
            helpers::set_date,
            markdown::markdown,
            versions::save("rendered"),
            route::pretty,
            handlebars::render(&templates, "post", view::post_template),
            handlebars::render(&templates, "layout", view::layout_template),
            item::write]),
        bind::sort_by(|a, b| {
            let a = a.extensions.get::<PublishDate>().unwrap();
            let b = b.extensions.get::<PublishDate>().unwrap();
            b.cmp(a)
        })
    ])
    .build();

Here's a "post index" rule which will create an index of the posts. Note that we're no longer using bind::select. Here we're using bind::create instead, which creates an Item in the bind that represents the creation of a file without reading from one first.

let posts_index =
    Rule::named("post index")
    .depends_on(&posts)
    .depends_on(&templates)
    .handler(chain![
        bind::create("index.html"),
        bind::each(chain![
            handlebars::render(&templates, "index", render_index),
            handlebars::render(&templates, "layout", view::layout_template),
            item::write])])
    .build();

The render_index function above could look something like this:

fn render_index(item: &mut Item) -> diecast::Result<()> {
  // notice "post index" depends on "posts",
  // so it has access to the "posts" dependency within its handlers.
  // useful for enumerating the posts in the index we're creating

  for post in item.bind().dependencies["posts"].iter() {
    // do something for each post
  }

  Ok(())
}

This can then be wired up to the Diecast command-line interface:

let mut site = Site::new(vec![statics, posts, index]);

// selects appropriate command based on
// process arguments. can also attach new commands
let command = command::Builder::new().build();

cmd.run(&mut site);

Middleware

Thanks to its extensible middleware nature, there are already a couple of packages that extend Diecast:

Previewing

  • live: watches input directory for file changes and rebuilds site accordingly
  • websocket: item updating for previews via websockets

Templating

Document Processing

Miscellaneous

  • github-pages: deploy to GitHub Pages. Can specify to build from a particular revision such as origin/master so that the site isn't built from changes that haven't been pushed, or from the working tree.
  • git: git information for items, e.g. last commit SHA and message that affected the given item
  • versions: saving and loading different versions of items. e.g. a feed-friendly version, before other processors are applied
  • adjacent: next/previous article references
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].