Giter VIP home page Giter VIP logo

metalsmith's Introduction

Metalsmith

npm: version ci: build code coverage license: MIT Gitter chat

An extremely simple, pluggable static site generator for NodeJS.

In Metalsmith, all of the logic is handled by plugins. You simply chain them together.

Here's what the simplest blog looks like:

import { fileURLToPath } from 'node:url'
import { dirname } from 'path'
import Metalsmith from 'metalsmith'
import layouts from '@metalsmith/layouts'
import markdown from '@metalsmith/markdown'

const __dirname = dirname(fileURLToPath(import.meta.url))

Metalsmith(__dirname)
  .use(markdown())
  .use(
    layouts({
      pattern: '**/*.html'
    })
  )
  .build(function (err) {
    if (err) throw err
    console.log('Build finished!')
  })

Installation

NPM:

npm install metalsmith

Yarn:

yarn add metalsmith

Quickstart

What if you want to get fancier by hiding unfinished drafts, grouping posts in collections, and using custom permalinks? Just add plugins...

import { fileURLToPath } from 'node:url'
import { dirname } from 'node:path'
import Metalsmith from 'metalsmith'
import collections from '@metalsmith/collections'
import layouts from '@metalsmith/layouts'
import markdown from '@metalsmith/markdown'
import permalinks from '@metalsmith/permalinks'
import drafts from '@metalsmith/drafts'

const __dirname = dirname(fileURLToPath(import.meta.url))
const t1 = performance.now()
const devMode = process.env.NODE_ENV === 'development'

Metalsmith(__dirname) // parent directory of this file
  .source('./src') // source directory
  .destination('./build') // destination directory
  .clean(true) // clean destination before
  .env({
    // pass NODE_ENV & other environment variables
    DEBUG: process.env.DEBUG,
    NODE_ENV: process.env.NODE_ENV
  })
  .metadata({
    // add any variable you want & use them in layout-files
    sitename: 'My Static Site & Blog',
    siteurl: 'https://example.com/',
    description: "It's about saying »Hello« to the world.",
    generatorname: 'Metalsmith',
    generatorurl: 'https://metalsmith.io/'
  })
  .use(drafts(devMode)) // only include drafts when NODE_ENV === 'development'
  .use(
    collections({
      // group all blog posts by adding key
      posts: 'posts/*.md' // collections:'posts' to metalsmith.metadata()
    })
  ) // use `collections.posts` in layouts
  .use(
    markdown({
      // transpile all md file contents into html
      keys: ['description'], // and also file.description
      globalRefs: {
        // define links available to all markdown files
        home: 'https://example.com'
      }
    })
  )
  .use(permalinks()) // change URLs to permalink URLs
  .use(
    layouts({
      // wrap layouts around html
      pattern: '**/*.html'
    })
  )
  .build((err) => {
    // build process
    if (err) throw err // error handling is required
    console.log(`Build success in ${((performance.now() - t1) / 1000).toFixed(1)}s`)
  })

How does it work?

Metalsmith works in three simple steps:

  1. Read all the files in a source directory.
  2. Invoke a series of plugins that manipulate the files.
  3. Write the results to a destination directory!

Each plugin is invoked with the contents of the source directory, and each file can contain YAML front-matter that will be attached as metadata, so a simple file like...

---
title: A Catchy Title
date: 2024-01-01
---
An informative article.

...would be parsed into...

{
  'path/to/my-file.md': {
    title: 'A Catchy Title',
    date: new Date(2024, 1, 1),
    contents: Buffer.from('An informative article'),
    stats: fs.Stats
  }
}

...which any of the plugins can then manipulate however they want. Writing plugins is incredibly simple, just take a look at the example drafts plugin.

Of course they can get a lot more complicated too. That's what makes Metalsmith powerful; the plugins can do anything you want!

Plugins

A Metalsmith plugin is a function that is passed the file list, the metalsmith instance, and a done callback. It is often wrapped in a plugin initializer that accepts configuration options.

Check out the official plugin registry at: https://metalsmith.io/plugins.
Find all the core plugins at: https://github.com/search?q=org%3Ametalsmith+metalsmith-plugin
See the draft plugin for a simple plugin example.

