Home >Web Front-end >JS Tutorial >How to Create a Static Site with Metalsmith

How to Create a Static Site with Metalsmith

Christopher Nolan
Christopher NolanOriginal
2025-02-18 09:00:21764browse

How to Create a Static Site with Metalsmith

The previous article discussed the reasons for whether to use a static website generator. In short, static website generators build page files that contain only HTML from templates and raw data (usually included in Markdown files). It offers some CMS benefits without the overhead of hosting, performance and security.

Static websites may be suitable for a variety of projects, including:

  • Small website or personal blog. A website with dozens of pages, infrequent posts and one or two authors might be ideal.
  • Technical documentation, such as REST API.
  • Application prototypes that require a series of web views.
  • E-Books—Markdown files can be converted to PDF or other formats and HTML.

Essentially, a static website generator is a building tool. You can use it to run tasks or project scaffolding like you would with Grunt or Gulp.

Key Points

  • Metalsmith is a flexible pluggable static website generator that is ideal for creating lightweight websites without the overhead of traditional CMS.
  • The installation and setup of Metalsmith requires Node.js, which involves initializing a new project directory and installing the necessary plugins via npm.
  • The project structure in Metalsmith involves organizing source files, templates, and assets, and clearly distinguishes between development and production construction.
  • Metalsmith uses various plug-ins to extend functionality, such as processing Markdown files, creating RSS feeds, and generating sitemaps, all configured in build files.
  • Custom plugins can be created to handle specific tasks, such as setting up metadata or adding debug information, enhancing Metalsmith's versatility in managing website content and structure.
  • The build process of Metalsmith can be integrated with task runners such as Gulp to deal with more complex scenarios, although Metalsmith itself is sufficient for simpler processes.

Why choose Metalsmith?

The undisputed static website champion is Jekyll – a Ruby project launched in 2008. You don't necessarily need Ruby expertise to use Jekyll, but that will help. Fortunately, most popular languages ​​have a wide variety of open source static website generators. JavaScript options include Hexo, Harp, and Assemble. For simpler projects, you can also use build tools like Gulp.

I chose Metalsmith for this tutorial because it:

  1. Not targeting specific types of projects (such as blogs)
  2. Support various template and data format options
  3. Lightweight
  4. Seldom dependencies
  5. Using modular structure
  6. Provides a simple plug-in architecture, as well as
  7. Easy to get started.

This tutorial has built a demo website. It won't win any design awards, but it illustrates the basic concept. Metalsmith build code can be checked and installed from the GitHub repository. Alternatively, you can follow the instructions here and create your own basic site.

I've used Metalsmith a few times-please don't think this is the ultimate way to build every static website!

Installation Metalsmith

Make sure you have Node.js installed (for example using nvm), then create a new project directory, such as project and initialize your package.json file:

<code>cd project && cd project
npm init -y
</code>

Install Metalsmith now and the various plugins we will use to build the site. These are:

  • metalsmith-assets — Include static assets in your Metalsmith build
  • metalsmith-browser-sync — Integrate BrowserSync into your workflow
  • metalsmith-collections — Add a collection of files to global metadata
  • metalsmith-feed — Generate RSS feed for collections
  • metalsmith-html-minifier — compress HTML files using kangax/html-minifier
  • metalsmith-in-place — render template syntax in source file
  • metalsmith-layouts — Apply layout to your source file
  • metalsmith-mapsite — Generate sitemap.xml file
  • metalsmith-markdown — Convert Markdown files
  • metalsmith-permalinks — Apply custom permalink mode to files
  • metalsmith-publish — Posts that support draft, private and future dates
  • metalsmith-word-count — Calculate the word count/average reading time for all paragraphs in an HTML file
<code>npm install --save-dev metalsmith metalsmith-assets metalsmith-browser-sync metalsmith-collections metalsmith-feed metalsmith-html-minifier metalsmith-in-place metalsmith-layouts metalsmith-mapsite metalsmith-markdown metalsmith-permalinks metalsmith-publish metalsmith-word-count handlebars
</code>

Project structure

We will use the following structure as the source (src) and build (build) directory in our project.

You can create sample files as follows, or copy them directly from the demo src directory.

Page

