Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

mangony

Yet another static site generator in NodeJS focussed on being fast and simple. Mangony fulfills just one task: It takes templates (like handlebars or jsx) and compiles them to an output directory.

generator, Veams, react, react-static, handlebars, templates, compiler, compile, render, Mangony, Grunt, static, sites, express, simple site generator, static site generator

readme

Logo Mangony

NPM version Build Status NPM install license

Yet another static site generator - fast, simple, powerful and pluggable.

Mangony fulfills just one task: It takes files, saves them in cache, use templates and compiles them to an output directory.

Features

  1. Mangony can be used anywhere as npm module.
  2. By using the provided development server (express) every change is completed in no time, no matter how many pages you have in your project.
  3. Only changed pages get compiled.
  4. Creation of deep ids is possible for all types.
  5. For every type (data, partials, layouts, pages) Mangony adds a watcher (chokidar).
  6. HJSON is available.
  7. Supports different template rendering options like Handlebars or React.

Installation

Install Mangony with

npm install mangony --save-dev

For the installation of the Grunt plugin, see grunt-mangony.

Usage

Just create a new instance of Mangony:

import Mangony from 'mangony';
const app = new Mangony();

Then render your mangony instance:

app.render();

To render files with a template engine you need to add a plugin. There are some engines provided to you, but you can easily create your own if you want to. Let's go with JSX for now:

import Mangony from 'mangony';
import jsxTemplaterPlugin from 'mangony/plugins/jsx-templater.js';

const app = new Mangony();

app.render()
   .then(() => app.use(jsxTemplaterPlugin);

When using the default options your files get compiled. But you can also integrate the development server.

Examples

dev.js

Let`s say we want to develop a new static page with the dev server in place.

import Mangony from 'mangony';
import jsxTemplaterPlugin from 'mangony/plugins/jsx-templater.js';
import serverPlugin from 'mangony/plugins/server.js';

const app = new Mangony({
    cwd: `src`,
    dest: `dist/`,
    watch: true,
    types: {
        data: {
            dir: 'data',
            files: [
                '**/*.json',
                '**/*.hjson'
            ]
        },
        partials: {
            dir: 'partials',
            files: [
                '**/*.hbs'
            ]
        },
        pages: {
            dir: 'pages',
            files: [
                '**/*.tsx'
            ]
        },
        layouts: {
            dir: 'layouts',
            files: [
                '**/*.hbs'
            ]
        }
    }
});

app.render()
   .then(() => app.use(jsxTemplaterPlugin, {
       compileStaticFiles: false
   })
   .then(() => app.use(serverPlugin, {
        bsEnabled: true,
        injectScript: true,
        start: true,
        port: 3000,
        usePort: true,
        useAssetsDir: false,
   }));

When using the devServer options all routes get registered.

Now you can open your browser at localhost:3000 and navigate to the page you want to change. The url is the path to your page without a file extension (i.e. /index). If you want to use the file extension as well, just enable it via options.

prod.js

Let`s say we want to build our static page.

import Mangony from 'mangony';
import jsxTemplaterPlugin from 'mangony/plugins/jsx-templater.js';

const app = new Mangony({
    cwd: `src`,
    dest: `dist/`
    types: {
        data: {
            dir: 'data',
            files: [
                '**/*.json',
                '**/*.hjson'
            ]
        },
        partials: {
            dir: 'partials',
            files: [
                '**/*.hbs'
            ]
        },
        pages: {
            dir: 'pages',
            files: [
                '**/*.hbs',
                '**/*.md'
            ]
        },
        layouts: {
            dir: 'layouts',
            files: [
                '**/*.hbs'
            ]
        }
    }
});

app.render()
    .then(() => app.use(jsxTemplaterPlugin, {
        compileStaticFiles: true,
    }));

Now you can find the complete rendered output in the destination folder.

Options

Generic Options

assets

  • default: "./"

Path to your assets in your destination directory.

collections

  • default: []

Add your own collections which can be used in YAML front matter or filename.settings.hjson.

cwd

  • default: "src"

The current working directory.

debug

  • default: false

Print more comments in your terminal to debug a bit better ;).

dest

  • default: "app"

Output directory.

exportData

  • default : false

Export the complete data stack as JSON file.

ext

  • default: ".html"

Define the extension of your output files. This can be overridden per file by using YAML Front Matter or page.settings.json.

flatten

  • default: false

Flatten your output directory.

types (object)

There are 4 necessary types which needs to be defined:

  • layouts
  • pages
  • partials
  • data

Each type has the following options:

types[type].createDeepIds

For every type you can create deep ids. The whole path to the file will be used. That makes it possible to have multiple identical named data, partial, layout and page files in different folders.

types[type].dir

  • default: "[type]"
  • relative to cwd

You can change the type directory to any folder you like.

Important: for every type directory Mangony creates a watcher if options.watch is true.

types[type].files

  • default: ["**/*.[typeExtension]"]

Pass an array of files to the files property. Globbing is possible.

types[type].pathDelimiter

  • default: "/"

By using deep ids the id is the path to your file. But using such ids in handlebars is not possible for your data files. That`s why you can define a path delimiter.

watch

  • default: false

Just enable the internal watching of file changes.

Plugins

Dev Server Plugin (mangony/plugins/server.js)

The dev server is providing the best developer experience by triggering a reload when a file has changed and supporting the rendering of only requested files. That means, even when your project is growing in terms of pages and components it almost does not matter because only changed files get recompiled and rendered.

When the server is registered, it sets servermode in your root context to true. This is helpful if you want to distinguish between static or server related executions.

Options

devServer.bs
  • default: null

You can pass your own Browser-Sync instance.

devServer.bsEnabled
  • default: true

You can disable browser-sync.

devServer.bsOptions
  • default: null

You can pass your custom Browser-Sync options object.

devServer.express
  • default: null

You can pass your own express instance.

devServer.injectScript
  • default: true

Set to false if you want to disable the injection of the browser-sync script.

devServer.port
  • default: 3000

Change the port of the development server.

devServer.start
  • default: false

Set to true if you want to use the provided development server.

devServer.useExt
  • default: true

Set to false if you do not want to use extensions in your routes.

devServer.usePort
  • default: true

Set to false if you have already a port provided to express.

devServer.useAssetsDir
  • default: true

Set to false if you have already an asset directory provided to express.

JSX Templater Plugin (mangony/plugins/jsx-templater.js)

With this plugin we can render React, Preact or similar JSX capable projects. Mangony is using a temporary directory to compile your files with ESBuild. That means .tsx and .jsx files are both supported out-of-the-box.

Options

compileStaticFiles
  • default: true

Enable/disable the compiling of your files.

Handlebars Templater Plugin (mangony/plugins/jsx-templater.js)

allow.YFMLayout (Boolean)

  • default: false

Add the possibility to reference layouts in YAML front matter. {{{yield}}} will be replaced in your referenced layout with the content of the page.

allow.YFMContextData (Boolean)

  • default: false

Flag to add a specific data context for your page by referencing a data file id in YAML front matter.

compileStaticFiles

  • default: true

Enable/disable the compiling of your files.

handlebarsInstance

  • default: Handlebars

Add the possibility to pass your own instance with custom helpers, like:

import Mangony from 'mangony';
import hbsTemplaterPlugin from 'mangony/plugins/hbs-templater.js';
import serverPlugin from 'mangony/plugins/server.js';
import mgyHelperWrapWith from 'mangony-hbs-helper-wrap-with';
import mgyHelpers from 'mangony-hbs-helpers';
import layouts from 'handlebars-layouts';
import handlebarsHelpers from 'handlebars-helpers';
import handlebars from 'handlebars';
import * as helpers from './helpers/hbs-helpers.js';

const engine = handlebars.create();

handlebarsHelpers({ handlebars: engine });
layouts.register(engine);
mgyHelpers.register(engine);
mgyHelperWrapWith.register(engine);
helpers.register(engine);

const mangony = new Mangony({
    cwd: 'src',
    dest: 'dist',
    exportData: false,
    evtNamespace: 'Mangony',
    ext: '.html',
    flatten: false,
    collections: [
        'sitemap',
    ],
    types: {
        data: {
            dir: 'templates',
            files: [
                '**/*.json',
                '**/*.hjson',
            ],
        },
        pages: {
            dir: 'templates/pages',
            files: [
                '**/*.hbs',
                '**/*.md',
            ],
        },
        partials: {
            dir: 'templates/partials',
            files: [
                '**/*.hbs',
            ],
        },
        layouts: {
            dir: 'templates/layouts',
            files: [
                '**/*.hbs',
            ],
        },
    },
    watch: devMode
});

mangony.render()
    .then(() => {
        return mangony.use(hbsTemplaterPlugin, {
            handlebarsInstance: engine,
            allow: {
                YFMContextData: true,
                YFMLayout: true,
            },
            compileStaticFiles: false,
        });
    })
  .then((templater) => {
    templater.then(() => {
      return mangony.templater.renderPages();
    });
  })

Why Mangony?

Static site generator and server?

In general I love static site generators. Simply deploy the output and you`re done - great.