API

Check out the full API reference at: https://metalsmith.io/api.

CLI

In addition to a simple Javascript API, the Metalsmith CLI can read configuration from a metalsmith.json file, so that you can build static-site generators similar to Jekyll or Hexo easily. The example blog above would be configured like this:

metalsmith.json

{
  "source": "src",
  "destination": "build",
  "clean": true,
  "metadata": {
    "sitename": "My Static Site & Blog",
    "siteurl": "https://example.com/",
    "description": "It's about saying »Hello« to the world.",
    "generatorname": "Metalsmith",
    "generatorurl": "https://metalsmith.io/"
  },
  "plugins": [
    { "@metalsmith/drafts": true },
    { "@metalsmith/collections": { "posts": "posts/*.md" } },
    { "@metalsmith/markdown": true },
    { "@metalsmith/permalinks": "posts/:title" },
    { "@metalsmith/layouts": true }
  ]
}

Then run:

metalsmith

# Metalsmith · reading configuration from: /path/to/metalsmith.json
# Metalsmith · successfully built to: /path/to/build

Options recognised by metalsmith.json are source, destination, concurrency, metadata, clean and frontmatter. Checkout the static site, Jekyll examples to see the CLI in action.

Local plugins

If you want to use a custom plugin, but feel like it's too domain-specific to be published to the world, you can include plugins as local npm modules: (simply use a relative path from your root directory)

{
  "plugins": [{ "./lib/metalsmith/plugin.js": true }]
}

The secret...

We often refer to Metalsmith as a "static site generator", but it's a lot more than that. Since everything is a plugin, the core library is just an abstraction for manipulating a directory of files.

Which means you could just as easily use it to make...

Resources

Troubleshooting

