npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tastic

v0.0.2

Published

Tastic the Fantastic, Semi-Automatic React Static site generator

Readme

Tastic is a Static-Site Generator built around building simple sites from markdown content. Relative to other Static-Site generators, tastic should

  • Be simple to get started with
  • Be simple to build on top of
  • Minimize layout and focus on the content itself

The space of static-site generators is pretty wide, and probably doesn't need another entry, so I thought I'd make my own. I tried Jekyll, and with minimal Ruby struggled to write good plugins, and eventually a gem went out of date. I tried Hugo and it was fine, but again plugins were a bit annoying. I did not try Astro or Gatsby, which might be more my speed - I spend a lot of time in React, so those might be sound starting points.

(Originally it was rendered with React via Mardown-To-JSX, and I'm planning on using React for making the frontend reactive in the future, but for now it is just inspired by React and JSX)

How to get started

  1. Put markdown content in a directory.
  2. Run tastic watch <directory>.
  3. Profit

tastic watch will build the contents into a static site in .tastic/out, set up listeners to watch the directory and trigger a rebuild on file changes, and then run a local server for the contents of the directory. For serving files on a real website you should just do tastic build and have some real server serving those files

How does tastic build things

The build process for tastic is to iterate through relevant directories, looking for files.

  • First it will iterate through any configured themes you have installed under <input>/.tastic/themes/<themeName>. If no explicit themes have been configured but there are folders there, they will be iterated through in alphabetic order
  • Then it will iterate through your layout folder in <input>/.tastic/layout. This is broadly where you should put any files relevant to the layout of your website that is not content
  • Then it will iterate through the <input> directory, ignoring the .tastic subdir if it exists

Each of these directories are fundamentally treated the same other than the fact that the priority of files align with the above iteration order - so between the files <input>/.tastic/themes/myCoolTheme/index.html, <input>/.tastic/layout/index.html and <input>/index.html, the first will be overwritten by the second and the third will override both the previous.

Within these directories,

  • files with any extension other than .html, .md, and .tastic will be copied to the out directory at their location relative to their dir (so <input>/.tastic/themes/myCoolTheme/foo/bar/baz.png will be copied to <input>/.tastic/out/foo/bar/baz.png)
  • .html, .md, and .tastic files will be processed as TasticFiles, which can go in a few different directions with a lot of overlap. A frontmatter section is parsed from each of these files containing metadata about the file, and in particular the tastic field is used to determine how exactly the file will be handled going forwards. There are 4 types of TasticFiles:
    1. post files (and any .md file will default to this) will be rendered in 5 stages:
      1. Template expansion
      2. Conversion to HTML
      3. Evaluation of components in HTML
      4. Wrapping with the special component wrapper
      5. Optionally prettified, and renamed to end in .html
    2. html files (and any .html file will default to this) will be treated the same without wrapping:
      1. Template expansion
      2. Evaluation of components in HTML
      3. Optionally prettified
    3. other files will not be assumed to be HTML, and will only be template expanded
    4. component files will be treated similarly to React components, will not produce a file of their own but can be referenced by other tastic files - e.g. <foo bar="baz">Some child</foo> might be used to render a component defined in the foo.tastic file. These files will also undergo:
      1. Template expansion
      2. Conversion to HTML
      3. Evaluation of components in HTML

Build processes

1. Frontmatter parsing

Frontmatter is parsed from the beginning of .html, .md, and .tastic files using the front-matter npm library, essentially just extracting any YAML written between ---\n bounds at the top of the file (and ignoring it if there is none). Arbitrary attributes can be passed, and the attributes will be accessible within the post variable in the Template String evaluation step, so for example:

---
foo: bar
---
${ post.foo }

will evaluate to <p>bar</p>

This information is also accessible within the site variable in contexts which have access to it, so your wrapper could do

<html>
  <body>
    ${ site.postList.map(({foo}) => foo) }
  </body>
</html>

to get a list of the foo frontmatter of all files (more about template evaluation in the next section).

Lastly, frontmatter can be used to specify options for how tastic will treat the given file by using the tastic key. This can contain an object with optional fields type to specify which of the four tastic file types this is and out to override the default path of the output file. For example, if you have a file foo.tastic

---
tastic:
  type: other
  out: foo.json
---
${ site.postList.map(({foo}) => foo) }

then the file foo.json will be created from the evaluated template string. As a shorthand, you can just pass the type instead of a full object, as in

---
tastic: component
---

2. Template string evaluation

The bodies of all Tastic files are evaluated as JS template literals. This means you can put arbitrary javascript in between ${ and } and it will be evaluated, e.g. hello ${ 1+2 } => hello 3

  • Is this terribly secure? Probably not? Make sure you are only running code that you trust! But it is at least simple to understand
  • The code will be evaluated in the context of a Function declaration, in strict mode, but that doesn't do much
  • If the value between the curly braces evaluates to null, undefined, and false, it will just be ignored instead of being rendered as the literal strings "null", "undefined", or "false" - both for JSX parity and because you probably don't want that
  • If the value between the curly braces evaluates to an array, it will be joined with spaces instead of commas
  • If the value between the curly braces evaluates to a function, it will be executed without arguments and the returned result will be cast to a string and output
  • Different tastic file types will have access to different variables
    • post files have access to the variable post of type InitialPostMetadata. This will include all of the metadata passed in the frontmatter, as well as a _file field containing metadata about the file
    • html and other files will not have access to a post variable, but will have access to the site variable of type SiteMetada, which contains a traversable tree of all of the parsed posts across the entire site
    • component files will have access to whatever variables are exposed in the thing that includes them, so it depends on whether they are referenced by a post or not. They also have access to the props variable, which will include any string attributes passed by the parent, and the children variable, which will evaluate to the compiled string of any child elements that might be passed it
      • The wrapper component and any component descendent will have access to both the site variable and an expanded post variable of type PostMetadata which includes the fully rendered post, it's table-of-contents, and helper navigation functions

3. HTML Conversion

All post files will be converted to HTML by first parsing their entirety with the node-html-parser package, and then any non-empty top-level text-nodes will be treated as markdown and converted into html via marked. This means something like this

---
some: ["front", "matter"]
---

# h1

<h2>h2</h2>

_italics_

<fakeTag />

Will be converted into the HTML

<h1>h1</h1>
<h2>h2</h2>
<i>italics</i>
<fakeTak />

4. Component evaluation

Any component referenced in the output of the HTML conversion step or in a given HTML file will be evaluated more or less as if it was included in the parent, with the additional props and children variables.

A component like foo.html:

# ${ post.title } - ${props.label}

${ children }

The end

when included by a given post:

---
title: Title
---

<foo label="label">Lorem Ipsem</foo>

would be evaluated as

<h1>Title - label</h1>
<p>Lorem Ipsem</p>
<p>The end</p>

If a component is declared at a given relative path, it will only be valid for files at that relative path or below, so /post.md would not see the existence of /docs/component.html, while /docs/post.md would.

If in the evaluation of a file, a component is valid from multiple locations, the component is overridden with the same priorities as regular files are overridden, as discussed at the top of the file - so /.tastic/layout/component.html would override /.tastic/themes/foo/component.html

5. Wrapping

The wrapper component (just a regular component with the name of wrapper) is a bit of a special case, in that instead of manually being referenced, if defined (and it almost certainly should be defined) it ends up being the wrapper provided around each post file. It should looks something like

<html>
  <head>
    <!-- all your common head stuff -->
  <head>
  <body>
    <!-- all your common body stuff, navigation, footers -->
    <!-- It is essential that you include children,
    cause otherwise your posts won't show up -->
    ${ children }
  </body>
</html>

It can and should reference other components to remain simple

TODO

Things I would like to and likely will do:

  • [ ] Theme-management as part of CLI
  • [ ] Dynamic theme and param management within watch command, involving something like
    • including some sort of process.env variable in the site variable which will let a component evaluate whether it is being run in the watch environment
    • using that to load a JS file in the default wrapper only when running in the watch environment
    • using that to add a little UI that can pop out and be used to send a few small API calls to the watch server
    • which will then adjust settings and rebuild
  • [ ] Include a default theme as part of the release?
  • [ ] Just generally more themes, tastic-themes repo
  • [ ] Get markdown with inline html to render appropriately (right now, html breaks markdown into chunks)
  • [ ] Allow for turning off katex, mermaid, and syntax highlighting
  • [ ] Expose more options for adding hooks to marked and options for highlight.js and katex
  • [ ] Nice ergonomics around getting post lists, filtered, sorted, nested, paginated
  • [ ] Get top-heading (first html element a heading?) and excerpt (first ~80 words of first paragraph?)
  • [ ] Allow meta components that do things like declare other output files (<tastic:Page url="foo"># contents</tastic:Page> ?) or remove this one (<tastic:Cancel /> ?)
  • [ ] Render as React app
  • [ ] tastic init command to add .tastic directory, install themes, optionally configure github action