But there is one major problem. When developing, every change leads to the compiling of all pages. In large projects this is very time consuming.

So why not just combine a server for development purpose with a static site generator?

Test

Just checkout the repository, install all dependencies with npm install and execute npm test.

Examples

See examples folder for JSX, Handlebars or Freemarker Templates.

License

see LICENSE.md.

changelog

v2.0.0-alpha-20

  • Add relateiveToBasePath support for pages

v2.0.0-alpha-16

  • Change jsx templater to bundle pages instead of compiling each file
  • Ignore layouts in settings file for jsx

v2.0.0-alpha-15

  • Improve watcher logic for directory checks

v2.0.0-alpha-13

  • Add type definitions for TS projects

v2.0.0-alpha-12

  • Add ignore support
  • Remove buffer from cache
  • Replace multi-glob with globby

v2.0.0-alpha-10

  • Add JSX Templating support (React/Preact)

v2.0.0-alpha

  • Add plugin system
  • Support different template engines like freemarker, handlebars and more

v1.4.0

  • Add browser-sync as option.

v1.3.4

  • Add better watcher handling for file and folder existence.

v1.3.3

  • Add directory check for watchers, because chokidar falls back to cwd which leads to multiple incremental builds and reloads per file.

v1.3.2

  • Bugfix for major server rendering issue, when page is changed.

v1.3.1

  • Add extension definition for single page by using page.settings.

v1.3.0

  • Add extension definition for single page by using YAML Front Matter.

v1.2.2

  • Fix bug in custom helper registration with path resolving included.

v1.2.1

  • Update mangony rendering process to support page.settings, and context merging.

v1.1.16

  • Update magnony-hbs-helper package version to support new helpers.

v1.1.15

  • Update assets path creation when flatten option is set.

v1.1.14

  • Add event namespace to support multiple watching instances at the same time.

v1.1.13

  • Add handlebars instance instead of using one global one (templater.js)

v1.1.12

  • Update mangony-hbs-helpers version

v1.1.11

  • Update templater.js to support manually added pages to the cache without directory context and srcExt

v1.1.10

  • Add devServer.bsEnabled and devServer.useExt

v1.1.9

  • Bump versions

v1.1.8

  • Fix register route handling in watch mode

v1.1.7

  • Add injectScript option

v1.1.6

  • Add default port to bsOptions

v1.1.5

  • Update server.js port for browser-sync

v1.1.3-v1.1.4

  • Version handling of markdown-it plugins

v1.1.2

  • Update error messages in loader.js

v1.1.1

  • Clean up server.js in options handling
  • Bump versions

v1.1.0

  • Add livereload (browser-sync) to development server
  • Add options for livereload
  • Add better event handling

v1.0.20

  • Bugfix: deep IDs for partials and layouts in watch mode

v1.0.19

  • Bugfix: deep IDs for partials

v1.0.18

  • Update bindEvents() in mangony to support renaming of pages in watch mode without errors

v1.0.17

  • Update packages
  • Update Readme

v1.0.16

  • Add custom mangony helpers

v1.0.15

  • Add unpublish/publish flag for pages in YFM

v1.0.14

  • Add basename to currentPage

v1.0.13

  • Add multiple {{{yield}}} replacements

v1.0.12

  • Add currentPage data object to @root

v.1.0.11

  • Updated templater.js to support YFMLayout and Extended Layouts at the same time