Set metalsmith.env('DEBUG', '*metalsmith*') to debug your build. This will log debug logs for all plugins using the built-in metalsmith.debug debugger. For older plugins using debug directly, run your build with export DEBUG=metalsmith-*,@metalsmith/* (Linux) or set DEBUG=metalsmith-*,@metalsmith/* for Windows.

Node Version Requirements

Future Metalsmith releases will at least support the oldest supported Node LTS versions.

Metalsmith 2.6.x supports NodeJS versions 14.18.0 and higher.
Metalsmith 2.5.x supports NodeJS versions 12 and higher.
Metalsmith 2.4.x supports NodeJS versions 8 and higher.
Metalsmith 2.3.0 and below support NodeJS versions all the way back to 0.12.

Compatibility & support policy

Metalsmith is supported on all common operating systems (Windows, Linux, Mac). Metalsmith releases adhere to semver (semantic versioning) with 2 minor gray-area exceptions for what could be considered breaking changes:

  • Major Node version support for EOL (End of Life) versions can be dropped in minor releases
  • If a change represents a major improvement that is backwards-compatible with 99% of use cases (not considering outdated plugins), they will be considered eligible for inclusion in minor version updates.

Credits

Special thanks to Ian Storm Taylor, Andrew Meyer, Dominic Barnes, Andrew Goodricke, Ismay Wolff, Kevin Van Lierde and others for their contributions!

metalsmith's People

Contributors

adrieankhisbe avatar ajedi32 avatar ansballard avatar calvinmetcalf avatar come-maiz avatar dominicbarnes avatar f2prateek avatar gamingcoder avatar ianstormtaylor avatar iwootten avatar justaboutjeff avatar lambtron avatar lramsey avatar mayo avatar moox avatar moozzyk avatar mortonfox avatar rwilhelm avatar ry5n avatar sethfalco avatar shicks avatar shinnn avatar sigo avatar srcreigh avatar tmcw avatar treygriffith avatar tschaub avatar webketje avatar woodyrew avatar zearin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

metalsmith's Issues

Out-of-the-box dev server for metalsmith

I was curious about the inclusion of a out of the box local server command for metalsmith.
Having used wintersmith very briefly, one of the handy aspects of that tool was the ability to enter $ wintersmith preview and bam a local server is running with watch going in the background. Similar to how you might use grunt-connect.

While I understand that metalsmith is more a file manipulator than a pure static site generator, I would think a lot of people would find this super useful.

(or at least a connect plugin)
-thanks!

Can we do replacements in file names or paths?

I'm just looking into MetalSmith as a solution for a project scaffolder. Is it possible to use something like the Prompt plugin to change the names of files or paths?

What I need to do is prompt for something like module and then rename a file such as module-settings.js. If I answer production to the prompt module then I want the file renamed to production-settings.js

Make the `read` function pluggable

It would be awesome if we could intercept the file read function by making it an pluggable interface.

The API could look like.

var m =  Metalsmith(__dirname)
  .reader(customReader)
 [...]

#reader(aReader)

Set the file reader to aReader, or get the full one if no aReader is provided.

aReader interface

A reader would look like:

var aReader = function(path, buffer){}

The current behaviour would be implemented like this:

var defaultReader = function(filepath, buffer){
  var file = { contents : buffer };
  if ( utf8(buffer) ){
     var parsed = front(buffer.toString());
     file = parsed.attributes;
     file.contents = new Buffer(parsed.body);
  }
  return file;
}

$ npm install metalsmith.... now what.

After installing node, npm and metalsmith, yeah, I'm a bit lost.
Is there any place where I could find some sort of step by step tutorial to get me started?
Haven't found anything in google.
Thanks.

Can't build jekyll example because segmentio/substitute won't install

I'm trying to test out the jekyll example on c9.io and the build process fails with the following errors.

npm ERR! git clone git://github.com/segmentio/substitute execvp(): No such file or directory
npm http 200 https://registry.npmjs.org/slug-component
npm http GET https://registry.npmjs.org/slug-component/-/slug-component-1.1.0.tgz
npm http 200 https://registry.npmjs.org/slug-component/-/slug-component-1.1.0.tgz
npm ERR! Error: spawn ENOENT
npm ERR!     at errnoException (child_process.js:980:11)
npm ERR!     at Process.ChildProcess._handle.onexit (child_process.js:771:34)
npm ERR! If you need help, you may report this log at:
npm ERR!     <http://github.com/isaacs/npm/issues>
npm ERR! or email it to:
npm ERR!     <[email protected]>

npm ERR! System Linux 2.6.32-431.3.1.el6oso.bz844450v4.x86_64
npm ERR! command "/usr/libexec/openshift/cartridges/c9-0.1/root/bin/node-openshift-v10" "/usr/libexec/openshift/cartridges/c9-0.1/root/lib-0.10/node_modules/npm/bin/npm-cli.js" "install"
npm ERR! cwd /var/lib/stickshift/53274867e0b8cd2089000016/app-root/data/804067
npm ERR! node -v v0.10.22
npm ERR! npm -v 1.3.8
npm ERR! syscall spawn
npm ERR! code ENOENT
npm ERR! errno ENOENT

Getting content of page in index.html

So I'm building a blog using Metalsmith and I have come to a problem.

I want to access content (in Markdown) from actual page in index.html, but the best I can do is {{contents}} and then I get whole contents of page (including page.html with <html> tags etc.).

Here's source of my blog.

Here's the place I want to display content of a page.

Thanks!

Community page?

Metalsmith is great! I've been tinkering around with it as my first tool of this kind simply because it is so extensible and elegant.

Is there a community forum, IRC channel, etc for metalsmith users and plugins?

Is there an easy way to render metadata in a markdown file?

I have a markdown file that I'm sending to a template file (I'm using metalsmith-templates). I also want this markdown file to be able to render things like: {{title}}

How would I go about doing this?
I'm new to this, so sorry if this is a dumb question.

Build files with specific mode (i.e. permission)

I'm writing a plugin that generates a clean script for a given metalsmith build. Right now I'm using metalsmith to generate this file --- i.e.

var path = 'clean.sh';
var result = '#!/bin/bash \nrm foo \nrm bar';
files[path] = { 'contents': result };
done();

but the problem is that (AFAIK) there's no way to specify the mode of the generated file. Shouldn't be too hard to add this functionality, and have it use the file's metadata.

Figure out file URL

Hi, I am currently in the process of figuring the menu of my website and I'm running into a tad bit of trouble figuring out the URL of a file.

Currently I have the following on my header.toffee file:

<nav>
    <ul>
        {#
            for page in menu {:
                <li><a href="#{page.url}" title="#{page.title}">#{page.title}</a></li>
            :}
        #}
    </ul>
</nav>

That outputs:

<nav>
    <ul>
        <li><a href="" title="Homepage">Homepage</a></li>
        <li><a href="" title="Posts">Posts</a></li>
        <li><a href="" title="About Me">About Me</a></li>
        <li><a href="" title="Contact">Contact</a></li>
    </ul>
</nav>

Which is OK. Now you will notice in the source code I have #{page.url}, what should I be using for this? Or should I define this on each file? Or on a metadata file? TBH it would be a bit of a pain to do that.

What I'm looking for is that if the file is in src/posts/blah.md that gets a URL metadata of /posts/blah.html or something along those lines.

What solution do you offer to achieve this? Thanks! :)

Error: No compatible version found: chalk

See https://travis-ci.org/OzzyCzech/metalsmith-title/builds/20998659

Seems to me like problem only on Travis

npm ERR! Error: No compatible version found: chalk@'^0.4.0'
npm ERR! Valid install targets:
npm ERR! ["0.1.0","0.1.1","0.2.0","0.2.1","0.3.0","0.4.0"]
npm ERR!     at installTargetsError (/home/travis/.nvm/v0.8.26/lib/node_modules/npm/lib/cache.js:719:10)
npm ERR!     at /home/travis/.nvm/v0.8.26/lib/node_modules/npm/lib/cache.js:641:10
npm ERR!     at saved (/home/travis/.nvm/v0.8.26/lib/node_modules/npm/node_modules/npm-registry-client/lib/get.js:138:7)
npm ERR!     at Object.oncomplete (fs.js:297:15)
npm ERR! If you need help, you may report this log at:
npm ERR!     <http://github.com/isaacs/npm/issues>
npm ERR! or email it to:
npm ERR!     <[email protected]>

Too many files causes plugins to not be called?

I'm trying to run metalsmith on a directory for source files. This directory contains my .git and node_modules directories (among a couple other things), so as you can imagine this includes many.. many files.

With that said, plugins do not seem to be called at all when this is done. I'm estimating around ~2000 files are located within these directories so i suspect the sheer volume of the files is proving to be a problem.

I ended up forking metalsmith to add an ignore method, which works around the problem.. but it doesn't solve the core issue. So i figured it was in good taste to post a ticket heh :)

Thoughts?

Multi Language Support?

Is there already a solution out there? Or if not, any plan to support it?

For template, implement a I18n.t(key) function is easy, but data from json or markdown file need a way to stored and used. I think it need to be built into the core, so that plugins can follow the convention and support it.

Metalsmith server?

I'm not aware of any sort of server being used for local development. I've seen the plugin to watch/actively build but nothing to serve the content up with. Am I mistaken or are we supposed to add that functionality ourselves? and if so what are some recommendations? Thanks.

#run signature in README is not corrent for Metalsmith.prototype.run in lib/index.js

run signature in README is not corrent for Metalsmith.prototype.run

with @normanrz 's #28 's run method, i can use metalsmith as normal, just get the json object to do something else.

like this:

Metalsmith(__dirname)
.use(plugin1)
.use(plugin2)
.run(fn)

but with v0.5.0's #run, i have no idea how can i get files list. maybe this?

var metal = Metalsmith(__dirname)
.use(plugin1)
.use(plugin2);

metal.read(function(err, files){
    metal.run(files, fn);
});

if so, i think i like the previous one :)

i think run is a little same to build, the only difference is, build write data to disk, and run just call all middleware, and output a json object.

why change run method from run(fn) in #28 to run(files, fn) in v0.5.0?

thanks.

Should be able to run more than once

The following fails for me.
(Real-world use case: I want gaze to run build() on each change under the src/ directory.)

$ npm install && node build.js

/Users/asadovsky/dev/test/node_modules/metalsmith/node_modules/async/lib/async.js:30
            if (called) throw new Error("Callback was already called.");
                              ^
Error: Callback was already called.
    at /Users/asadovsky/dev/test/node_modules/metalsmith/node_modules/async/lib/async.js:30:31
    at Object.oncomplete (fs.js:107:15)

File contents below.

package.json

{
  "name": "test",
  "version": "0.0.1",
  "dependencies": {
    "metalsmith": "^0.9.0"
  }
}

build.js

function build() {
  require('metalsmith')(__dirname).build();
}
build();
build();

src/index.html

hello

Metalsmith and Filenames, What can we do to improve them?

I just wanted to create a metalsmith-core discussion after we talked in metalsmith/collections#9. So, with that said..

The Problem

Filename mutations are hard to track, and hard to reference. The most common use case i run into is files linking to themselves, or other files. A file object found in the files object has no clue what it's own filename is. So templates that want to render that file, possibly with links to itself or other similar files, run into issues.

This problem becomes more prevalent with plugins like metalsmith-collections(). A collection is a list of files, and because these files are broken away from the files object, there is a large disconnect between the file data and the filename of that file.

The core of the issue is that an object, as it seems to me, is a poor storage format for a series of files. We can create plugins to store the filename within the file data, but when the key of the files inevitably mutates, there is no longer any validity to file.filename. You can set a spec, which requires updates to both to be changed in tandem, but then you have to wonder why even bother with the key at all?

Solution?

The two most obvious solutions are..

  • Store a filename value in each file's metadata, and have plugins update that when they change the filename. This is suboptimal for multiple reasons (mild incompatability with current plugins, error prone due to sync requirements, etc)
  • Another solution would be to replace the object with an array. While this would cleanly solve the syncing issue above, it also is a massive change to the core design to this library, and severely breaks all plugins.. i think it's a safe assumption that we're stuck with the file Object for now.

Any thoughts? Hopefully there is a sane solution i'm not thinking of.

Categories or Tags?

Hi there,

Really like the design of Metalsmith but got blocked when trying to reproduce a Tag or Category functionality with the existing plugins. More specifically I'm talking about accessing all posts in a category or tag with a tag.* approach and being able to add tag (and multiple tags) metadata. Cherry on top would be hierarchical Categories like in Hexo.

Am I missing something obvious or should I wait for @lasar with https://github.com/lasar/metalsmith-tags?

Cheers,

Jun

can't install metalsmith

when installing metalsmith i get the npm error message

Error: No compatible version found: chalk@'^0.4.0'
Valid install targets:
0.1.0","0.1.1","0.2.0","0.2.1","0.3.0","0.4.0"]

Not sure if it makes a difference or not but I'm on windows

Ignoring files on Read, thoughts?

So i was running into issues with metalsmith reading many files, which can be discussed here: #49

With that said, i needed to solve the issue myself. Ignoring the files seemed like an obvious solution, but i didn't see a way to ignore the files that metalsmith was working with right from the start. As i mentioned in #49, metalsmith was failing to load plugins in general.. so that didn't seem possible.

With that said, i introduced a ignore files option in both jergason/recursive-readdir/pull/4 and metalsmith (https://github.com/leeolayvar/metalsmith/compare/ignores-support).

I'm opening this ticket for discussion to discuss if my metalsmith patch is even welcome. I don't know the ecosystem, so there may likely be a more idiomatic way to accomplish this workaround. Also, this is a ticket instead of a PR because my metalsmith PR depends on a PR to readdir() so it cannot be merged yet.

Anyway, thoughts? Note that tests are included for both patches.

Thanks.

Missing dependency: commander

The module commander is not listed as a dependency in package.json and therefore metalsmith throws the following error:

module.js:340
    throw err;
          ^
Error: Cannot find module 'commander'
    at Function.Module._resolveFilename (module.js:338:15)
    at Function.Module._load (module.js:280:25)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object.<anonymous> (/usr/local/lib/node_modules/metalsmith/bin/metalsmith:5:15)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)

Make Metalsmith interoperable with Gulp

There are quite a few build tools that have popped up in the last months. Gulp is one of them. It is based on node streams and has a very fast-growing plugin ecosystem. However, it doesn't have great metaphors for 1:n file transformations, like Sass-imports or RequireJS optimization. Because of the tree-transformations possible in Metalsmith plugins, it is a better fit for these kind of tasks.

I was wondering if it was a good idea to make Metalsmith ready for interoperation. Gulp uses Vinyl for representing files which is very similar to Metalsmith's representation. There could be a very thin adapter. Other than that Metalsmith would need a way to accept in-memory files as input instead of disk-only. For in-memory output, I made #28.

I'm curious, what you guys think.

irc channel

It would be nice to have a way to discuss about metalsmith, don't you think ?

Corrupted images after build

I have .png (images) stored inside the src folder with my .md files: when I run metalsmith these images are copied in the build directory (as I want) but corrupted.

This is the my metalsmith file

{
  "source": "src",
  "destination": "build",
  "plugins": {
    "metalsmith-markdown": {
      "smartypants": true,
      "gfm": true,
      "tables": true,
      "smartyLists": true
    },
    "metalsmith-templates": {
      "engine": "handlebars",
      "directory": "templates"
    },
    "metalsmith-assets": {
      "source": "./assets",
      "destination": "./assets"
    }
  }
}

And these are two md5sum of two images

MD5 (src/w1/res/api-level.png) = 1c61169cc0998d23fd879a2651b4e691
MD5 (build/w1/res/api-level.png) = e2f5d76e9997b443302e69c98bedd214

Middleware not run when source folder is empty

While developing my metalsmith-watch plugin I noticed that a middelware is only run when there is at least one file in the source folder.

I think each plugin should decide what to do in a case of an empty files object.
In the case of my watch plugin it would be to start watching for changes.

Problem with {{contents}} in build.

When I put {{contents}} in my index.html template, it fetches the contents of my index.md, but instead of returning <p> tag he returns &lt;p&gt; I have not found anything similar on google, what would be the problem?

`contents` gets escaped by default

It seem like the content of contents is somehow escaped by default, i.e. given that I have this in a Markdown file:

Testing...

Metalsmith generates this:

&lt;p&gt;Testing...&lt;/p&gt;

Instead of this:

<p>Testing...</p>

I've tried a couple template engines, all of them yielding the same result.

I'm not entirely sure this is exclusive to Metalsmith, but it looks like the generated files in the examples folder have the same issue too.

generic pipeline branching/ source file filtering

Plugins basically do their own filtering of source files, sometimes it's hard-coded and sometimes in options, etc.

I was feeling the need for a more declarative way to say "run this list of middleware on these selected files", so I put together metalsmith-branch. It's not entirely tested yet but see what you think.

metalsmith.use( 
  branch('*.md')        // for only md source files,
    .use( templates({       // run through swig template engine
               engine: "swig",
               inPlace: true
          })
    )
    .use( markdown() )      // and generate html
)
.use(  /* plugin to be run on all files */ )

