GithubHelp home page GithubHelp logo

metalsmith / in-place Goto Github PK

View Code? Open in Web Editor NEW
57.0 57.0 27.0 2.74 MB

A metalsmith plugin for in-place templating

License: MIT License

JavaScript 100.00%
metalsmith metalsmith-plugin node templating

in-place'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!

in-place's People

Contributors

blakeembrey avatar doodzik avatar greenkeeper[bot] avatar ianstormtaylor avatar ismay avatar jimniels avatar leviwheatcroft avatar mpalpha avatar nategreen 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

Watchers

 avatar  avatar  avatar

in-place's Issues

Use with handlebars-layouts

Hi,
I'm attempting to use this plugin to extend blocks provided by handlebars-layouts, but it doesn't appear to be working correctly; as all I ever get is [object Object] (other Handlebars logic does work however). Here is my Metalsmith setup:

Metalsmith(__dirname)
.source('src')
.use(ms_collections({
  pages: {
    pattern: 'pages/**/*.md'
  },
  articles: {
    pattern: 'articles/*.md',
    sortBy: 'date',
    reverse: true
  }
}))
.use(ms_filemetadata([
  {
    pattern: 'articles/*.md',
    metadata: {
      'layout': 'post.html'
    }
  }
]))
.use(ms_helpers({
  directory: '_helpers',
  pattern: /\.js$/
}))
.use(ms_inPlace({
  'engine': 'handlebars',
  'partials': '_partials',
  'pattern': 'pages/**/*.md'
}))
.use(ms_markdown())
.use(ms_moveUp('pages/**/*'))
.use(ms_permalinks({
  linksets: [{
    match: { collection: 'articles' },
    pattern: 'articles/:title',
  }]
}))
.use(ms_layouts({
  engine: 'handlebars',
  default: 'default.html',
  directory: '_layouts',
  partials: '_partials',
  helpers: handlebarsHelpers
}))
// .use(function(files, metalsmith, done) {
//   console.log('Files: ');
//   console.log(files);
//   console.log();
//   console.log('Metalsmith: ');
//   console.log(metalsmith);
// })
//.use(ms_html_minifier())
.destination('build')
.build(function(err) {
  if (err) throw err;
});```

I'm looking to use the helpers provided by that library to extend blocks setup by my Handlebars templates. If you have any other suggestions I'd really appreciate it. Thanks!

renaming files

When doing this:

    .use(require('metalsmith-in-place')({
      engine: 'jade',
      pattern: '*.jade'
    }))

index.jade does not get converted into index.html. Perhaps it should be made configurable for this to happen.

Template engine includes regression from metalsmith-templates

I understand, and support the splitting of metalsmith-in-place and layouts from metalsmith-templates, but one bit of functionality that was very useful to me, is not possible with in metalsmith-in-place that does in fact work in metalsmith-templates when the inPlace key is set to true, file includes.

swig example

/*!
Component Name

Component description

Markup:
{% include "components/molecules/cta/cta.html" %}
*/

.cta-wrapper {
  @extend .clearfix;
  clear: both;
  background: #dedede;
  .cta {
    text-align: center;
  }
}

results in:

> metalsmith -c kstatic_preprocess_scss.json
  Metalsmith · ENOENT, no such file or directory '/components/molecules/cta/cta.html'

stranger yet changing the path with ../ has no effect on the error so using {% include "components/molecules/cta/cta.html" %} results in no modification to the path in the error.

Which is to say both
{% include "components/molecules/cta/cta.html" %}
and
{% include "../../../components/molecules/cta/cta.html" %}
result in…
Metalsmith · ENOENT, no such file or directory '/components/molecules/cta/cta.html'

The same example works perfectly with metalsmith-templates when the inPlace option is on.

How do I pass the files object to a helper?

Using handlebars. I have a template with a call to a helper

{{postlist}}

I have a simple helper there. What I want to do is to create a list of posts which match a certain criteria (the details are unimportant)

helpers.postlist = (param, options) => {
  return "-----POSTLIST-----";
}

But no reference to the current files or metalsmith object is passed on to the helper. How do I go about passing that file list into the helper? It sounds silly having to re-read the directory from within the helper, as I have already all the information I need in the files object.

Thanks.

Update readme

To clarify the difference with the original metalsmith-templates.

npm installation broken?

$ npm install --save metalsmith-in-place
[email protected] node_modules/metalsmith-in-place
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected] ([email protected], [email protected])
└── [email protected] ([email protected], [email protected], [email protected], [email protected])
$ metalsmith

  Metalsmith · failed to require plugin "metalsmith-in-place".

$

going into the node_modules/metalsmith-in-place/ directory and doing npm install manually, fixes this issue.

The tests also fail until I do a manual install inside the module directory.

Plugin doesn't work on Windows

metalsmith-in-place plugin doesn't work in Windows. Below is the error I get. The same application builds fine on Mac.

I am using metalsmith-in-place and metalsmith-layouts plugins. Below is the code snippet from my build file:

.use(discoverHelpers({
        directory: paths.src + '/helpers',
        pattern: /\.js$/
      }))  
      .use(inPlace({
        engine: "handlebars",
        partials: paths.src + "/partials",
        pattern: "**/*.hbs",
        rename: true
      }))
      .use(layouts({
        engine: "handlebars",
        default: "index.hbs",
        directory: paths.src + "/layouts/",
        pattern: "**/*.html"
      }))
      .on('error', console.log.bind(console)) 

If I remove the inPlace (metalsmith-in-place), the error goes off even on windows. But, obviously the application doesn't work as the helpers are not compiled any more.

Error:

events.js:141
      throw er; // Unhandled 'error' event
      ^
 Error: The partial menu/nav could not be found
    at Object.invokePartial (Z:\sample\node_modules\handlebars\dist\cjs\handlebars\runtime.js:266:11)
    at Object.invokePartialWrapper [as invokePartial] (Z:\sample\node_modules\handlebars\dist\cjs\handlebars\ru
    at Object.eval (eval at createFunctionContext (Z:\sample\node_modules\handlebars\dist\cjs\handlebars\compil
    at main (Z:\sample\node_modules\handlebars\dist\cjs\handlebars\runtime.js:173:32)
    at ret (Z:\sample\node_modules\handlebars\dist\cjs\handlebars\runtime.js:176:12)
    at ret (Z:\sample\node_modules\handlebars\dist\cjs\handlebars\compiler\compiler.js:525:21)
    at Z:\sample\node_modules\consolidate\lib\consolidate.js:734:16
    at Z:\sample\node_modules\consolidate\lib\consolidate.js:143:5
    at Promise._execute (Z:\sample\node_modules\bluebird\js\release\debuggability.js:272:9)
    at Promise._resolveFromExecutor (Z:\sample\node_modules\bluebird\js\release\promise.js:473:18)
    at new Promise (Z:\sample\node_modules\bluebird\js\release\promise.js:77:14)
    at promisify (Z:\sample\node_modules\consolidate\lib\consolidate.js:136:10)
    at exports.handlebars.render (Z:\sample\node_modules\consolidate\lib\consolidate.js:724:10)
    at convert (Z:\sample\node_modules\metalsmith-in-place\lib\index.js:123:7)
    at Z:\sample\node_modules\metalsmith-in-place\node_modules\async\lib\async.js:181:20
    at Object.async.forEachOf.async.eachOf (Z:\sample\node_modules\metalsmith-in-place\node_modules\async\lib\a

npm ERR! Windows_NT 6.1.7601
npm ERR! argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Users\\...\\npm\\node_modules\\npm\\bin\\
npm ERR! node v4.4.3
npm ERR! npm  v3.3.12
npm ERR! code ELIFECYCLE
npm ERR! [email protected] gulp: `gulp "build"`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] gulp script 'gulp "build"'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the sample package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     gulp "build"
npm ERR! You can get their info via:
npm ERR!     npm owner ls sample
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     Z:\sample\npm-debug.log

Decouple file extension and template engine/transformer

Hey! Thanks for this plugin.

One issue I have is the tight coupling between a file extension (ex. .html.hbs) and its corresponding transformer (ex. jstransformer-handlebars). I'm using the metalsmith-permalinks plugin, and it's not building proper permalinks from templates if they're not a .html file (source).

So. I can't use .html for my templates since this plugin won't transform them with Handlebars, and I can't use .html.hbs in order to get pretty permalinks.

I've tried putting the .use(permalinks()) call both before and after my inPlace() call. I noted that inPlace is behaving differently from metalsmith-markdown, for instance. The Markdown plugin will process an .md file to HTML and pass it to permalinks, but inPlace doesn't seem to process .html.hbs files to HTML at once and pass to permalinks:

src/
   lol.md
// ...
.use(markdown())
.use(permalinks());

Turns into

build/
   lol/
      index.html

since permalinks already got a lol.html to play with (I debugged the output).

It would be super cool if we could override a certain extension to be transformed with a certain transformer:

.use(inPlace({
  transformer: 'jstransformer-handlebars'
}))

I realise this is trickling down in to the other repo (https://github.com/superwolff/metalsmith-engine-jstransformer/blob/master/lib/render-file.js#L36), but the option needs to live up here I guess.

Working with partials

I've encountered a strange bug where partials aren't recognized.

build.js

ms.use(markdown());
ms.use(inplace({
  engine: 'handlebars',
  partials: 'src/partials/'
}));

some-page.md


---
title: Some Page

---

{{> panels }}

When executing the build script, I get the error:

Fatal error: Parse error on line 3:
... <p>{{&gt; panels }}</p>
---------^
Expecting 'ID', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', got 'INVALID'

Thoughts?

Plugin assumptions

This plugin assumes that a src directory will contain templates that one wouldn't otherwise put in layouts for rendering specifically as in-place templates in that src directory. It's somewhat strange to me because I put all my layouts/in-place templates in my src directory and render the adjacent directories that contain markdown and content. Considering that src is typically used in contrast to dist, would it be reasonable to say that all files that should be processed would be in src including layouts and in-place templates? This would mean that layouts and in-place are effectively part of the same processing that happens on other src files. I realize that there used to be a metalsmith-templates that took care of both of these. I honestly think that makes more sense because splitting layouts outside of src seems to be somewhat confusing.

I think something like this would make a ton of sense:

- src/
  - templates/
    - layouts/ -> layouts that use includes
    - includes/ -> includes that go in layouts
    - template.liquid -> arbitrary template that's rendered from using it's name

This way you know where everything is, and it's actually handling one responsibility, rendering templates.

Metadata could be:

layout: layout-name
or 
template: template

Nunjucks' include and import don't work

When using Nunjucks' include and import the following error shows up:
Error: template names must be a string: undefined

include and import work fine in metalsmith-layouts, so I think it's related to metalsmith-in-place.

On Stack Overflow I cross-posted a more detailed explanation of what I'm trying to achieve, in case this was not a bug in metalsmith-in-place.

Phase out language specific tests

After #58. As this lib will then no longer have to concern itself with template engine specific logic (just an api that you can bolt different rendering functions on).

Extra <p></p> blocks around in-place markup

This may be user error.

I'm trying to set up a multi-column Bootstrap layout in Metalsmith with Handlebars. I have a page design that has

left-col        right-col
   bottom-wide-section

where left-col, right-col, and bottom-wide-section are all user-provided content (markdown).

  • Bootstrap requires me to wrap parts of my {{{content}}} block in row and column divs.
  • Handlebars returns content as a monolithic block and doesn't have provisions for splitting it (as best I can tell).
  • Metalsmith can't combine multiple .md files into a multi-part content block (as best I can tell), and even if it could, I doubt Handlebars could address it properly.

So, to get around these limitations, I was trying to use in-place to define rows and columns as follows (reduced test case, only defines row).

test.md


---
layout: standardPage.hbs
title: "TestPage"

---
{{{inplace.beginRow}}}

This is some test content.

Will there be a blank paragraph block above?

{{{inplace.endRow}}}

When my pipeline is markdown -> in-place -> layouts, I get the following output.

<div class="body-text" role="main">
    <p>
        <div class="row">
    </p>
    <p>This is some test content.</p>
    <p>Will there be a blank paragraph block above?</p>
    <p>
        </div>
    </p>

</div>

Note the <p> blocks enclosing the <div> and </div>. The browser automatically "fixes" the HTML.
Browser "Fixed" HTML

<div role="main" class="body-text">
    <p>
        </p><div class="row">
    <p></p>

    <p>This is some test content.</p>
    <p>Will there be a blank paragraph block above?</p>
    <p>
        </p></div>
    <p></p>

</div>

This creates layout problems by injecting extra paragraph margins and padding in the layout.

Any pipeline that runs markdown first will have the extra <p> blocks because markdown wraps the in-place values in <p> blocks as shown by the markdown -> layouts (no in-place) pipeline below.

<div class="body-text" role="main">
    <p>{{{inplace.beginRow}}}</p>
    <p>This is some test content.</p>
    <p>Will there be a blank paragraph block above?</p>
    <p>{{{inplace.endRow}}}</p>

</div>

Running markdown after in-place prevents markdown from rendering content wrapped in divs and other block elements.

Is this expected behavior?

If so, how would one go about assembling a page that requires content to be broken into several pieces on the page? Or how would one inject HTML markup into the content block? (Coding it directly will cause markdown to skip wrapped content, and I'd rather not ask users to write HTML--that's the whole point of markdown.)

Or should in-place (optionally?) remove and immediately adjacent <p></p> wrapper?

metadata in partials

Does the plugin handle metadata in partials?
e.g.

In my template file
template/index.html


---
template: main.html

---

I have a partial file
template/partials/main.html


---
title: Test Title

---
{{> section}}
<p>Test partial</p>

and in another partial
template/partials/section.html

<header><h1>{{header}}</header>
<p>{{{content}}</p>

I was expecting the result to be
build/index.html

<header><h1>Test Title</h1></header>
<p>Test partial</p>

however I do not get that expected result. The meta data is just printed out unformatted. Does in-place handle markdowns in partials?

my .json for metalsmith

"metalsmith-layouts": {
      "engine": "handlebars",
      "default": "index.html",
      "directory": "template",
      "partials":"template/partials",
      "pattern":"*.html"
    },
    "metalsmith-in-place":
    {
      "engine":"handlebars",
      "partials":"template/partials",
      "pattern": "*.html"
    },

ECT partials

No matter what I try to do I can't seem to get this resolved so any help would be appreciated!

After trying pretty much everything I could think of to get partials working using ECT I decided to replicate the test fixture for partials provided on this repo. I kept the metalsmith js file as simple as possible, only including a use call to metalsmith-in-place (with the engine and partials properties set) and then building.

At first I tried passing a simple object to the partials property and then including that via <% include "footer" %> (without the file extension) but that resulted in the error:
'[Error: Failed to load template footer in page on line 2]'
and the error:
'[TypeError: Cannot read property 'ect' of undefined in page on line 2]' with the file extension

Next I went with the folder option and simply passed the name of it to the partials property while doing the exact same thing in my template file but alas, the same error reared its ugly head.

The only thing that I have found that DOES work is directly outputting the content of the partials object (eg. <%- @partials.footer %>) but this approach destroys the way I would normally do my templating.

Any help or insight would be greatly appreciated!

Check performance

  • How does it compare to the old 1.x.x version
  • How can it be improved further

npm version isn't latest code

Installing the latest version from npm doesn't give the latest code, even though the version number will be marked as latest.

To reproduce, go to an empty directory and then:

  1. Run npm install metalsmith-in-place
  2. Go check index.js for any mentions of exposeConsolidate

Update readme

  • document use of partials (not all languages implement it)
  • document use of extends, includes (relative to.., filename requirement)
  • Warn that processing a lot of large files without filtering will slow everything down

fails if partials contain comments with block-partials

if the partial contains comments like below:

<!--
{{!
/**
 * This is a component
 *
 * @param   {string}  content
 * @example
 * {{#> partial}}
 *     {{> another-partial}}
 * {{/ partial}}
 */
}}
 -->

the plugin fails with error:

events.js:154
      throw er; // Unhandled 'error' event
      ^

Error: Parse error on line 14:
...sight here..."}} * {{/ partial}}
----------------------^
Expecting 'EOF', got 'OPEN_ENDBLOCK'
    at Object.parseError (../node_modules/handlebars/dist/cjs/handlebars/compiler/parser.js:267:19)
    at Object.parse (../node_modules/handlebars/dist/cjs/handlebars/compiler/parser.js:336:30)
    at HandlebarsEnvironment.parse (../node_modules/handlebars/dist/cjs/handlebars/compiler/base.js:46:43)
    at compileInput (../node_modules/handlebars/dist/cjs/handlebars/compiler/compiler.js:514:19)
    at Object.ret (../node_modules/handlebars/dist/cjs/handlebars/compiler/compiler.js:523:18)
    at Object.invokePartialWrapper [as invokePartial] (../node_modules/handlebars/dist/cjs/handlebars/runtime.js:72:46)
    at Object.eval (eval at createFunctionContext (../node_modules/handlebars/dist/cjs/handlebars/compiler/javascript-compiler.js:254:23), <anonymous>:6:28)
    at main (../node_modules/handlebars/dist/cjs/handlebars/runtime.js:173:32)
    at ret (../node_modules/handlebars/dist/cjs/handlebars/runtime.js:176:12)
    at ret (../node_modules/handlebars/dist/cjs/handlebars/compiler/compiler.js:525:21)
    at ../node_modules/consolidate/lib/consolidate.js:734:16
    at ../node_modules/consolidate/lib/consolidate.js:143:5
    at Promise._execute (../node_modules/bluebird/js/release/debuggability.js:272:9)
    at Promise._resolveFromExecutor (../node_modules/bluebird/js/release/promise.js:473:18)
    at new Promise (../node_modules/bluebird/js/release/promise.js:77:14)
    at promisify (../node_modules/consolidate/lib/consolidate.js:136:10)

Won't render handlebars

I've looked at every example I can find and the source but I can't see why this just isn't getting rendered at all. I tried inPlace({pattern: '**/'.html'}) too, I can't specify the handlebars engine because it doesn't expose a render method so jstransform is supposed to deal with it isn't it?

build.js

var Metalsmith = require('metalsmith');
var layouts = require('metalsmith-layouts');
var inPlace = require('metalsmith-in-place');
var autoprefixer = require('metalsmith-autoprefixer');
var assets = require('metalsmith-assets');
var markdown = require('metalsmith-markdown');
var permalinks = require('metalsmith-permalinks');
var collections = require('metalsmith-collections');
var debug = require('metalsmith-debug');

Metalsmith(__dirname)
  .destination('./public')
  .source('./content')
  .clean(true)
  .use(assets({
    source: './assets',
    destination: './assets'
  }))
  .use(inPlace())
  .use(collections({
      blog:{
        pattern:'blog/**/*.html'
      }
  }))
  .use(permalinks({
    pattern: ':title',
    relative: false,
    linksets: [{
        match: { collection: 'blog' },
        pattern: ':collection/:title'
    }]
  }))
  .use(autoprefixer())
  .use(layouts({
    engine: 'handlebars',
    directory: './template',
    default: 'default.hbs',
    partials: './template/partial',
    pattern: '**/*.html'
  }))
  .use(debug())  // set $env:DEBUG='metalsmith:*' to see output
  .build(function(err) {
    if (err) throw err;
  })

content/blog/index.html

<h1>List of blog pages.</h1>

{{#each post in blog}}
    <h1>{{post.title}}</h1>
{{/each}}

public/blog/index.html

...template
    </section>

    <div class="main">
        <h1>List of blog pages.</h1>

{{#each post in blog}}
    <h1>{{post.title}}</h1>
{{/each}}

    </div>

    <footer>
...template

Update readme

  • explain what this plugin does
  • add examples for the default engine, along with instructions on how to use it
  • Travis badge points to repo and not to master branch

explain that in-place is your first stop, and that layouts is a polyfill for languages without extends ( #64 ) (do this in metalsmith-layouts)

Should we expect everything to be in src?

Metalsmith loads everything from src, so it would make sense to design this lib around that assumption. It seems to be what most newcomers expect as well.

On the other hand, the files in src could also be seen as the files that you want in build. Whereas wrapper templates are more secondary files, that you don't want to see in your build output for example. Which approach are we taking?

Update readme

  • Include metalsmith-templates deprecation
  • Document passing of unrecognised parameters to consolidate

Multiple errors with Nunjucks import

Using the Metalsmith static-site-example I ran into two issues with Nunjucks import.

I added static-site/layouts/macros.html and try to import it for further usage from within index.md

{% import "macros.html" as macros %} throws:

Template render error: (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/src/index.html)
  Error: template names must be a string: undefined
    at Object.exports.prettifyError (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/jstransformer-nunjucks/node_modules/nunjucks/src/lib.js:34:15)
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/jstransformer-nunjucks/node_modules/nunjucks/src/environment.js:486:31
    at root [as rootRenderFunc] (eval at <anonymous> (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/jstransformer-nunjucks/node_modules/nunjucks/src/environment.js:565:24), <anonymous>:26:3)
    at Obj.extend.render (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/jstransformer-nunjucks/node_modules/nunjucks/src/environment.js:479:15)
    at Transformer.render (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-in-place/node_modules/jstransformer/index.js:289:25)
    at renderFile (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-in-place/lib/render-file.js:48:31)
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-in-place/index.js:38:25
    at Array.forEach (native)
    at Ware.<anonymous> (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-in-place/index.js:34:24)
    at Ware.<anonymous> (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith/node_modules/ware/node_modules/wrap-fn/index.js:45:19)
    at next (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith/node_modules/ware/lib/index.js:85:20)
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith/node_modules/ware/node_modules/wrap-fn/index.js:121:18
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-layouts/node_modules/async/lib/async.js:52:16
    at done (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-layouts/node_modules/async/lib/async.js:246:17)
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-layouts/node_modules/async/lib/async.js:44:16
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-layouts/lib/index.js:143:9
make: *** [build] Error 1

{% import "../layouts/macros.html" as macros %} throws:

Template render error: (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/src/index.html) [Line 23, Column 19]
  expected name as lookup value, got .
    at Object.exports.prettifyError (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/jstransformer-nunjucks/node_modules/nunjucks/src/lib.js:34:15)
    at Obj.extend.init (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/jstransformer-nunjucks/node_modules/nunjucks/src/environment.js:437:27)
    at new new_cls (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/jstransformer-nunjucks/node_modules/nunjucks/src/object.js:46:28)
    at Object.module.exports.compile (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/jstransformer-nunjucks/node_modules/nunjucks/index.js:64:12)
    at Object.exports.compile (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/jstransformer-nunjucks/index.js:41:27)
    at Transformer.render (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-in-place/node_modules/jstransformer/index.js:288:44)
    at renderFile (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-in-place/lib/render-file.js:48:31)
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-in-place/index.js:38:25
    at Array.forEach (native)
    at Ware.<anonymous> (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-in-place/index.js:34:24)
    at Ware.<anonymous> (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith/node_modules/ware/node_modules/wrap-fn/index.js:45:19)
    at next (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith/node_modules/ware/lib/index.js:85:20)
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith/node_modules/ware/node_modules/wrap-fn/index.js:121:18
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-layouts/node_modules/async/lib/async.js:52:16
    at done (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-layouts/node_modules/async/lib/async.js:246:17)
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-layouts/node_modules/async/lib/async.js:44:16
make: *** [build] Error 1

I could get around this by adding a variable to the YAML front matter like this: pathToMacros : ../layouts/macros.html and called it using that variable {% import pathToMacros as macros %}

But then I end up with the following template not found error:

Template render error: (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/src/index.html)
  Template render error: (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/src/index.html)
  Error: template not found: /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/layouts/macros.html
    at Object.exports.prettifyError (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/jstransformer-nunjucks/node_modules/nunjucks/src/lib.js:34:15)
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/jstransformer-nunjucks/node_modules/nunjucks/src/environment.js:486:31
    at root [as rootRenderFunc] (eval at <anonymous> (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/jstransformer-nunjucks/node_modules/nunjucks/src/environment.js:565:24), <anonymous>:26:3)
    at Obj.extend.render (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/jstransformer-nunjucks/node_modules/nunjucks/src/environment.js:479:15)
    at Transformer.render (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-in-place/node_modules/jstransformer/index.js:289:25)
    at renderFile (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-in-place/lib/render-file.js:48:31)
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-in-place/index.js:38:25
    at Array.forEach (native)
    at Ware.<anonymous> (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-in-place/index.js:34:24)
    at Ware.<anonymous> (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith/node_modules/ware/node_modules/wrap-fn/index.js:45:19)
    at next (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith/node_modules/ware/lib/index.js:85:20)
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith/node_modules/ware/node_modules/wrap-fn/index.js:121:18
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-layouts/node_modules/async/lib/async.js:52:16
    at done (/Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-layouts/node_modules/async/lib/async.js:246:17)
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-layouts/node_modules/async/lib/async.js:44:16
    at /Users/js/Downloads/metalsmith-test/metalsmith/examples/static-site/node_modules/metalsmith-layouts/lib/index.js:143:9
make: *** [build] Error 1

Not sure where the issue lies: metalsmith-in-place, jstransformer-nunjucks, Nunjucks or even my own fault?

Thanks for help in advance!

Cannot get jstransformer to work

Okay, so I really want to unlock the jstransformer power of this plugin. But I cannot get it to work!


First of all, the README claims that passing engine to the plugin is optional. When I leave it blank, I get a fatal error that says the engine option is required. Very frustrating.

Next, I tried to explicitly set engine to JSTransformer. Sounds simple enough, right? Unfortunately, I found it surprisingly confusing. Here’s why.


The README says the default engine is “jstransformer”, but that word links to metalsmith-engine-jstransformer instead. I looked in the source code, and that appears to be what is used by metalsmith-in-place.

So, the README text says one thing, the README links to a different thing, and finally there is a third project metalsmith-jstransformer.

After trying both jstransformer and metalsmith-engine-jstransformer, I kept getting the same error:

Error: Unknown template engine: "function Engine(files, metalsmith, options) {
    _classCallCheck(this, Engine);

    this.files = files;
    this.options = options;
    this.metadata = metalsmith.metadata();
    this.source = metalsmith.source();
  }"

Thoroughly frustrated and baffled, I tried using metalsmith-jstransformer instead. That failed, too. (Yes, I also installed the necessary jstransformer-* plugins. For now, I was just using Handlebars.)

As a matter of fact, I remained confused about the relationship between metalsmith-jstransformer and this project until I began writing this issue. In the process of writing, I now understand that metalsmith-jstransformer appears merely to have been an inspiration, and is not required or even used by this project.

This relationship needs to be clearly stated on the README, along with a clear statement about the metalsmith-engine-jstransformer, and whether metalsmith-engine-* is a sub-naming scheme to be used by all engines for this plugin.

I’m dying to try out this use of metalsmith-in-place out…but please tell me what is going on! I’m pretty frustrated after trying to figure this out for a couple of hours.

Please help! And May the Source Be With You™.

How to specify the template engine?

I would like to use Nunjucks as template engine with metalsmith-in-place using the jstransformer-nunjucks module.

How can I configure my build pipeline to use this module? In the latest (2.0 beta) documentation I can't find any details on specifying an engine.

Thanks a lot in advance!

Abstract rendering to separate library

Abstract rendering to a replaceable render function (so you can use consolidate, jstransformers or whatever). Makes testing simpler and abstracts the rendering to a separate wrapper library (which can then also be used by metalsmith-layouts as well).

  • Users should also be able to override it.
  • Abstract the api so it can fit other rendering libs besides jstransformers.

Would probably be good to release jstransformers and consolidate-compatible wrappers first. Also, after this release scanning for partials, helpers, etc. as separate libs.

Can't use with metalsmith-layouts

Using metalsmith-in-place seems to render my pages without regard to metalsmith-layouts

This configuration ...


	metalsmith(buildCfg.rootDir)
		.clean(true)
		.source(buildCfg.hbsTemplatesDir + site + "/" + buildCfg.hbsPagesDirname)
		.destination(buildCfg.hbsOutDir + site)
		// use stuff
		.use(inPlace())
		.use(layouts({
			engine: "handlebars",
			"default": buildCfg.hbsDefaultLayoutFilename,
			directory: buildCfg.hbsTemplatesDir + site + "/" + buildCfg.hbsLayoutDirname,
			partials: buildCfg.hbsTemplatesDir + site + "/" + buildCfg.hbsPartialsDirname,
			pattern: "**/*.hbs",
                        rename: true
		}))
		.build();

using this layout ...

---
title: "My Title"
layout: main.hbs
appCss: /app/main.css
basePath: /
---
<my-app></my-app>

renders ...

<my-app></my-app>

without regard of the layout and partials within the layouts and partials directory.

Name is confusing

The names layouts and in-place are a bit confusing (to newcomers especially). Make it more obvious that in-place is the main lib, and that layouts is just a polyfill for languages without extends

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.