Using Relative Links in Metalsmith

Christian Emmer
Christian Emmer
May 21, 2020 · 4 min read

Relative links in HTML increases a site's portability to be hosted from anywhere, and it's easy to automatically convert links in Metalsmith projects.

The main reason you would want to use relative links rather than semi-absolute links (those that start with /) is to make your output more portable, so it can be hosted from any directory. For example, JetBrains IDEs serve HTML files at localhost:<port>/www/<path>, though that's a very specific example.

Project setup

To keep this article short and to the point we're not going to set up a full website, just enough to show sample usage. See "Starting a Metalsmith Project" for a more complete article on how to set up a Metalsmith project.

Starting a Metalsmith Project

Sep 19, 2019 · 12 min read

Metalsmith is a plugin-based static site generator originally from Segment. It's a current favorite of mine because of how sites are built as a pipeline of plugins where the output of each plugin is the input of the next. This allows for strong control over what happens and when it happens.

Starting a Metalsmith Project

Installing packages

Starting with an empty project, install some Metalsmith packages:

npm install --save metalsmith metalsmith-html-relative

Source file structure

Create the following directories and files for use in the build pipeline:

.
├── index.js
└── src
    ├── contact
    │   └── index.html
    ├── index.html
    └── static
        └── css
            └── styles.css

No need to fill in src/static/css/styles.css, it just needs to exist.

Writing the source files

Let's fill in the HTML files such that they reference each other and our CSS:

<!-- src/index.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Home</title>
    <link rel="stylesheet" href="/static/css/styles.css">
</head>
<body>
<h1>Home</h1>
<a href="/index.html">Home</a>
<a href="/contact/index.html">Contact</a>
</body>
</html>
<!-- src/contact/index.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Contact</title>
    <link rel="stylesheet" href="/static/css/styles.css">
</head>
<body>
<h1>Contact</h1>
<a href="/index.html">Home</a>
<a href="/contact/index.html">Contact</a>
</body>
</html>

Then set up your index.js file like this:

const Metalsmith = require('metalsmith');
const relative   = require('metalsmith-html-relative');

Metalsmith(__dirname)
    .source('./src')         // source directory for the pipeline
    .use(relative())         // convert all local links to be relative links
    .destination('./build')  // destination directory of the pipeline
    .clean(true)             // clean the destination directory before build
    .build(err => {          // execute the build
        if (err) {
            throw err;
        }
    });

This will:

  • Convert all local resource links (hyperlinks, CSS, JavaScript, images, etc.) in all HTML files to be relative.
  • Copy everything in src/ to build/.

See the metalsmith-html-relative options for other available options.

Build and output

Run the build command like normal:

node index

And you'll get output similar to (minus comments):

<!-- build/index.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Home</title>
    <link rel="stylesheet" href="static/css/styles.css">  <!-- previously: /static/css/styles.css -->
</head>
<body>
<h1>Home</h1>
<a href="index.html">Home</a>  <!-- previously: /index.html -->
<a href="contact/index.html">Contact</a>  <!-- previously: /contact/index.html -->
</body>
</html>
<!-- build/contact/index.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Contact</title>
    <link rel="stylesheet" href="../static/css/styles.css">  <!-- previously: /static/css/styles.css -->
</head>
<body>
<h1>Contact</h1>
<a href="../index.html">Home</a>  <!-- previously: /index.html -->
<a href="index.html">Contact</a>  <!-- previously: /contact/index.html -->
</body>
</html>

Note that no local resource link begins with a forward slash (/), and there are a number of links that start with a parent directory reference (../).

Conclusion

Admittedly the use cases for all of this are limited, but you can definitely save some time if you need it!