Deploy Plugins

I have been thinking about plugins for deploying the build directory. If using the JS API I could of course do the deploy during the build callback but I like the idea of being able to keep everything in plugins and just using a config file. What about adding a "build" or "built" event that plugins can attach to after completion? Or should deployment be kept separate from metalsmith?

Build fails when no posts > 245

I get the following error when the number of posts I'm using is greater than 245 in the jekyll example. Doesn't matter which posts, just if there's more than 245.

 (libuv) Failed to create kqueue (24)

I'm on Lion and have tested against node v0.10.5 and v0.10.26 with the same results. I've written the example in a node script which fails also. Apparently this has something to do with the number of concurrent filesync operations [https://github.com/componentjs/component/issues/296], but I'm unsure how I'd go about limiting this within a plugin. I guess this therefore maybe stem from an issue with the markdown plugin being unthrottled.

epub plugin / example

The Metalsmith website is quite explicit about the ability to use it for generating ebooks... only a plugin / example seems to be lacking. Am I missing something, or should it be simple enough to piece together such a setup without the need for a plugin?

Throw EMFILE errors

Hi all,

Thanks so much for the awesome project. Sooo flexible, sooo easy to get up and running.

When reading in large projects (~10mb+) it seems that blowing out the ulimit causes metalsmith to fail silently. While I know I really should be splitting up such an big project, it took a while to track down the cause of the issue.

Let me know if I can provide any more info.

Cheers,
Brad

Use a middleware only once

Hello,

In a classical workflow, every single plugin registered as a middleware is run once. But in a workflow using metalsmith-watch, each registered plugin is meant to be called several times.

The problem is: there is some metalsmith plugins (the ones not directly interacting with the files stream) which makes sense to only run once. Run them twice or more may be a waste of time. This could be the case with:

Therefore, I think it could be great to have the possibility to register a middleware which will only be called once. So the choice would be left to the developer judgment.

A code sample of how I see it:

var metalsmith = require('metalsmith');
var markdown = require('metalsmith-markdown');
var metadata = require('metalsmith-metadata');
var watch = require('metalsmith-watch');

metalsmith(__dirname)
  .once(metadata({ ... }));
  .use(markdown());
  .watch();
  .build();

What do you think?

Plugins order in metalsmith.json

Plugins section:

"plugins": {
    "metalsmith-drafts": true,
    "metalsmith-markdown": true,
    "metalsmith-permalinks": "posts/:title",
    "metalsmith-templates": "handlebars"
  }

according to ECMAScript specification: The mechanics and order of enumerating the properties ... is not specified.
Here must be an array.

Examples fail from CLI

Following install of the CLI (which I assume is "npm install -g metalsmith"?), I can't run any of the examples listed within /examples. Metalsmith fails with:

"Metalsmith · failed to require plugin "metalsmith-markdown"."

or similar. Installing dependencies using npm install, I receive the same error.

I'm running node v0.10.26.

Shepherding the ecosystem

I'm just wondering if it makes sense to guide the ecosystem in some way. Inspired by gulp.js or the community around component it would be nice to have something similar for metalsmith. I think of guidelines for plugin authors, like adding a special keyword (e.g. metalsmith-plugin) to the package.json or best practices for authoring in general. With the keyword in special it would be possible to create a search engine where people can find the respective plugin they need in a centralized way.

Let me know what you think. :)