Page Markdown file is included in src/html. This can contain a first-level subdirectory for each website section, i.e.

  • src/html/start — Pages that describe the project in a specific order
  • src/html/article — Various articles arranged in anti-chronological order
  • src/html/contact — Single contact page

Each directory contains an index.md file, which is the default page for that section. Other pages can use any unique name.

The build process converts these files into directory-based permalinks, such as

  • src/html/start/index.md becomes /start/index.html
  • src/html/start/installation.md becomes /start/installation/index.html

Each Markdown file provides content and meta information, called "preface" is located at the top between -- marks, e.g.

<code>---
title: My page title
description: A description of this page.
layout: page.html
priority: 0.9
date: 2016-04-19
publish: draft
---

This is a demonstration page.

## Example title
Body text.</code>

Most preface questions are optional, but you can set:

  • priority: A number between 0 (low) and 1 (high), which we will use to sort menus and define XML sitemaps.
  • publish: Can be set as draft, private, or future date to ensure it is not published before it is needed.
  • date: The date of the article. If not set, we will use any future release dates or file creation dates.
  • layout: The HTML template to use.

Template

HTML page template is included in src/template. Two templates have been defined:

  • src/html/template/page.html Default layout
  • src/html/template/article.md Article layout that displays date, before and after links, etc.

Although other options are supported, the Handlebars template system is used. A typical template requires a {{{ contents }}} tag to contain the page content and any preface values, such as {{ title }}:

<code>cd project && cd project
npm init -y
</code>

The references to {{> meta }}, {{> header }} and {{> footer }} are partially...

Part

The

section—or the HTML snippet file—is contained in src/partials. These are mainly used in templates, but can also be included in the content page using the following code:

<code>npm install --save-dev metalsmith metalsmith-assets metalsmith-browser-sync metalsmith-collections metalsmith-feed metalsmith-html-minifier metalsmith-in-place metalsmith-layouts metalsmith-mapsite metalsmith-markdown metalsmith-permalinks metalsmith-publish metalsmith-word-count handlebars
</code>

where partialname is the name of the file in the src/partials directory.

Static Assets

Static assets (such as images, CSS, and JavaScript files) are included in src/assets. All files and subdirectories will be copied as is to the root of the website.

Custom Plugin

The custom plugins required to build the site are included in the lib directory.

Build directory

The website will be built in the build directory. We will build the website in two ways:

  • Development Mode: HTML will not be compressed and will start the test web server.
  • Production mode: If NODE_ENV is set to production, the build directory is cleared and the final compressed file is generated.

Define your first build file

You can create a basic example called build.js in the root directory of the project directory:

<code>---
title: My page title
description: A description of this page.
layout: page.html
priority: 0.9
date: 2016-04-19
publish: draft
---

This is a demonstration page.

## Example title
Body text.</code>

Run it with node ./build.js and a static website will be created in the build directory. Markdown will be parsed as HTML, but it is not available because we did not include the template during the build process.

Metalsmith plugin

On the surface, the Metalsmith build file looks similar to the one used in Gulp (although it does not use streams). Call the plugin by passing it to the Metalsmith use method using any appropriate arguments. The plugin itself must return another function, which accepts three parameters:

  • A files array containing information about each page
  • A metalsmith object containing global information, such as metadata, and
  • A done function that must be called after the plugin completes its work

This simple example logs all metadata and page information to the console (it can be defined in build.js):

