Highly customizable multi-purpose rule based generator that can be used in a wide variety of use-cases. Candygen has been previously used for building static websites with arbitrary structure, email templating and even code generation (see Examples section for more details).
Also feel free to reach out on twitter if you have questions or feedback
These section will guide you through installation and basic setup for your first candygen project.
In order to use candygen you will need to have Node.js installed on your system.
Examples below use yarn for package management. However, same results could be achieved by using corresponding npm
commands.
Create an empty folder for your project:
mkdir myproject
cd myproject
Optionally, run npm init
or yarn init
to create a package.json
:
yarn init
Add candygen generator as a dependency to your project:
yarn add @candygen/generator
Create initial candygen configuration file, by running:
yarn cg init
This will create a file named candygen.config.js
, with following content:
module.exports = {
init: function () {
return {
schemaVersion: '1.0',
rules: [
// {
// template: '',
// script: '',
// data: '',
// output: ''
// }
]
}
}
};
Candygen configuration file should always contain a method called init()
that returns JavaScript object with the final rule set, partials and helpers definition
Modify candygen.config.js
to look like:
module.exports = {
init: function () {
return {
schemaVersion: '1.0',
rules: [
{
template: 'index.html.hbs',
data: 'data.json',
output: 'index.html'
}
],
partials: []
}
}
};
Create a new file data.json
with the following content:
{"message":"Hello, World!"}
And another file named index.html.hbs
containing:
<!DOCTYPE html>
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>{{message}}</h1>
</body>
</html>
Run the following command to generate output:
yarn cg
Check the newly created output
folder that should contain index.html
with the following contents:
<!DOCTYPE html>
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
There are several commands that could be used once @candygen/generator
is added as a dependency in your project folder:
yarn cg
- runs generator onceyarn cg init
- createdcandygen.config.js
with empty default configurationsyarn cg version
- outputs the current version of the candygen generator
If you need to copy a number of files as they are from your project folder into your output folder you should place them in a folder named static
.
This is particularly useful for asset files in case of static website generation, such as CSS stylesheets, JavaScript files, images etc.
Below is a small illustration of how this works:
/sample
candygen.config.js
/static
style.css
/images
1.png
2.png
If you run:
yarn cg
You will get:
/sample
candygen.config.js
/static
style.css
/images
1.png
2.png
/output
style.css
/images
1.png
2.png
Configuration file must always be named candygen.config.js
and it must always be on the root level of the project folder
This file must contain a method named init()
:
module.exports = {
init: function () {
return [CONFIGURATION];
}
};
[CONFIGURATION]
must always be an object with the following properties:
inputPath: string;
[Optional] Change the folder that should be treated as the root input folder by the generatoroutputPath: string;
[Optional] Alternative output path for the results of the generationrules: Rule[];
Set of rules describing the generation process. See Rule section below for more detailspartials: Partial[];
Set of reusable partial templates that could be used for injecting repeated sections as well as for layouting (For example, for header, footers). See Partials section below for more detailshelpers?: Helper[];
[Optional] Set of templating helpers implemented in JavaScript. See Partials section below for more details
Rule
Rule defines an atomic action perfomed by the generator during the output generation process. There several properties for each rule:
data (optional)
Data contains data in the JSON format that either will be directly passed to the handlebars template defined under template
property, or will first be transformed by a script defined in a script
property.
In case if data is directly passed to the template it should be in the following format:
{
"pages": [
{...}
]
}
script (optional)
Path to a JavaScript file containing a function called run()
that will be executed to prepare the templating data.
In case if data
property is defined for the rule. The parsed JSON value of the file specified in the data
property is passed to the run()
method.
Scripts could be very useful for various transformations on the initial data. An example below illustrates a usage of a script in order to change post titles in the example above to be in the upper case:
module.exports = {
run (data) {
data.pages.forEach(page => {
page.posts.forEach(post => {
post.title = post.title.toUpperCase();
});
})
return data;
}
}
A script must always return output in the following format:
{
"pages": [
{...}
]
}
template
A relative (to the input folder) path to a handlebars template file
output
A file name or a file name pattern for the resulting output. Two special tokens are replaced in the output value depending on the resulting page that is being processed. This way one rule can produce multiple output files:
@ID@
-pageId
value of the page will be injected instead of this token@PAGENUM@
- number of the page in the pages array will be injected instead of this token
Partial
Partials are defining handlebars partials that can contain repeated sections (such as header, footer, copyrights) or alternative be used as layouts (see handlebars partials documentation for more details)
Two properties are needed to define a partial:
name
- partial's name, will be used in other templates or partials to refer to this partialtemplate
- path to a file containing handlebars template for this partial
Here's an example definition for two partials header and footer:
...
schemaVersion: '1.0',
rules: [
...
],
partials: [
{
name: 'header',
template: 'templates/partials/header.hbs'
},
{
name: 'footer',
template: 'templates/partials/footer.hbs'
}
]
...
After being defined these partials can be used in other templates and other partials in the following way:
{{> header}}
<div class="content">
...
</div>
{{> footer}}
Helpers
Similarly to partials, helpers section can be used to define custom handlebars helpers (inline and block helpers are supported).
Two properties are needed to define a helper:
name
- helper's name, will be used in other templates or partials to refer to this helperfn
- JavaScript function - implementation of this helper
Below is an example helper definition:
...
schemaVersion: '1.0',
rules: [
...
],
partials: [
...
],
helpers: [
{
name: 'upperCaseOrMissing',
fn: (value) => {
return value ? value.toUpperCase() : 'MISSING';
}
}
]
...
Candygen Dev Server runs in background and serves the latest result of the generation. When any input file changes, Dev Server updates the output correspondingly. It is installable as a separate package:
yarn add @candygen/dev-server
In order to run it, run the following command in the folder contaning candygen.config.js
:
yarn cg-dev
Optionally you can specify a port on which dev server will run:
yarn cg-dev port=3333
This repo contains all packages related to candygen and represents a monorepo. It is using (lerna)[https://lernajs.io/] to manage multiple packages. It is recommended to use yarn for package management as this project relies on yarn workspaces. This repo includes a basic VSCode configuration for debugging generator and dev-server packages. In order to start developing locally, checkout this repository and run:
yarn build
To run TypeScript compiler in watch mode for all sub-packages use the following command:
yarn tsc-all--watch
Here's a list of websites using candygen:
Another example could be found under packages/candygen-example
This example package is also installable running yarn add @candygen/example
We use SemVer for versioning
- Turan Rustamli (rustamli)
This project is licensed under the MIT License - see the LICENSE.md file for details