Shasum check failed during installation

Very promising but I can't install it; this is the error I'm getting:

[metalsmith]$ sudo npm install metalsmith
npm http GET https://registry.npmjs.org/metalsmith
npm http 304 https://registry.npmjs.org/metalsmith
npm http GET https://registry.npmjs.org/metalsmith/-/metalsmith-0.2.0.tgz
npm http 200 https://registry.npmjs.org/metalsmith/-/metalsmith-0.2.0.tgz
npm ERR! Error: shasum check failed for /var/folders/qc/5btbq4w57jj0zjrr68gt49v80000gn/T/npm-6536-3FoPTotg/1394219464649-0.22078773751854897/tmp.tgz
npm ERR! Expected: ca795b5d076d3badf27e3fdaaef90431a83417a3
npm ERR! Actual:   56edbc1600c6d2ebd2ce7db9d0a68ef6153d6c06
npm ERR!     at /usr/local/lib/node_modules/npm/node_modules/sha/index.js:38:8
npm ERR!     at ReadStream.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/sha/index.js:85:7)
npm ERR!     at ReadStream.EventEmitter.emit (events.js:117:20)
npm ERR!     at _stream_readable.js:920:16
npm ERR!     at process._tickCallback (node.js:415:13)
npm ERR! If you need help, you may report this *entire* log,
npm ERR! including the npm and node versions, at:
npm ERR!     <http://github.com/isaacs/npm/issues>