<code>
 lang="en">
  >
    {{> meta }}
  >
  >

  {{> header }}

  <main>></main>
    >

      {{#if title}}
        <h1>></h1>{{ title }}>
      {{/if}}

      {{{ contents }}}

    >
  >

  {{> footer }}

>
>
</code>

Metalsmith build code can be updated to use this plugin:

<code>{{> partialname }}</code>

This debugging function can help you create your own custom plugins, but most of the features you may need are already written – there is a long list of plugins on the Metalsmith website.

Make a better build

The main parts of the demo site build file are explained below.

If the NODE_ENV environment variable is set to production (export NODE_ENV=production on Mac/Linux or NODE_ENV=production on Windows), the variable devBuild will be set to true:

<code>cd project && cd project
npm init -y
</code>

Home directory is defined in the dir object so that we can reuse them:

<code>npm install --save-dev metalsmith metalsmith-assets metalsmith-browser-sync metalsmith-collections metalsmith-feed metalsmith-html-minifier metalsmith-in-place metalsmith-layouts metalsmith-mapsite metalsmith-markdown metalsmith-permalinks metalsmith-publish metalsmith-word-count handlebars
</code>

Load Metalsmith and plug-in modules. Note:

  • Excellent Browsersync test server is only required when creating a development build
  • HTML compressor module referenced by htmlmin is only required when creating a production build
  • Three custom plugins have been defined: setdate, moremeta, and debug (explained in more detail below)
<code>---
title: My page title
description: A description of this page.
layout: page.html
priority: 0.9
date: 2016-04-19
publish: draft
---

This is a demonstration page.

## Example title
Body text.</code>

siteMeta object is defined using information applied to each page. Important values ​​are domain and rootpath, which are set based on development or production build:

<code>
 lang="en">
  >
    {{> meta }}
  >
  >

  {{> header }}

  <main>></main>
    >

      {{#if title}}
        <h1>></h1>{{ title }}>
      {{/if}}

      {{{ contents }}}

    >
  >

  {{> footer }}

>
>
</code>

also defines a templateConfig object to set the template default values. This will be used by the metalsmith-in-place and metalsmith-layouts plugins, which enable in-page and template rendering using Handlebars:

<code>{{> partialname }}</code>
The

Metalsmith object is now initialized as before, but we also pass the siteMeta object to the metadata method to ensure that this information is available for each page. So we can refer to items like {{ name }} in any page to get the site name.

<code>// basic build

'use strict';

var
  metalsmith = require('metalsmith'),
  markdown   = require('metalsmith-markdown'),

  ms = metalsmith(__dirname) // the working directory
    .clean(true)            // clean the build directory
    .source('src/html/')    // the page source directory
    .destination('build/')  // the destination directory
    .use(markdown())        // convert markdown to HTML
    .build(function(err) {  // build the site
      if (err) throw err;   // and throw errors
    });
</code>

Our first plugin call metalsmith-publish, which removes any file whose preface publish value is set to draft, private, or future date:

<code>function debug(logToConsole) {
  return function(files, metalsmith, done) {
    if (logToConsole) {
      console.log('\nMETADATA:');
      console.log(metalsmith.metadata());

      for (var f in files) {
        console.log('\nFILE:');
        console.log(files[f]);
      }
    }

    done();
  };
};
</code>

setdate is a custom plugin included in lib/metalsmith-setdate.js. It ensures that each file has a "date" value set, and even if no value is defined in the previous question, it can be achieved by falling back to the release date or file creation time as much as possible:

<code>ms = metalsmith(__dirname) // the working directory
  .clean(true)             // clean the build directory
  .source('src/html/')     // the page source directory
  .destination('build/')   // the destination directory
  .use(markdown())         // convert Markdown to HTML
  .use(debug(true))        // *** NEW *** output debug information
  .build(function(err) {   // build the site
    if (err) throw err;    // and throw errors
  });
</code>

metalsmith-collections is one of the most important plugins because it assigns each page to a category or taxonomy based on its location or other factors in the source directory. It can reorder files using prefaces such as dates or priorities and allows you to set custom metadata for the collection. Code definition:

  • The start collection of each file in the src/html/start directory. It sorts them by priority values ​​set in the previous question in the file.
  • The article collection of each file in the src/html/article directory. It sorts them in anti-chronological order
  • The page collection of each default page named index.*. It sorts them by priority values ​​set in the previous question in the file.
<code>devBuild = ((process.env.NODE_ENV || '').trim().toLowerCase() !== 'production')
</code>

The next is the Markdown to HTML conversion, followed by the metalsmith-permalinks plugin, which defines the directory structure for the build. Please note that moremeta sets :mainCollection for each file below:

<code>dir = {
  base:   __dirname + '/',
  lib:    __dirname + '/lib/',
  source: './src/',
  dest:   './build/'
}
</code>

metalsmith-word-count Calculates the number of words in an article and calculates how long it takes to read it. Parameter { raw: true } Output only numbers:

<code>metalsmith  = require('metalsmith'),
markdown    = require('metalsmith-markdown'),
publish     = require('metalsmith-publish'),
wordcount   = require("metalsmith-word-count"),
collections = require('metalsmith-collections'),
permalinks  = require('metalsmith-permalinks'),
inplace     = require('metalsmith-in-place'),
layouts     = require('metalsmith-layouts'),
sitemap     = require('metalsmith-mapsite'),
rssfeed     = require('metalsmith-feed'),
assets      = require('metalsmith-assets'),
htmlmin     = devBuild ? null : require('metalsmith-html-minifier'),
browsersync = devBuild ? require('metalsmith-browser-sync') : null,

// custom plugins
setdate     = require(dir.lib + 'metalsmith-setdate'),
moremeta    = require(dir.lib + 'metalsmith-moremeta'),
debug       = consoleLog ? require(dir.lib + 'metalsmith-debug') : null,
</code>

moremeta is another custom plugin included in lib/metalsmith-moremeta.js. It attaches other metadata to each file:

  • root: The absolute or calculated relative file path to the root directory
  • isPage: Set to true for the default partial page named index.*
  • mainCollection: The main collection name, i.e. start or article
  • layout: If not set, the layout template can be determined from the metadata of the main collection
  • navmain: Array of top-level navigation objects
  • navsub: Array of secondary navigation objects
Plugin code is more complicated because it handles navigation. If you need a simpler hierarchy, there are simpler options.

<code>cd project && cd project
npm init -y
</code>
The metalsmith-in-place and metalsmith-layouts plugins control the in-page and template layout respectively. Pass the same templateConfig object as defined above:

<code>npm install --save-dev metalsmith metalsmith-assets metalsmith-browser-sync metalsmith-collections metalsmith-feed metalsmith-html-minifier metalsmith-in-place metalsmith-layouts metalsmith-mapsite metalsmith-markdown metalsmith-permalinks metalsmith-publish metalsmith-word-count handlebars
</code>
If htmlmin is set (in production build), we can compress HTML:

<code>---
title: My page title
description: A description of this page.
layout: page.html
priority: 0.9
date: 2016-04-19
publish: draft
---

This is a demonstration page.

## Example title
Body text.</code>
debug is the final custom plugin included in lib/metalsmith-debug.js. It is similar to the debug function described above:

<code>
 lang="en">
  >
    {{> meta }}
  >
  >

  {{> header }}

  <main>></main>
    >

      {{#if title}}
        <h1>></h1>{{ title }}>
      {{/if}}

      {{{ contents }}}

    >
  >

  {{> footer }}

>
>
</code>
Start the Browsersync test server so that we can test the development build. If you haven't used it before, it looks like magic: every time you make a change, your website will magically refresh, and when you scroll or browse the website, the views in two or more browsers will Synchronization:

<code>{{> partialname }}</code>
Lastly, we can use:

    metalsmith-mapsite Generate XML sitemap
  • metalsmith-feed Generate an RSS feed for pages in the article collection
  • metalsmith-assets Copy files and directories in src/assets to build without modification.
<code>// basic build

'use strict';

var
  metalsmith = require('metalsmith'),
  markdown   = require('metalsmith-markdown'),

  ms = metalsmith(__dirname) // the working directory
    .clean(true)            // clean the build directory
    .source('src/html/')    // the page source directory
    .destination('build/')  // the destination directory
    .use(markdown())        // convert markdown to HTML
    .build(function(err) {  // build the site
      if (err) throw err;   // and throw errors
    });
</code>
The rest is the last .build() step to create the website:

<code>function debug(logToConsole) {
  return function(files, metalsmith, done) {
    if (logToConsole) {
      console.log('\nMETADATA:');
      console.log(metalsmith.metadata());

      for (var f in files) {
        console.log('\nFILE:');
        console.log(files[f]);
      }
    }

    done();
  };
};
</code>
When you are done, you can run node ./build.js again to build your static website.

What to pay attention to

I learned a lot when building a simple Metalsmith website, but be aware of the following issues:

Incompatible plug-ins

Plugins may conflict with other plugins. For example, calculating the metalsmith-rootpath of the relative root path is not very compatible with metalsmith-permalinks that create custom build directory structures. I solved this problem by writing custom root path calculation code in the lib/metalsmith-moremeta.js plugin.

Plugin order is crucial

If the plugins are placed in the wrong order, the plugins may depend on or conflict. For example, the metalsmith-feed plugin that generates RSS must be called after metalsmith-layouts to ensure that RSS XML is not generated in the page template.

Browsersync rebuild issue

When Browsersync runs and edits the file, the collection is reparsed, but the old data still seems to exist. This may be an issue with the lib/metalsmith-moremeta.js custom plugin, but the menu and front and back links may be out of sync. To fix it, stop the build and restart the build using Ctrl/Cmd C.

Do you still need Gulp?

People using task managers such as Gulp will notice that Metalsmith provides a familiar build process. There are plug-ins for CSS preprocessing, image compression, file connection, vilification and more with Sass. For a simpler process, it might be enough.

However, Gulp has a wider range of plugins and allows for complex build activities such as lint, deployment, and PostCSS processing using auto-prefixer. There are some Gulp/Metalsmith integration plugins, although I have some problems and they should not be necessary because Gulp tasks can run Metalsmith directly, e.g.

<code>cd project && cd project
npm init -y
</code>

This process prevents the Browsersync rebuild problem mentioned above. Remember to use .clean(false) to ensure that Metalsmith never clears the build folder when other tasks are active.

Is Metalsmith suitable for you?

Metalsmith is ideal if you have simple or highly customized website needs. Maybe try using a document project and add one feature at a time. Metalsmith isn't as fully functional as alternatives like Jekyll, but it's not designed to be that way. You may need to write your own plugin, but it's easy to do so, which is a huge benefit for JavaScript developers.

Creating a Metalsmith build system takes time, and we haven't considered the amount of work involved in HTML templates and deployment. However, once you have a process available, adding, editing, and deleting Markdown files becomes very simple. It may be easier than using CMS, and you have all the benefits of a static website.

FAQs about creating static websites with Metalsmith

What is Metalsmith and why should I use it to create static websites?

Metalsmith is a simple and easy-to-use pluggable static website generator. It is based on Node.js and uses a modular structure that allows you to add functionality as needed through plugins. This makes it incredible flexibility and customizability. You should use Metalsmith to create a static website because it allows you to build your website exactly as you wish without being restricted by traditional CMS. In addition, static websites are faster, safer, and easier to maintain than dynamic websites.

How to install Metalsmith?

To install Metalsmith, you need to install Node.js and npm on your computer. After installing these, you can install Metalsmith by running the command npm install metalsmith in the terminal. This will install Metalsmith and all its dependencies.

How to create a new Metalsmith project?

To create a new Metalsmith project, first navigate in the terminal to the directory where you want to create the project. Then, run the command metalsmith to create a new project. This will create a new directory with the name of your project, and within this directory it will create a basic structure for your static website.

How to add plugins to my Metalsmith project?

To add plugins to your Metalsmith project, you need to install them via npm and then reference them in your Metalsmith configuration file. For example, to add the markdown plugin, you first need to run npm install metalsmith-markdown, and then in your configuration file, you need to add var markdown = require('metalsmith-markdown'); and add .use(markdown()) Go to your Metalsmith build chain.

How to build my Metalsmith website?

To build your Metalsmith website, you need to run the command metalsmith build in the terminal. This compiles all the files and outputs them to the build directory, which you can then deploy to your server.

How to customize the layout of my Metalsmith website?

To customize the layout of your Metalsmith website, you can use template engines such as Handlebars or Jade. These allow you to create reusable templates for different parts of your website, such as headers, footers, and individual pages.

How to add content to my Metalsmith website?

To add content to your Metalsmith website, you can create a markdown file in the source directory. When building a website, these files are converted to HTML. You can also use CMS such as Netlify CMS to manage your content.

How to deploy my Metalsmith website?

To deploy your Metalsmith website, you can use services such as Netlify or GitHub Pages. These services will host your static website and automatically deploy changes when you push to the repository.

How to update my Metalsmith website?

To update your Metalsmith website, you simply change the source file and rebuild your website. Changes will be reflected in the build directory, which you can then deploy to your server.

Can I use Metalsmith for large and complex websites?

Yes, Metalsmith is highly scalable and can be used for large and complex websites. Its modular structure allows you to add functionality as needed, and its use of static files means it can handle a lot of content without slowing down.

The above is the detailed content of How to Create a Static Site with Metalsmith. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn