Skip to content

Commit

Permalink
Updates README (aligned with other core plugins)
Browse files Browse the repository at this point in the history
  • Loading branch information
webketje committed Jul 16, 2023
1 parent 8788f47 commit 22cff02
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 41 deletions.
146 changes: 109 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,44 +38,81 @@ Pass `@metalsmith/in-place` to `metalsmith.use` :
```js
import inPlace from '@metalsmith/in-place'

// render all files matching **/*.{njk,nunjucks} to HTML
// shorthand
metalsmith.use(inPlace({ transform: 'nunjucks' }))

// render all files matching **/*.{hbs,handlebars,md,marked,markdown} to HTML
// also works with files containing both!
metalsmith.use(inPlace({ transform: 'handlebars' })).use(inPlace({ transform: 'marked' }))
// same as shorthand
metalsmith.use(
inPlace({
transform: jsTransformerNunjucks, // resolved
extname: '.html',
pattern: '**/*.{njk,nunjucks}*',
engineOptions: {}
})
)
```

## Options
In the transformed file, you have access to `{ ...metalsmith.metadata(), ...fileMetadata }`, so that the following build

- [transform](#transform): required. Which transformer to use: a string representing node module name or local JS module path (starting with `.`) whose default export is a jstransformer. As a shorthand for existing transformers you can remove the `jstransformer-` prefix: `marked` will be understood as `jstransformer-marked`. Or an actual jstransformer; an object with `name`, `inputFormats`,`outputFormat`, and at least one of the render methods `render`, `renderAsync`, `compile` or `compileAsync` described in the [jstransformer API docs](https://github.com/jstransformers/jstransformer#api)
- [pattern](#pattern): optional. Defaults to `**/*.<transform.inputFormats>`. Useful to further limit the scope of the transform by path or glob (accepts a string or an array of strings).
- [engineOptions](#engineoptions): optional. Pass options to the jstransformer that's rendering the files. The default is `{}`.
```js
metalsmith.metadata({ title: 'Default title', nodeVersion: process.version }).use(inPlace({ transform: 'handlebars' }))
```

### `pattern`
for a file:

Only files that match this pattern will be processed. So this `metalsmith.json`:
```yml
---
title: Article title
---
<h1>{{ title }}</h1>Node v{{ nodeVersion }}
```

```json
{
"source": "src",
"destination": "build",
"plugins": [
{
"@metalsmith/in-place": {
"transform": "nunjucks",
"pattern": "blog/**/*.njk"
}
}
]
would render `<h1>Article title</h1>Node v16.20`

Multiple transforms can be used to target different sets of files, or to reprocess the same files multiple times in the order they are `metalsmith.use`'d:

```js
// this build will apply the marked transform to index.md, the handlebars transform to index.hbs,
// and handlebars first, marked second to both index.hbs.md, index.md.hbs, and html-minifier to all (only in production)
metalsmith
.env('NODE_ENV', process.env.NODE_ENV)
.use(inPlace({ transform: 'handlebars', extname: null }))
.use(inPlace({ transform: 'marked' }))

if (metalsmith.env('NODE_ENV') !== 'development') {
metalsmith.use(inPlace({ transform: 'html-minifier' }))
}
```

Would only process files within the `./src/blog` folder, because the pattern is relative to your source folder. See [Metalsmith#match](https://metalsmith.io/api/#Metalsmith+match) for further details.
### Options

In most cases, you will only need to specify the `transform` and `engineOptions` option.

- [transform](#transform) (`string|JsTransformer`): **required**. Which transformer to use. The full name of the transformer, e.g. `jstransformer-handlebars`, its shorthand `handlebars`, a relative JS module path starting with `.`, e.g. `./my-transformer.js`, whose default export is a jstransformer or an actual jstransformer: an object with `name`, `inputFormats`,`outputFormat`, and at least one of the render methods `render`, `renderAsync`, `compile` or `compileAsync` described in the [jstransformer API docs](https://github.com/jstransformers/jstransformer#api)
- [extname](#extension-handling) (`string|false|null`): optional. How to transform a file's extensions: `''|false|null` to remove the last `transform.inputFormat` matching extension, `.<ext>` to force an extension rename.
- [engineOptions](#engineoptions) (`Object<string, any>`): optional. Pass options to the jstransformer that's rendering the files. The default is `{}`.
- pattern (`string|string[]`): optional. Override default glob pattern matching `**/*.<transform.inputFormats>*`. Useful to limit the scope of the transform by path or glob to a subfolder, or to include files not matching `transform.inputFormats`.

### Extension handling

By default in-place will apply smart default extension handling based on `transform.inputFormats` and `transform.outputFormat`.
For example, any of the source files below processed through `inPlace({ transform: 'handlebars' })` will yield `index.html`.

| source | output |
| ------------------ | ---------------- |
| src/index.hbs | build/index.html |
| src/index.hbs.html | build/index.html |
| src/index.html.hbs | build/index.html |

The example demonstrates that:

- order of extensions doesn't matter, _order of plugin execution does!_: you can pick the final extension to match the most suitable editor syntax highlighting
- a single in-place run only alters the rightmost extension matching `transform.inputFormats`
- you may choose to include or omit the `transform.outputFormat` in the source file name (.html in this case).

### `engineOptions`

Use this to pass options to the jstransformer that's rendering your templates. So this
Pass options to the jstransformer that's rendering your templates via `engineOptions`. The
`metalsmith.json`:

```json
Expand All @@ -99,29 +136,64 @@ Use this to pass options to the jstransformer that's rendering your templates. S

If you use [Pug](https://pugjs.org/api/getting-started.html), make sure to pass `engineOptions: { filename: true }`. This will ensure the filename of each processed file is passed to the render method as expected by this engine.

### Multiple transforms per file

Suppose a file `tags.hbs` that lists all the article tags used on your website

```hbs
---
title: Tags
description: Browse articles by tag
---
<h1>{{ title }}</h1>
<p>{{ description }}</p>
<ul>
{{#each tags}}
<li><a href="/tags/{{ . }}">{{ . }}</a></li>
{{/each}}
</ul>
```

To reduce Handlebars noise, you could add `metalsmith.use(inPlace({ transform: 'marked' })` to your build and change the filename to `tags.hbs.md` to generate markdown syntax with Handlebars!

```hbs
---
title: Tags
description: Browse articles by tag
---
# {{ title }}
{{ description }}
{{#each tags}}
- [{{.}}](/tags/{{ . }})
{{/each}}
More markdown here..
```

**Caution**: when using multiple templating transforms per file, make sure there is no conflicting syntax.
For example markdown will transform blocks indented by 4 spaces to `<pre>` tags, and marked's `smartypants` can potentially garble the result.

### Usage with @metalsmith/layouts

`@metalsmith/in-place` should always be used _before_ `@metalsmith/layouts`.
In most cases `@metalsmith/in-place` is intended to be used _before_ `@metalsmith/layouts`.
You can easily share `engineOptions` configs between both plugins:

```js
import inPlace from '@metalsmith/in-place'
import layouts from '@metalsmith/layouts'

const engineOptions = {
filters: {
get(context, keypath) {
return keypath.split('.').reduce((obj, prop, index, all) => {
if (obj[prop]) return obj[prop]
return ''
}, context)
}
}
}

metalsmith.use(inPlace({ transform: 'nunjucks', engineOptions })).use(layouts({ pattern: '**/*.html', engineOptions }))
const engineOptions = {}
metalsmith // index.hbs.hbs
.use(inPlace({ transform: 'handlebars', extname: '', engineOptions })) // -> index.hbs
.use(layouts({ engineOptions })) // -> index.html
```

@metalsmith/layouts uses a similar mechanism targeting `transform.inputFormats` file extensions by default.
The example requires files ending in `.hbs.hbs` extension, but if you don't like this, you can just have a single `.hbs` extension, and change the in-place invocation to `inPlace({ engineOptions, transform, extname: '.hbs' })` for the same result.

### Debug

To enable debug logs, set the `DEBUG` environment variable to `@metalsmith/in-place*`:
Expand Down
5 changes: 1 addition & 4 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -467,10 +467,7 @@ describe('@metalsmith/in-place', () => {
)
})
it('filepath with periods in basename', () => {
strictEqual(
handleExtname('some.release/v2.4.0.html.njk', options.defaults),
'some.release/v2.4.0.html'
)
strictEqual(handleExtname('some.release/v2.4.0.html.njk', options.defaults), 'some.release/v2.4.0.html')
})
})
})
Expand Down

0 comments on commit 22cff02

Please sign in to comment.