Giter Club home page Giter Club logo

collections'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!

collections's People

Contributors

anthonyshort avatar axe312ger avatar bashaus avatar davidknezic avatar dpobel avatar emmercm avatar fidian avatar growdigital avatar ianstormtaylor avatar lambtron avatar leviwheatcroft avatar mikestopcontinues avatar patdavid avatar petasittek avatar rgladwell avatar spacedawwwg avatar webketje avatar woodyrew 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

collections's Issues

metalsmith-markdown and metalsmith-collections can interfere

I have a site with the following directory structure:

src
|-------films
|         |-------film1.md
|         |-------film2.md
|-------templates
          |-------film-template.html

And my metalsmith.json looks like this

{
  "source": "src",
  "destination": "build",
  "metadata": {
    "title": "A site",
    "description": ""
  },
  "plugins": {
    "metalsmith-markdown": {},
    "metalsmith-collections": {
      "films": {
        "pattern": "films/*.md",
        "sortBy": "title"
      }
    }
  }
}

When I run metalsmith, I get the following error message

/ASite/node_modules/metalsmith-collections/lib/index.js:51
      col.sort(function(a, b){
          ^
TypeError: Cannot call method 'sort' of undefined
    at /ASite/node_modules/metalsmith-collections/lib/index.js:51:11
    at Array.forEach (native)
    at /ASite/node_modules/metalsmith-collections/lib/index.js:46:10
    at Object.next [as _onImmediate] (/ASite/node_modules/metalsmith/node_modules/ware/lib/index.js:56:8)
    at processImmediate [as _immediateCallback] (timers.js:330:15)

It appears that because the metalsmith-markdown actually modifies the files array at https://github.com/segmentio/metalsmith-markdown/blob/master/lib/index.js#L43-L44 when the metalsmith-collections runs, it can't find any .md files.

Putting metalsmith-collections first and metalsmith-markdown second in metalsmith.json fixes the problem.

I am not sure if this is intentional or if it could be considered a bug. I am not sure what the solution should be. A suggestion would be to have files be an object with "transformed" and "original" path names, or possibly metalsmith-collections could be modified to always re-read the original files.

Newest version on npm

Hi, could you please bump the version number and publish the latest version to npm? Having the path property is very useful.

Thanks

Multiple builds break the plugin

The plugin isn't idempotent, running it twice will screw up the metadata.

app = metalsmith()
  .use(collections({ articles: { ... } })
  .build(done => ...)
  .build(done => ...)

The workaround is to create a middleware that clears up metadata:

app = metalsmith()
  .use((files, ms, done) => {
    ms.metadata({ articles: [] })
    done()
  })
  .use(collections({ articles: { ... } })
  .build(done => ...)
  .build(done => ...)

Can't get prev or next links

I have to md files:


---
title: English
collection: articles
layout: article.hbs

---

---
title: Hindi
collection: articles
layout: article.hbs

---

I'm matching using the collection metadata. How do I get the links for the pages??
Thanks!

No collection metadata: Matcher failing

My collection's metadata isn't being added to the global metadata. When using node-debug, I see that my files don't match the path when they should. The pattern will be "_site_src/content/projects/*.html" but the given path is "projects/something.html"

My collection files do not have a collection metadata in the yaml front matter.

Here is my setup:

metalsmith: {
    main: {
        options: {
            metadata: {
                title: "My Blog",
                description: "My second, super-cool blog."
            },
            plugins: {
                "metalsmith-collections": {
                    projects: {
                        pattern: "_site_src/content/projects/*.html"
                    }
                },
                "metalsmith-templates": {
                    engine: "handlebars",
                    directory: "_site_src/templates"
                },
                "metalsmith-permalinks": {
                    pattern: "projects/:title"
                }
            }
        },
        src: "_site_src/content",
        dest: "build"
    }
}

Or maybe I'm doing something wrong???

index example?

would be nice if readme included an example of generating index pages.

[TypeError: col.sort is not a function]

I keep getting this error when trying to run a build:

Path looks like: src/_projects/project.md

Build looks like:

.use(collections({
    projects: {
      pattern: "_projects/*.md"
    },
    posts: {
      pattern: "_posts/*.md"
    }
  }))

storyblok and metalsmithJs (how to create a collection of blog-posts)

Hello, I'm creating a blog-post with metalsmith where I'm getting all my data from storyblok headless CMS,
I need to create a collection of blog posts from storyblok in order iterate on it and render it using handlebars, and I can't find a proper solutions, aby help will be appreciated

Update changelog

All releases > 0.7.0 aren't documented. Also version 0.8.0 seems to be removed or at least missing, 0.9.0 seems to exist twice and 0.9.9 exist without previous patch levels:

2016-11-02_222211

What the hank is going on here @lambtron?

Why is the property added collection and not collections?

This gets me every time I have to grab a collection from a file.
The property that is added to the file is: collection, yet its value is an array of collections

I get this would break everyone's code (unless we add both keys while people migrate), but it really makes zero sense.

Unless I am missing something :)

Collection hierarchy

I have a modified version of this repo where a collection can have a parent and children. I can do a PR here or should I just publish it as a "new" plugin?

Note: It doesn't break existing behaviour.

Thanks, Woody

Collections with markdown, permalinks and include

So, rad tool by the way, the flexibility is impressive, and I'm looking forward to seeing the ecosystem of plugins expand.

I'm trying to use markdown, permalinks, and include in the following order

.use( drafts() )
      .use( metaobj({
        "site" : {
          "title": "Site Name",
         "description": "Tagline"
        },
        "styles": [
          "/css/main.css"
        ],
        "nav": [
          { "name": "…", "href": "…", "title": "…" },
        ]
      }))
      .use( minclude() )
      .use( collections({
        careers: {
          sortBy: 'date',
          reverse: true
        }
      }))
      .use( markdown() )
      .use( permalinks({
        pattern: ':title'
      }))
      .use( templates({
        engine: "swig",
        directory: "templates"
      }))
      .use(beautify({
        "html": true,
        "js": false,
        "css": false
      }))

then i set up a few .md files with the following frontmatter (with different titles of course):


---
template: careerlisting.html
title: UX Engineer
collection: careers
date: 2014-10-8

---

however when i try and print out the variable in my templates and build...
the include partials function as expected
the permalinks structure works

but the collections dont echo.... the metadata seems to exist, but seems to be empty (im using swig templates)

Here's the template chunk

  {% for career in collections.careers %}
  {{career}}
  {% endfor %}

Choose metalsmith collection from .md file

I've been using Metalsmith static site generator for some time and I believe is a great tool. Now I started using metalsmith-collections plugin but I stumbled across this issue.

Given the case that I have two collections defined, for instance "en_news" and "sp_news" and the following news.hbt file:

<h1>{{title}}</h1>
{{contents}}

<ul>
    {{#each collections.en_news}}
        <li>
            <h3>{{this.title}}</h3>
            <article>{{this.contents}}</article>
        </li>
    {{/each}}
</ul>

Now in the .md file I want the collection to be either collection.en_news:

---
title: News
template: news.hbt
lang-collection: en_news

---
News in english language

...or collection.sp_news:

---
title: Noticias
template: news.hbt
lang-collection: sp_news

---
News in spanish language

How can I use "lang-collection" inside test.hbt to define the used collection?

Of course the following does not work:

{{#each collections.{{lang-collection}}}}

Thanks in advance!

Specify layout in collection

Hi,
Is there a way to specify default frontmatter; in this case layout, in an item matched by the glob specified in a collection if not specified already in the file?

allow grouping by pattern

for example if there is an /articles folder, that way people don't have to add a collection metadata property to every file

Calling collections property in template returns '0'

I'm currently trying to put together an index page but I can't seem to call the collection in one of my files without it returning '0' or undefined. Any ideas?

My current file structure:

src
  |-- posts
     |-- index.html
     |-- category1
          |-- post.md
     |-- category2
     |-- category3
layouts
  |-- post.html

This is what I'm calling in posts/index.html

{% for cat in collections.category1 %}
   <li>{{ cat.title }}</li>
{% endfor %}

This is my index.coffee

metalsmith __dirname
      .use define
        config:
          environment: 'develop'
      .use collections
        'category1':
          pattern: 'posts/category1/*.md'
        'category2':
          pattern: 'posts/category2/*.md'
        'category3':
          pattern: 'posts/category3/*.md'
      .use markdown
      .use permalinks
        pattern: 'posts/:collection/:url'
        relative: false
      .use layouts
        engine: 'swig'
        partials: 'partials'
        pattern: '**/*.html'
      .use inPlace 
        engine: 'swig'
        partials: 'partials'
      .use sass
        outputStyle: 'compressed'
      .use autoprefixer()
      .use htmlMinify
        removeAttributeQuotes: false
      .use uglify()
      .build (error) ->
        if error
          console.log error

I'm still pretty new at this and I've tried to dig through similar issues but none of the solutions worked for me. Any help would be appreciated!

Documentation incomplete

The documentation describes how to describe and ingest collections, but there is no explanation as to how the collections can be used in other files (such as in an index.jade).

Open to other maintainers?

Hello.
Any chance someone could be brought aboard to help maintain this plugin?
It's used by nearly everyone who uses Metalsmith.

Or at least some clarity that this is the final version and we should fork if we want to add features or help out with potential issues.

Thanks - love Metalsmith and hope it doesn't go away.

fails with empty collections

This stops happening as soon as the collection is non-empty:

/Users/hunter/code/playfuljs/node_modules/metalsmith-collections/lib/index.js:56
        col.sort(function(a, b){
            ^
TypeError: Cannot call method 'sort' of undefined
    at /Users/hunter/code/playfuljs/node_modules/metalsmith-collections/lib/index.js:56:13
    at Array.forEach (native)
    at /Users/hunter/code/playfuljs/node_modules/metalsmith-collections/lib/index.js:47:10
    at Object.next [as _onImmediate] (/Users/hunter/code/playfuljs/node_modules/metalsmith/node_modules/ware/lib/index.js:68:8)
    at processImmediate [as _immediateCallback] (timers.js:330:15)

Absence of metadata in output in non-empty collections

Adding metadata to a collection works fine, but as soon as that collection has any items in it, all the metadata goes away.

Scenario 1 - Empty collection with Metadata:
Config:

"posts": {
          "sortBy": "date",
          "reverse": false,
          "metadata": {
            "name": "Posts",
            "path": "posts/index.html"
          }
}

Metadata:

posts: {
    name: "Posts",
    path: "posts/index.html
}

Scenario 2 - Using pattern with metadata:
Config:

"posts": {
          "pattern": "posts/**.md",
          "sortBy": "date",
          "reverse": false,
          "metadata": {
            "name": "Posts",
            "path": "posts/index.html"
          }
}

Metadata:
Posts data without a metadata tag.

This is also an issue when using post metadata to define collections.

images in collection

How would I add image paths to collection? I want to display thumbnail of the article.

Repeat runs with collections adds duplicates

Currently, repeated calls to metalsmith.build() is non-idempotent because metalsmith-collections will find the same files that belongs to a collection, and add them to the same array as exists in memory from the previous run.

This is due to metalsmith storing collections in the global metadata object. Maybe it should empty out the collections arrays every time it runs?

My workaround right now is essentially

metalsmith.build(function(err, files) {
  if (err) throw err;
  metalsmith.metadata(origMetadata);
});

data.path would be more useful with an html extension than a markdown one

I was using this plugin and noticed that path gave me the original file name. Depending on the order in which I place the plugin, this can be inconvenient. I noticed it would be an easy fix!

I would imagine that you want all paths to be HTML anyways, so it can probably be done without any additional options. The gist of it is that you include the function below and have data.path = replaceExtension(file).

Just a thought. If it seems like something worth implementing, here is a script that does this...

function replaceExtension(name) {
    var splitNameName = name.split('.');

    splitNameName.pop();
    splitNameName.push('html');

    return splitNameName.join('.');
}

Ability to specify Multiple Collections

I'd like to hear your (@ianstormtaylor) .. or anyones, thoughts on the ability for a single document to be included in multiple collections. Most obviously via something like:


---
collection: foo bar

---

and

---
collection:
- foo
- bar

---

I'm likely going to submit a PR in the near future for this ability, but since it's a very core aspect to the design of this plugin, i figure it's worth discussing before i need the feature and end up submitting a PR heh.

using both pattern: and metadata at the same time?

I seem to be having a simple problem. If I use only a pattern to describe a collection, it works fine:

article: {
pattern: 'articles/*/index.html'
...}

If I simple use the metadata, it works fine as well,

article: {
sortBy: 'date',
reverse: true}

If I try to use the pattern, when there is a metadata key in the front-matter, I get errors...

Can we not use both a pattern and metadata at the same time, or is it an either/or proposition?

Collection opts aren't loaded - therefore no collections

Hi - I'm trying to build up a collection of recent blog posts for a right nav section. I have the following configuration of the collections plugin.

  .use(collections({
    blogposts: '**/*.md'
  }))

Unfortunately, whenever I run this, I was never seeing any data in my collection (there should have been 25 items in the array, but the array was always empty). In digging into the source, the spot that seems to be breaking me is at https://github.com/segmentio/metalsmith-collections/blob/master/lib/index.js#L25. I'm not exactly sure why, but Object.keys always returns an empty array. Further, Object.getOwnPropertyNames also returns an empty array.

I'm running Node 6.0.0 - not sure whether something changed wrt the JavaScript interpreter or if I'm just doing something incredibly dumb, but I'm a little stumped at the moment.

thoughts?

Allow collections through metadata alone

I would like to use collections like this:

metalsmith.use(collections())

Where each file may contain a collection defined in the frontmatter:

---
collection: some_collection

---

Thoughts?

"pattern:" does not work in CLI

Somehow i can only add files to my collection by setting the metadata collection in the file.
I can not select any files with the pattern attribute like following:

"metalsmith-collections": {
    "articles": {
        "pattern": "*.md"
    }
}

or

"metalsmith-collections": {
    "articles": "*.md"
}

This will only give me an empty collection in the template

Path not being set properly when using metalsmith-in-place

I am using both metalsmith-collections and metalsmith-in-place. I am using markdown and Nunjucks so my files are in the format of filename.md.njk, I also have noticed that the path for the filenames when collections is run is being set using the *.md.njk format.

I have created my own articles plugin that modifies the navigation for my articles based on the file structure and also the path. The issue I am having is that it appears I have to run metalsmith-in-place before metalsmith-collections in order to get the path to be correct so something like articles/first-series/first-page.md.njk rather than articles/first-series/first-page.html.

It would be fine to run metalsmith-in-place before metalsmith-collections however when I do that then I do not get the path, next or previous links for my posts collection. See the attached screenshot for more information.

Here is my build file as it currently sits.

/*jslint es6 */

/*
 * Metalsmith build file
 * Build site with `node build`
 */

'use strict';

const inplace = require('metalsmith-in-place');
const layouts = require('metalsmith-layouts');
const metalsmith = require('metalsmith');
const collections = require('metalsmith-collections');
const serve = require('metalsmith-serve');
const watch = require('metalsmith-watch');
const assets = require('metalsmith-assets');
const drafts = require('metalsmith-drafts');
const excerpts = require('metalsmith-excerpts');
const paginate = require('metalsmith-pager');
const archive = require('metalsmith-collections-archive');
const debug = require('metalsmith-debug-ui');


/* Local Plugins */
const utils = require('./lib/utils');
const articles = require('./lib/articles');
const permalinks = require('./lib/my-permalinks');

const templateConfig = {
    engineOptions: {
        highlight: utils.highlight,
        filters: {
            toUpper: utils.toUpper,
            spaceToDash: utils.spaceToDash
        }
    }
};

let ms = metalsmith(__dirname);

debug.patch(ms);

ms.metadata({
      site: {
        name: 'A Developers Blog',
        author: 'Joseph Crawford',
        description: 'A Developers Blog'
      }
    })
    .clean(true)
    .source('./src/')
    .destination('./build/')
    .use(collections({
      posts: {
        pattern: 'posts/**/*.njk',
        sortBy: 'date',
        reverse: true
      },
      articles: {
        pattern: ['articles/*.njk', 'articles/**/*.njk'],
        refer: false
      },
      reviews: {
        pattern: ['reviews/*.njk', 'reviews/**/*.njk'],
        sortBy: 'date',
        reverse: true
      }
    }))
    .use(archive({
      layout: 'archive.njk',
      rootLevel: false,
      collections: {
        'posts': true
      }
    }))
    .use(articles({
      collection: 'articles'
    }))
    .use(drafts())
    .use(excerpts())
    .use(paginate({
      collection: 'posts',
      elementsPerPage: 1,
      pagePattern: 'page/:PAGE/index.html',
      index: 'post.njk',
      paginationTemplatePath: '../layouts/partials/paginator.njk',
      layoutName: 'post.njk'
    }))
    .use(inplace(templateConfig))
    .use(layouts(templateConfig))
    .use(permalinks({
      relative: false,
      pattern: ":title",
      // each linkset defines a match, and any other desired option
      linksets: [{
        match: { collection: 'posts' },
        pattern: 'post/:date/:title',
      },{
        match: { collection: 'articles' },
        pattern: 'articles/:series.name/:title'
      },{
        match: { collection: 'reviews' },
        pattern: 'reviews/:date/:title'
      }]
    }))
    .use(assets({
      source: __dirname + '/assets/',
      destination: '.'
    }))
    .use(serve({
      port: 8080,
      verbose: true
    }))
    .use(watch({
      paths: {
        "${source}/**/*": true,
        "lib/**/*": "**/*",
        "layouts/**/*": "**/*"
      }
    }))
    .build(function (err) {
        if (err) {
          console.log(err);
            throw err;
        }
        console.log('Build finished!');
    });

COLLECTIONS RUNNING FIRST
screen shot 2018-12-13 at 4 21 06 pm



IN-PLACE RUNNING FIRST
screen shot 2018-12-13 at 4 21 37 pm



MY BUILD DIRECTORY
screen shot 2018-12-13 at 4 24 23 pm

Inconstant contents

Hey—unsure if this is a problem related to Metalsmith or this plugin. When I build the site the value of contents for each article sometimes changes.

For example, here's the value of contents of article one:
<p>A really short, rushed-feeling string of words.</p>

However, when I edit article two by adding a couple line breaks, the contents of article one becomes:

<html> <head> <title>My Blog</title> </head> <body> <h1>My Fourth Post</h1> <time>Thu Dec 06 2012 16:00:00 GMT-0800 (PST)</time> <p>A really short, rushed-feeling string of words.</p> </body> </html>

Any ideas?

Self closing tags stripped out / removed?

I'm using metalsmith to render some SVG markup, which contain a lot of self closing tags:

For example:

 <circle cx="33" cy="19" r="2"/>

When printing these out at the layout level with metalsmith there is no problem, everything is preserved.

However when I'm looping through a collection:

index.html

        {{#each collections.components }}
{{>component}}
        {{/each}}

component.html

    <div class="demo-rendered cf">
        {{{ this.contents }}}
    </div>

output

    <div class="demo-rendered cf">
         <circle cx="33" cy="19" r="2">
    </div>

All the self-closing tags are stripped out, which means the browser assumes these tags need nesting and everything goes downhill pretty quickly.

The fact these are only removed when returning from the collection implies the issue is with this plugin. Is this something anyone else has run into?

(note this also applies to more basic self closing tags: <br/>, <input type="text />

Order of plugins?

Hello!
I have a simple config:

{
  "source": "./content",
  "destination": "./_site",
  "metadata": {
    "title": "title",
    "description": "desc"
  },
  "plugins": {
    "metalsmith-drafts": {},
    "metalsmith-markdown": {},
    "metalsmith-permalinks": {
      "pattern": ":title"
    },
    "metalsmith-templates": {
      "engine": "swig",
      "directory": "templates"
    },
    "metalsmith-collections": {
      "genre": {}
    }
  }
}

If I try to build it $ metalsmith, I can’t get collections variable from within templates.
Maybe there should be some docs on basic usage of collections in templates?

How to use collections with ignore?

I am having a one-page that should include some collections. But, I don't want to generate those include files. So I am using .ignore("mypath") like described in the docs. However, when using ignore after or before using collections, those include files will be deleted from the stack of the collection. So, how can I use ignore but still get even ignored files into the stack of collections?

I am aware that this repository is not actively maintained, so in the meantime I will either don't use this plugin or delete the ignore files after using metalsmith.

Add Travis

Tests are there. Would be nice to have Travis test it for us.

Path not being populated

Not sure if this is related to the partial build bug, or CLI. But I'm building via the CLI interface and no posts in collection are receiving paths:

{
  "source": "./views/blog-src",
  "destination": "./views/blog-pub",
  "plugins": {
    "metalsmith-collections": {
      "posts": {
        "pattern": "./views/blog-src/posts/*.html",
        "sortBy": "date",
        "reverse": "true"
      },
      "latestPosts": {
        "pattern": "./views/blog-src/posts/*.html",
        "sortBy": "date",
        "reverse": "true",
        "limit": "10"
      }
    },
    "metalsmith-permalinks": {
      "pattern": ":date/:title"
    },
    "metalsmith-markdown": true,
    "metalsmith-layouts": {
      "engine": "ejs",
      "default": "post.ejs",
      "directory": "views",
      "version": "lkebgw46346lbj",
      "user": false,
      "static": true,
      "userID": false
    }
  }
}

This is what I get:

{ title: 'test post',
  date: Thu Jan 01 2015 01:00:00 GMT+0100 (CET),
  publishDate: Thu Jan 01 2015 01:00:00 GMT+0100 (CET),
  modifyDate: Thu Jan 01 2015 01:00:00 GMT+0100 (CET),
  author: 'Jesper Bylund',
  collection: [ 'posts' ],
  contents: '<p>This is just a test of the watch thing!</p>\n',
  mode: '0644',
  stats: 
   { dev: 16777220,
     mode: 33188,
     nlink: 1,
     uid: 501,
     gid: 20,
     rdev: 0,
     blksize: 4096,
     ino: 30144996,
     size: 169,
     blocks: 8,
     atime: Sun Jul 03 2016 15:35:52 GMT+0200 (CEST),
     mtime: Sun Jul 03 2016 15:28:18 GMT+0200 (CEST),
     ctime: Sun Jul 03 2016 15:28:18 GMT+0200 (CEST),
     birthtime: Sun Jul 03 2016 11:26:01 GMT+0200 (CEST) } }

metalsmith-collections hangs

With this setup my make serve build hangs as soon as I include metalsmith-collections. Removing metalsmith-collections fixes this. However, as far as I can tell I'm not doing anything out of the ordinary.

Looks like it's running into an infinite loop of sorts. Any idea what's causing this?

Collection from JSON?

I have a list page that I would like to template from a block of JSON, rather than from a set of markdown files. (I could create a file for each list item, but that seems excessive because they are just a few properties each, with no body, and I only need a list page, not pages for each of them individually).

The config could be something like this:

 Metalsmith(__dirname)
    .use(collections({
      talks: {
        json: 'content/talks.json'
      },

Might you be interested in adding this feature to metalsmith-collections? I'd be happy to try adding it in a fork and submitting a PR if so.

TypeError: Cannot call method 'sort' of undefined

Ran across this bug(?) today, so I'm reporting it:

$ make build
node_modules/.bin/metalsmith

/home/eduan/dev/eduantech-metalsmith/node_modules/metalsmith-collections/lib/index.js:51
      col.sort(function(a, b){
          ^
TypeError: Cannot call method 'sort' of undefined
    at /home/eduan/dev/eduantech-metalsmith/node_modules/metalsmith-collections/lib/index.js:51:11
    at Array.forEach (native)
    at /home/eduan/dev/eduantech-metalsmith/node_modules/metalsmith-collections/lib/index.js:46:10
    at Object.next [as _onImmediate] (/home/eduan/dev/eduantech-metalsmith/node_modules/metalsmith/node_modules/ware/lib/index.js:56:8)
    at processImmediate [as _immediateCallback] (timers.js:330:15)
Makefile:3: recipe for target 'build' failed
make: *** [build] Error 8

And here's my metalsmith.json file in case it's relevant:

{
  "source": "src",
  "destination": "build",
  "metadata": {
    "title": "EduanTech"
  },
  "plugins": {
    "metalsmith-drafts": true,
    "metalsmith-markdown": {
      "smartypants": false,
      "gfm": true,
      "tables": true
    },
    "metalsmith-collections": {
      "menu": {
        "pattern": "*.(md|toffee)"
      }
    },
    "metalsmith-templates": "toffee"
  }
}

I am using version 0.1.0. Help appreciated. :)

Do not output collection files

Hi,
in jekyll there is an option to ignore the output of collections. That means e.g. the collection can be used in template code, but the file is not written to the output directory.

See http://jekyllrb.com/docs/collections/:

collections:
    my_collection:
      output: false

Can this be achieved with metalsmith-collections?

Contents of collection is html encoded

I have pulled in a collection of html files using this plugin. The collection is named posts. I then have a template that uses the collection

{{#each posts}}
  {{contents}}
{{/each}}

This does print out the contents but the html is html encoded. '<' is '<' for instance. What am I doing wrong?

My metalsmith.json is simple

{
  "metadata": {
    "site": {
      "title": "Tomaw Tech"    
    }
  },
  "plugins": {
    "metalsmith-collections": {
      "posts": "posts/*"
    },
    "metalsmith-page-titles":{},
    "metalsmith-in-place": {
      "engine": "handlebars"
    },
    "metalsmith-layouts": {
      "engine": "handlebars",
      "default": "layout.html"
    },
    "metalsmith-broken-link-checker": true
  }
}

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.