npm ERR! System Darwin 13.0.0
npm ERR! command "node" "/usr/local/bin/npm" "install" "metalsmith"
npm ERR! cwd /my/path/metalsmith
npm ERR! node -v v0.10.24
npm ERR! npm -v 1.3.21
npm ERR! 
npm ERR! Additional logging details can be found in:
npm ERR!     /my/path/metalsmith/npm-debug.log
npm ERR! not ok code 0
[metalsmith]$ 

Got the same error by trying to install it both -- globally and locally.
I'm on OSX 10.9.1 with npm 1.3.21 and node 0.10.24.

Thanks!

Jade templates + Jade content not working

cannot seem to get this configured correctly...

is it possible to use jade's blocks and extends? i cannot seem to wire up the template to the source file when they are both .jade files

├── src
│   └── index.jade
└── templates
    └── layout.jade

"ENOTEMPTY, directory not empty" error

When executing Metalsmith on my Windows machine, I sometimes receive the following error:

Error: ENOTEMPTY, directory not empty 'C:\Projects\metalsmith\build\2013\05\21'
  at Object.fs.rmdirSync (fs.js:612:18)
  at rmkidsSync (C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rim
raf\rimraf.js:247:11)
  at rmdirSync (C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rimr
af\rimraf.js:237:7)
  at fixWinEPERMSync (C:\Projects\metalsmith\node_modules\metalsmith\node_module
s\rimraf\rimraf.js:150:5)
  at rimrafSync (C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rim
raf\rimraf.js:216:26)
  at C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rimraf\rimraf.j
