You want to build a website or blog with a static site generator. Well, here is our elevator pitch. It’s as easy as that: Mustache style chart.
You want to try yourself, if it is really this easy. Have a go:
$ git clone $ cd metalsmith/examples/static-site $ make
Metalsmith and its plugins can be installed with npm:
The package exposes both a JavaScript API, and CLI in case you’re used to that type of workflow from other static site generators. To see how they’re used check out the examples.
Metalsmith is an extremely simple, pluggable static site generator. So let us explain why:
Why is Metalsmith a pluggable static site generator?
The task of a static site generator is to produce static build files that can be deployed to a web server. These files are built from source files. Basically for a static site generator this means:
from a source directory read the source files and extract their information
manipulate the information
write the manipulated information to files into a destination directory
Metalsmith is built on this reasoning. It takes the information from the source files from a source directory and it writes the manipulated information to files into a destination directory. All manipulations, however, it exclusively leaves to plugins.
Manipulations can be anything: translating templates, transpiling code, replacing variables, wrapping layouts around content, grouping files, moving files and so on. This is why we say »Everything is a Plugin«. And of course, several manipulations can be applied one after another. Obviously, in this case the sequence matters.
Why is Metalsmith extremely simple?
When all manipulations are performed by plugins, the only thing Metalsmith has to do in its core is to provide for an underlying logic of actually how manipulations are dealt with and for a defined interface for the plugins. To achieve this, we only needed around 400 lines of code — have a look at the source yourself. We believe this is rather simple.
For manipulations Metalsmith uses a very clever, but extremely simple idea. All source files are initially converted into JavaScript objects with the usual
{property: property value}
{property: property value}
pairs contain information on the original file itself (such as its
. The JavaScript object for each file is then supplemented with all variables either specified in the front-matter of the file or elsewhere. The manipulations performed by the plugins are now nothing else then modifications applied to the JavaScript objects either by changing the properties or the property values.
Breaking down Metalsmith into a core and many plugins has several advantages. It reduces complexity. It gives the user the freedom to use exactly only those plugins he or she needs. Furthermore, it distributes the honor and the burden of maintaining the Metalsmith core and its plugins onto the Metalsmith community. With this approach we hope to keep the Metalsmith environment pretty up-to-date.
Writing plugins itself is also rather simple. The plugin-interface is easy to understand and most plugins are also rather short.
Every site needs JavaScript anyway. Just like the popular task runners gulp or grunt Metalsmith is programmed in JavaScript. So, you do not have to rely on a further language such as Ruby, Python or Go. This also helps to keep your workflow simple.
All of the logic in Metalsmith is handled by plugins. You simply chain them together. Here’s what the simplest blog looks like. It uses only two plugins,
Metalsmith(__dirname) // instantiate Metalsmith in the cwd.source('sourcepath') // specify source directory.destination('destpath') // specify destination directory.use(markdown()) // transpile markdown into html.use(layouts()) // wrap a nunjucks layout around the html.build(function(err) { // this is the actual build process if (err) throw err; // throwing errors is required });
… and by the way, if you do not want your destination directory to be cleaned before a new build, just add
. But what if you want to get fancier by hiding your unfinished drafts and using permalinks? Just add plugins…
Metalsmith(__dirname).source('sourcepath').destination('destpath').clean(false) // do not clean destination // directory before new build.use(drafts()) // only files that are NOT drafts.use(markdown()).use(permalinks()) // make a permalink output path.use(layouts()).build(function(err) { if (err) throw err; });
jstransformer-nunjucks
package to render layouts. Make sure to install it with
npm install jstransformer-nunjucks
. Other templating languages can be used as well (see the metalsmith-layouts readme for more information).
Metalsmith works in three simple steps:
Read all the files in a source directory and transform them into a JavaScript object of JavaScript objects.
Invoke a series of plugins that manipulate these objects.
According to the information contained in the resulting objects write them as files into a destination directory
Every file in the source directory is transformed into a JavaScript Object. For instance,
--- title: A Catchy Title draft: false --- An unfinished article...
{ 'relative_to_sourcepath/my-file.md': { title: 'A Catchy Title', draft: false, contents: 'An unfinished article...', mode: '0664', stats: {
where the content of the file is always put into the property value of
. For illustration purposes only we display the value of
as a string. Technically, however, the property value of
object, in order to also handle straight binary data well.
contains the permission the file has and
has more technical information on the file such as
. Furthermore, the file is also parsed for YAML-front-matter information, which will then also be put into the JS Object. Thus, we finally have an JavaScript object of JavaScript objects. This encompassing JavaScript object is usally called
since it contains all the JavaScript objects that represent the files.
{ "relative_to_sourcepath/file1.md": { title: 'A Catchy Title', draft: false, contents: 'An unfinished article...', mode: '0664', stats: {
The plugins can manipulate the JavaScript objects representing the original files however they want, and writing one is super simple. Here’s the code for the
plugin from above. You can also find the code in the github repository for
. The code just runs through the JS object
and deletes all contained JavaScript objects that have a property value of
Of course plugins can get a lot more complicated too. That’s what makes Metalsmith powerful; the plugins can do anything you want and the community has written a large amount of plugins already.
Note: The order the plugins are invoked is the order they are in the build script or the file for cli implementations. This is important for using a plugin that requires a plugins output to work.
If you are still struggling with the concept we like to recommend you the
plugin. It is a metalsmith plugin that writes the
{property: property value}
pairs excerpted from the JavaScript objects representing the files to the filesystem as.json files. You can then view the.json files to find out how files are represented internally in Metalsmith.
We believe, that understanding the internal representation of files as JavaScript objects is really key to fully grasp the concept of Metalsmith. To see this, we look at what happens in the second example chain above:
So, within the Markdown chain above after applying
the initial representation of the
Assuming we have defined a very simple nunjucks layout file in a separate layouts folder…
in our Metalsmith chain our JavaScript object becomes:
is performed our JavaScript object is written to
relative_to_destpath/myfile/index.html
. So you see, how the chain works. It’s rather straight forward, isn’t it?
For Metalsmith we have stated that everything is a plugin. That is true, but in addition the Metalsmith core also provides for a
function. You can specify arbitrary
{property: property value}
pairs and these information will be globally accessible from each plugin.
var debug = require('metalsmith-debug');... Metalsmith(__dirname).source('sourcepath').destination('destpath').clean(false).metadata({ author: 'John Doe', site: 'http://example.com' }).use(markdown()).use(layouts()).use(debug()) // displays debug info on the console.build(function(err) { if (err) throw err; });
As you have seen in the code above, we have also introduced a plugin named
. For this plugin to actually show debug information you need to define an environment variable
The source and destination path, the metadata and all files are then logged to the console.
Yes, we know. The documentation can be improved. If you want to help, give us a shout. But in the meantime have a look at the Awesome Metalsmith list. There you will find references to a number of excellent tutorials, examples and use cases.
We keep referring to Metalsmith as a “static site generator”, but it’s a lot more than that. Since everything is a plugin, the core library is actually just an abstraction for manipulating a directory of files.
Which means you could just as easily use it to make…
Read template files from a directory.
Parse files for template placeholders.
Prompt user to fill in each placeholder.
Render files with a templating engine.
Write filled-in files to a new directory.
Read files from a source directory.
Convert Sass files to CSS.
Sprite images in a certain folder.
Write files to a public directory.
Read chapter files from a directory.
Build a table of contents from the tree.
Convert Markdown to HTML.
Convert Markdown to ePUB.
Convert Markdown to MOBI.
Write compiled files to a directory.
Read files from a source directory.
Convert Markdown files to HTML.
Build a navigation from the tree.
Render each file with a template.
Moustache styles how to
Write HTML to the static directory.
The plugins are all reusable. That PDF generator plugin for eBooks? Use it to generate PDFs for each of your blog posts too!
Writing a plugin is not difficult as you have seen above with the
plugin. In order to achieve more complicated tasks you will most likely find and can use
-packages. Look at how others have done it. Here is an example using
(which we appreciate if you use it) and
// we would like you to use debug var debug = require('debug')('metalsmith-myplugin'); var multimatch = require('multimatch'); // Expose `plugin`. module.exports = plugin; function plugin(opts){ opts.pattern = opts.pattern || []; return function (files, metalsmith, done){ setImmediate(done); Object.keys(files).forEach(function(file){ if(multimatch(file, opts.pattern).length) { debug('myplugin working on: %s', file); // // here would be your code // } }); }; }
Even though we touched on the topic already, we did not tackle it explicitly. We mentioned that plugins usually run through all files presented to
. This happens in a loop like this:
Object.keys(files).forEach(function(file){ // // here would be your code // });
The question now is, how does for instance a markdown-engine know, which files to transpile? The answer is easy. Per default,
is a JavaScript object that has its full filename (including its path) as a value. If the check is not true it jumps over it, otherwise it is passing the file to the engine. After processing it,
and the next plugin can now check against the new filename and so on.
A process such as this is called check for pattern matching. Many
-plugins employ such matching. Either they check against internally set requirements or patterns or they offer an explicit option to check against user defined matches, like we have already seen in the
Pattern matching is normally based on glob pattern. Many plugins employ either own functions or rely on
var multimatch = require('multimatch'); [...] // Checks whether files should be processed // length is zero if no matching pattern was found if (multimatch(file, opts.pattern).length) { // process file }
The core Metalsmith library doesn’t bundle any plugins by default.
Here’s a list of plugins that are provided by the awesome Metalsmith community. But mind you, this list is by no means complete, because not every author PRs his or her plugin. So you might want to search for further plugins:
A metalsmith plugin for indexing contents on Algolia.
Create URL aliases for any page.
Builds a file tree in metadata so you can determine parents, list children, jump to previous and next siblings.
Convert AngularJS templates from HTML into JavaScript and preload $templateCache.
Create an archives page organized by date fields.
Plugin to transform AsciiDoc files to HTML using asciidoctor.js
Test file objects with assert.
Include static assets in your build.
Automatically generate Atomic CSS from HTML using Atomizer.
Include authors information in collection files.
Automatically use metalsmith-collections based on the filesystem.
Automatically add vendor prefixes to CSS.
Nicely format your html, css or js files.
Load and render bibtex bibliographies.
Add bitly links to the metadata of each file.
Combine multiple HTML files into one. Updates links and images.
Run separate metalsmith pipelines on selected files.
Check for relative and root-relative broken links.
Compress files with brotli.
Leverage Browser Sync for an easier development workflow.
Complie Javascript with browserify.
Add a build date, for things like feeds or sitemaps.
Adds metadata about the build environment (build date, user, version, platform and more)
Process only files that have changed.
Check all links, both internal and external, in anchors, images, and external page resources.
Generate a script to cleanup the build directory, if you are adding more than just Metalsmith files.
Invalidate Amazon CloudFront cache. Best used in conjunction with the metalsmith-s3 plugin.
Syntax highlighting for code within Markdown and HTML files.
Compile CoffeeScript files to Javascript.
Add metadata to every file in a collection
Group files together, like blog posts. That way you can loop over them to generate an index, or add 'next' and 'previous' links between them.
Concatenate your files through file conventions, rather than configuration.
Create static sites with data stored at Contentful.com
Convert image files with imagemagick.
Add creation and updated timestamps
Load JSON/YAML files into the metadata of files from within your source tree or a models folder.
Use markdown content within html tags via data-markdown attribute.
Enrich file metadata with dates present in source filenames.
Format dates defined in the YAML Front Matter
Render a nice browser based ui to inspect build files & meta.
Sets default values to frontmatter metadata if they don't exist.
Manually define values in the metadata.
Discovers your template helpers and registers them with Handlebars.
Discovers your template partials and registers them with Handlebars.
Adds Disqus comments widget and counter.
Make a dithered copy of images.
Hide any files marked as drafts.
Easily apply a function to each file or filename.
Eslint your JavaScript files.
Bump files up one or more directories.
Easily encode HTML entities in any HTML file by surrounding target code in triple backticks.
Register all environment variables as metadata.
Incorporate your active Etsy shop data into a static website.
Query Excel files with SQL and convert to Markdown tables.
Omit attributes from each file's metadata.
Metalsmith plugin to create an excerpt of a html file.
Extract the first paragraph from the beginning of any HTML file.
Serve static files with express, built-in support for liveReload.
A Metalsmith favicons generator.
Generate an RSS feed for a collection.
Generate Atom feed for a collection.
Add metadata on files based on a pattern.
Allows quick manipulation of the file object.
Insert a hash of the content into the file name.
Flatten a directory hierarchy.
Iterate through the properties of a frontmatter object and for each property replace the value with the string contents of a utf-8 encoded file resolved using the original value as a file path.
Iterate through the properties of a frontmatter object and for each property render the value using a jstransformer and replace it.
Scan images in specified subfolder and add it to metadata.
Scan for images in folders and add them to metadata.
Generate sites from Gather Content projects
Lets you get gists from Github Gist
Convert markdown with Github Markdown API.
Adds the Google Analytics script to your html files
Scrape files from Google Drive.
Pull in data from a google spreadsheet using the API.
Pull in images from Gravatar.com.
A lightweight plugin that incorporates Metalsmith builds into gulp pipelines.
Use Gulp plugins in Metalsmith, or Metalsmith as a Gulp plugin. Useful for uploading files, reading less than an entire directory tree, using external front matter, etc.
Compress files with gzip.
Process Handlebars in Markdown files.
Extract headings from HTML files and attach them to the file's metadata. Useful for automatically building navigation for a document.
Add an id and anchor to all headings on a page. Ideal for permalinks.
Add page-specific hooks (like mini-plugins) to your build
Use html-validator to validate your HTML.
Tidy your HTML files to make your source beautiful.
Use Hypher hyphenation engine in your HTMLs.
Easily create multiple localised branches of your site using the excellent i18next library.
Run plugins in the build sequence conditionally.
Ignore any files that match a pattern.
A Metalsmith plugin to minify images using imagemin.
An image resizing plugin for Metalsmith. Not dependent on imagemagick/graphicsmagick!
In-place templating, render templates in your source files.
Make other source files available as properties.
Allows content to be included (nested) within other content by including the file path
Inject metadata constants into source file data.
Inline CSS files, including those generated by preprocessors
Inlines static assets like SVG, Javascript and CSS
Inlines SVG images into your HTML files
Print/inspect the file objects, mainly for debugging.
Display image and gif links on mouse hover.
Automatically generate icon font files using Fontello.
Faster incremental builds for Metalsmith.
A plugin to create directory indexes.
JavaScript packer/minifier/uglifier for Metalsmith
Automatically extract dates from Jekyll-style filenames.
Manipulate your HTML files with jQuery.
Parse.json files and make their properties available to downstream plugins.
Creates files from the properties within.json files with filename patterns and permalinks.
Compile content with any JSTransformer.
Apply layouts to your source files through any JSTransformer.
Provide `partial` helpers with any JSTransformer.
A Metalsmith plugin to auto convert dates to moment objects.
Flexible, powerful manipulation of key-value pairs in file metadata.
Add KSS styleguide information.
Apply layouts to your source files.
Convert LESS files to CSS.
Instead of manually adding links to files, repeat your script, link, img and a tags by using globs.
Creates localized branches of a collection.
Implement client-side search engine.
Convert Markdown files to HTML.
Convert Markdown files to HTML using markdown-it.
Enables the use of Markdown partials, e.g. Markdown fragments can be inserted into the contents section of a page markdown file via an include marker.
Precompiles markdown files replacing templates with their real content.
Convert Markdown files to HTML using Remarkable.
Wrapper for the Mingo library which allows to make MongoDB style queries.
Convert Javascript files to html.
Adds multi-language support to your projects.
Convert Markdown files to HTML using MultiMarkdown-4 syntax.
Load metadata from JSON or YAML files.
Add a directory of JSON files for use in templates and pages.
Read file metadata from separate files (as an alternative to frontmatter).
Highlight code in markdown files with highlight.js.
Read file metadata from frontmatter.
Include JSON models into files and expose the data as metadata on the file object
Converts file metadata to object
Stores the content before the "more" comment tag in HTML files.
Moves and/or removes files in the file structure.
Modifies metadata to make it more useful in Mustache templates. Adds easy conditions and links to parent objects.
Preprocess CSS files with Myth.
Move whole directories and their contents up one or more levels.
Generate navigation based on file trees
A metalsmith plugin for nesting your layouts when using the handlebars engine.
Add, remove and rebuild AngularJS dependency injection annotations.
Include npm modules in your globals
Filter out attributes from each file's metadata.
Add Facebook Open Graph meta tags to HTML.
Metalsmith wrapper for optipng - to optimize and make your png images smaller
Convert org-mode files to HTML.
Parses the contents of and makes them available in a global 'pkg'
adds file path values (dirname, extname, basename, path) to metadata
A plugin that use Parcel for bundling of assets
Provide 'partial' helper to include other files.
Paginate collections of file; it's meant to be used with metalsmith-collections.
A simple plugin that uses metalsmith-collections to create a paginated collection.
Paginate arrays and collections into multiple files.
Convert files with pandoc.
Convert HTML files to PDF using wkhtmltopdf
Export HTML files to PDF using Headless Chrome
Add a global site title to every `<title>` tag.
An alternative to metalsmith-permalinks allowing for custom permalinks and overrides.
Apply custom permalinks and rename files to be nested properly for static sites, basically converting `about.html` into `about/index.html`.
Gives responsive image resolution choices. Generates image sets for use with the Picset Handlebars Helper plugin
Uses generated responsive image resolutions. Those generated by the Picset Generate plugin display in browser via a `<picture>` element
Simple mirror translations for blog-like entries.
A Metalsmith plugin for PostCSS.
Stub content-less files from JSON/Yaml metadata files
Modifies internal urls with some prefix.
The imperial mustache
Generate custom text previews saved to file metadata.
Syntax highlighting for HTML templates using Prism.js.
Create static sites with data stored at Prismic.io
Adds metadata for projects (think portfolio content) from GitHub or filesystem (through collections) that can be looped over for creating a portfolio of work.
Prompt the user for series of answers in the command line and add them to the global metadata.
A metalsmith plugin to convert a property value from markdown to HTML.
Declare files as draft, private, or future-dated and use callback to automate rebuilds.
Convert Pug (previously Jade) files to HTML.
Render any file using React JS based component templates
Use React in metalsmith as a templating language
A simple plugin to create client-side HTTP redirections.
Performs search and replace in text source files
Adds a link function into your metadata so templates can link resources easier.
Rename files matching a given pattern.
Replace attribute values in each file's metadata.
Use rework CSS processor to rework your files.
Convert Rho files to HTML.
Grab content from the web and expose the results to metadata.
Bundle JavaScript with Rollup.
Auto-calculate the relative path to your root directory in template urls.
Copy, read, and write files on Amazon S3.
Convert Sass files to CSS.
Stylelint your Sass files.
Groups files into series for easier navigation
Simple http server for development. Best used with metalsmith-watch.
Use the powerful sharp library to resize and manipulate your images.
Render wordpress-esque shortcodes via templates.
A metalsmith wrapper for shortcode-parser.
A metalsmith plugin for generating a file.
Generate an image gallery, using the Skeleton CSS framework.
Add a slug property to file metadata, based on a another property.
Extract snippets from files, limited by a maximum number of characters.
Copy public assets into the build directory.
CSS packer/minifier/optimizer for Metalsmith.
Convert Stylus files to CSS.
Generate integrity hashes for site resources.
Use a shorthand when including plugins and avoid calling require() on each individual module.
Preprocess CSS files with SUITCSS.
Useful bits for those of us using swig
Create Symlinks for large files or directories.
Generate a table of contents from a document headers.
Generate tag listing pages based on tags provided in pages.
Clock how long it takes for plugins in your build sequence to run.
Add timestamp comment to html files
Deprecated in favor of metalsmith-layouts and metalsmith-in-place.
Generates JSON files from markdown, preserving filenames and frontmatter.
Converts Twitter status URLS to embedded Twitter statuses
Renders all files with the Twig template engine.
Adds Twitter Card meta tags to enable Twitter share rich snippets.
Enhance typography in HTML files.
Uglifies/minifies your JavaScript files
Remove unused CSS rules with UnCSS
Remove pages from collections, but still allow them to build
Easily validate file metadata, checking existence, type, and pattern.
Watching for file changes and trigger rebuilds.
Bundle CommonJS, AMD and ES6 modules.
Compute wordcount and average reading time.
Write the metadata excerpted from the files to the filesystem as json files.
XO lint your JavaScript files.
A Metalsmith plugin that lets you embed YouTube Videos.
If you write your own plugin, submit a pull request to the metalsmith.io repository and it will show up here!
new Metalsmith(dir)
.use(plugin)
function to the middleware stack. Metalsmith uses ware to support middleware, so plugins should follow the same pattern of taking arguments of
(files, metalsmith, callback)
argument by reference, and then calling
.build(fn)
Build with the given settings and a callback having signature
.source(path)
to the source directory, or get the full one if no
is provided. The source directory defaults to
.destination(path)
to the destination directory, or get the full one if no
is provided. The destination directory defaults to
.concurrency(max)
Set the maximum number of files to open at once when reading or writing. Defaults to
. To avoid having too many files open at once (
errors), set the concurrency to something lower than
.clean(boolean)
Set whether to remove the destination directory before writing to it, or get the current setting. Defaults to
.frontmatter(boolean)
Set whether to parse YAML frontmatter. Defaults to
.ignore(path)
Ignore files/paths from being loaded into Metalsmith.
can be a string, a function, or an array of strings and/or functions. Strings use the glob syntax from minimatch to match files and directories to ignore. Functions are called with the full path to the file as their first argument, and the
object returned by Node’s
function as their second argument, and must return either
.metadata(json)
Get the global metadata. This is useful for plugins that want to set global-level metadata that can be applied to all files.
.path(paths…)
relative to the working directory. This is useful for plugins who want to read extra assets from another directory, for example
.run(files, fn)
Run all of the middleware functions on a dictionary of
is the altered dictionary.
Add metadata to your files to access these build features. By default, Metalsmith uses a few different metadata fields:
You can add your own metadata in two ways:
Enabling a plugin that adds metadata programmatically.
Set the mode of the file. For example,
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Comments
There are no comments for this post "Metalsmith". Be the first to comment...
Add Comment