UNPKG

10 kBMarkdownView Raw
1# Metalsmith
2
3[![npm: version][npm-badge]][npm-url]
4[![ci: build][ci-badge]][ci-url]
5[![code coverage][codecov-badge]][codecov-url]
6[![license: MIT][license-badge]][license-url]
7[![Gitter chat][gitter-badge]][gitter-url]
8
9> An extremely simple, _pluggable_ static site generator for NodeJS.
10
11In Metalsmith, all of the logic is handled by plugins. You simply chain them together.
12
13Here's what the simplest blog looks like:
14
15```js
16import { fileURLToPath } from 'node:url'
17import { dirname } from 'path'
18import Metalsmith from 'metalsmith'
19import layouts from '@metalsmith/layouts'
20import markdown from '@metalsmith/markdown'
21
22const __dirname = dirname(fileURLToPath(import.meta.url))
23
24Metalsmith(__dirname)
25 .use(markdown())
26 .use(
27 layouts({
28 pattern: '**/*.html'
29 })
30 )
31 .build(function (err) {
32 if (err) throw err
33 console.log('Build finished!')
34 })
35```
36
37## Installation
38
39NPM:
40
41```
42npm install metalsmith
43```
44
45Yarn:
46
47```
48yarn add metalsmith
49```
50
51## Quickstart
52
53What if you want to get fancier by hiding unfinished drafts, grouping posts in collections, and using custom permalinks? Just add plugins...
54
55```js
56import { fileURLToPath } from 'node:url'
57import { dirname } from 'node:path'
58import Metalsmith from 'metalsmith'
59import collections from '@metalsmith/collections'
60import layouts from '@metalsmith/layouts'
61import markdown from '@metalsmith/markdown'
62import permalinks from '@metalsmith/permalinks'
63import drafts from '@metalsmith/drafts'
64
65const __dirname = dirname(fileURLToPath(import.meta.url))
66const t1 = performance.now()
67const devMode = process.env.NODE_ENV === 'development'
68
69Metalsmith(__dirname) // parent directory of this file
70 .source('./src') // source directory
71 .destination('./build') // destination directory
72 .clean(true) // clean destination before
73 .env({
74 // pass NODE_ENV & other environment variables
75 DEBUG: process.env.DEBUG,
76 NODE_ENV: process.env.NODE_ENV
77 })
78 .metadata({
79 // add any variable you want & use them in layout-files
80 sitename: 'My Static Site & Blog',
81 siteurl: 'https://example.com/',
82 description: "It's about saying »Hello« to the world.",
83 generatorname: 'Metalsmith',
84 generatorurl: 'https://metalsmith.io/'
85 })
86 .use(drafts(devMode)) // only include drafts when NODE_ENV === 'development'
87 .use(
88 collections({
89 // group all blog posts by adding key
90 posts: 'posts/*.md' // collections:'posts' to metalsmith.metadata()
91 })
92 ) // use `collections.posts` in layouts
93 .use(
94 markdown({
95 // transpile all md file contents into html
96 keys: ['description'], // and also file.description
97 globalRefs: {
98 // define links available to all markdown files
99 home: 'https://example.com'
100 }
101 })
102 )
103 .use(permalinks()) // change URLs to permalink URLs
104 .use(
105 layouts({
106 // wrap layouts around html
107 pattern: '**/*.html'
108 })
109 )
110 .build((err) => {
111 // build process
112 if (err) throw err // error handling is required
113 console.log(`Build success in ${((performance.now() - t1) / 1000).toFixed(1)}s`)
114 })
115```
116
117## How does it work?
118
119Metalsmith works in three simple steps:
120
1211. Read all the files in a source directory.
1222. Invoke a series of plugins that manipulate the files.
1233. Write the results to a destination directory!
124
125Each 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...
126
127```yml
128---
129title: A Catchy Title
130date: 2024-01-01
131---
132An informative article.
133```
134
135...would be parsed into...
136
137```js
138{
139 'path/to/my-file.md': {
140 title: 'A Catchy Title',
141 date: new Date(2024, 1, 1),
142 contents: Buffer.from('An informative article'),
143 stats: fs.Stats
144 }
145}
146```
147
148...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](examples/drafts-plugin/index.js).
149
150Of course they can get a lot more complicated too. That's what makes Metalsmith powerful; the plugins can do anything you want!
151
152## Plugins
153
154A [Metalsmith plugin](https://metalsmith.io/api/#Plugin) is a function that is passed the file list, the metalsmith instance, and a done callback.
155It is often wrapped in a plugin initializer that accepts configuration options.
156
157Check out the official plugin registry at: https://metalsmith.io/plugins.
158Find all the core plugins at: https://github.com/search?q=org%3Ametalsmith+metalsmith-plugin
159See [the draft plugin](examples/drafts-plugin) for a simple plugin example.
160
161## API
162
163Check out the full API reference at: https://metalsmith.io/api.
164
165## CLI
166
167In addition to a simple [Javascript API](#api), the Metalsmith CLI can read configuration from a `metalsmith.json` file, so that you can build static-site generators similar to [Jekyll](https://jekyllrb.com) or [Hexo](https://hexo.io) easily. The example blog above would be configured like this:
168
169`metalsmith.json`
170
171```json
172{
173 "source": "src",
174 "destination": "build",
175 "clean": true,
176 "metadata": {
177 "sitename": "My Static Site & Blog",
178 "siteurl": "https://example.com/",
179 "description": "It's about saying »Hello« to the world.",
180 "generatorname": "Metalsmith",
181 "generatorurl": "https://metalsmith.io/"
182 },
183 "plugins": [
184 { "@metalsmith/drafts": true },
185 { "@metalsmith/collections": { "posts": "posts/*.md" } },
186 { "@metalsmith/markdown": true },
187 { "@metalsmith/permalinks": "posts/:title" },
188 { "@metalsmith/layouts": true }
189 ]
190}
191```
192
193Then run:
194
195```bash
196metalsmith
197
198# Metalsmith · reading configuration from: /path/to/metalsmith.json
199# Metalsmith · successfully built to: /path/to/build
200```
201
202Options recognised by `metalsmith.json` are `source`, `destination`, `concurrency`, `metadata`, `clean` and `frontmatter`.
203Checkout the [static site](examples/static-site), [Jekyll](examples/jekyll) examples to see the CLI in action.
204
205### Local plugins
206
207If 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)
208
209```json
210{
211 "plugins": [{ "./lib/metalsmith/plugin.js": true }]
212}
213```
214
215## The secret...
216
217We 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.
218
219Which means you could just as easily use it to make...
220
221- [A project scaffolder.](examples/project-scaffolder)
222- [A build tool for Sass files.](examples/build-tool)
223- [A simple static site generator.](examples/static-site)
224- [A Jekyll-like static site generator.](examples/jekyll)
225
226## Resources
227
228- [Gitter Matrix community chat](https://app.gitter.im/#/room/#metalsmith_community:gitter.im) for chat, questions
229- [X (formerly Twitter) announcements](https://x.com/@metalsmithio) and the [metalsmith.io news page](https://metalsmith.io/news) for updates
230- [Awesome Metalsmith](https://github.com/metalsmith/awesome-metalsmith) - great collection of resources, examples, and tutorials
231- [emmer.dev on metalsmith](https://emmer.dev/blog/tag/metalsmith/) - A good collection of various how to's for metalsmith
232- [glinka.co on metalsmith](https://www.glinka.co/blog/) - Another great collection of advanced approaches for developing metalsmith
233- [Getting to Know Metalsmith](http://robinthrift.com/post/getting-to-know-metalsmith/) - a great series about how to use Metalsmith for your static site.
234
235## Troubleshooting
236
237Set `metalsmith.env('DEBUG', '*metalsmith*')` to debug your build. This will log debug logs for all plugins using the built-in `metalsmith.debug` debugger.
238For older plugins using [debug](https://github.com/debug-js/debug/) directly, run your build with `export DEBUG=metalsmith-*,@metalsmith/*` (Linux) or `set DEBUG=metalsmith-*,@metalsmith/*` for Windows.
239
240### Node Version Requirements
241
242Future Metalsmith releases will at least support the oldest supported Node LTS versions.
243
244Metalsmith 2.6.x supports NodeJS versions 14.18.0 and higher.
245Metalsmith 2.5.x supports NodeJS versions 12 and higher.
246Metalsmith 2.4.x supports NodeJS versions 8 and higher.
247Metalsmith 2.3.0 and below support NodeJS versions all the way back to 0.12.
248
249### Compatibility & support policy
250
251Metalsmith is supported on all common operating systems (Windows, Linux, Mac).
252Metalsmith releases adhere to [semver (semantic versioning)](https://semver.org/) with 2 minor gray-area exceptions for what could be considered breaking changes:
253
254- Major Node version support for EOL (End of Life) versions can be dropped in minor releases
255- 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.
256
257## Credits
258
259Special thanks to [Ian Storm Taylor](https://github.com/ianstormtaylor), [Andrew Meyer](https://github.com/Ajedi32), [Dominic Barnes](https://github.com/dominicbarnes), [Andrew Goodricke](https://github.com/woodyrew), [Ismay Wolff](https://github.com/ismay), [Kevin Van Lierde](https://github.com/webketje) and [others](https://github.com/segmentio/metalsmith/graphs/contributors) for their contributions!
260
261## [License](LICENSE)
262
263[npm-badge]: https://img.shields.io/npm/v/metalsmith.svg
264[npm-url]: https://www.npmjs.com/package/metalsmith
265[ci-badge]: https://github.com/metalsmith/metalsmith/actions/workflows/test.yml/badge.svg
266[ci-url]: https://github.com/metalsmith/metalsmith/actions/workflows/test.yml
267[codecov-badge]: https://coveralls.io/repos/github/metalsmith/metalsmith/badge.svg?branch=master
268[codecov-url]: https://coveralls.io/github/metalsmith/metalsmith?branch=master
269[license-badge]: https://img.shields.io/github/license/metalsmith/metalsmith
270[license-url]: LICENSE
271
272[gitter-badge]: https://img.shields.io/badge/[gitter:matrix]-join-blue.svg
273[gitter-url]: https://app.gitter.im/#/room/#metalsmith_community:gitter.im