s:245:5
  at Array.forEach (native)
  at rmkidsSync (C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rim
raf\rimraf.js:244:26)
  at rmdirSync (C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rimr
af\rimraf.js:237:7)
  at fixWinEPERMSync (C:\Projects\metalsmith\node_modules\metalsmith\node_module
s\rimraf\rimraf.js:150:5)
  at rimrafSync (C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rim
raf\rimraf.js:216:26)
  at C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rimraf\rimraf.j
s:245:5
  at Array.forEach (native)
  at rmkidsSync (C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rim
raf\rimraf.js:244:26)
  at rmdirSync (C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rimr
af\rimraf.js:237:7)
  at fixWinEPERMSync (C:\Projects\metalsmith\node_modules\metalsmith\node_module
s\rimraf\rimraf.js:150:5)
  at rimrafSync (C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rim
raf\rimraf.js:216:26)
  at C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rimraf\rimraf.j
s:245:5
  at Array.forEach (native)
  at rmkidsSync (C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rim
raf\rimraf.js:244:26)
  at rmdirSync (C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rimr
af\rimraf.js:237:7)
  at fixWinEPERMSync (C:\Projects\metalsmith\node_modules\metalsmith\node_module
s\rimraf\rimraf.js:150:5)
  at rimrafSync (C:\Projects\metalsmith\node_modules\metalsmith\node_modules\rim
raf\rimraf.js:216:26)
  at Metalsmith.write (C:\Projects\metalsmith\node_modules\metalsmith\lib\index.
js:214:14)
  at C:\Projects\metalsmith\node_modules\metalsmith\lib\index.js:141:12
  at next (C:\Projects\metalsmith\node_modules\metalsmith\node_modules\ware\lib\
index.js:60:42)
  at C:\Projects\metalsmith\node_modules\metalsmith-assets\index.js:50:9
  at done (C:\Projects\metalsmith\node_modules\metalsmith-assets\node_modules\as
ync\lib\async.js:128:19)
  at C:\Projects\metalsmith\node_modules\metalsmith-assets\node_modules\async\li
b\async.js:25:16
  at C:\Projects\metalsmith\node_modules\metalsmith-assets\index.js:66:11
  at fs.js:266:14
  at Object.oncomplete (fs.js:107:15)

If I run a second time or manually delete the build directory before execution, it works 100% of the time.

I believe it might have something to do with the way files are deleted in Windows, as I think I read that Node only marks files for deletion and doesn't actually delete them itself. This may be causing a long enough delay, before Windows actually performs the delete, that the directory removal step is being performed while the files still exist.

New "Empty the build directory before building" functionality breaks static-plugin

The build directory gets now deleted during the build procedure (see #19). Because the write part of the build procedure runs after the middleware loop (run) this breaks plugins like static that operate on the existing build directory: such plugins work but the directory gets thrown away after they're finished.

A possible solution could be to introduce a second middleware stack that runs after the write part.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.