Wikic
a simple static site generator
Table of Contents
Example
Usage
CLI
wikic init
Use wikic init to create a new wikic folder
wikic init <dir>
wikic build
Use wikic build to build pages.
wikic build [options]
# Options:
#
# -h, --help output usage information
# -c, --clean clean public dir before building
# -w, --watch watch src dir change
# -s, --serve serve public dir
# -d, --dir <dir> change working dir
# -o, --output <dir> change public dir
# -p, --port <number> change server port
Node module
const htmlclean = require('htmlclean')
const Wikic = require('wikic')
const docslist = require('wikic-suite-docslist')
const wikic = new Wikic()
// add filter to minify html before write
wikic.filter.register('beforeWrite', function minify(context) {
if (!context.data) return context
context.data = htmlclean(context.data)
return context
})
// add suite to provide `list` variable
wikic.registerSuite(docslist)
// build the site and start watcher and server to debug or preview
wikic
.build()
.then(() => wikic.watch())
.then(() => wikic.serve())
Getting started
Installation
# install as a cli tool
npm install -g wikic
# install as a node dependency
npm install --save wikic
Configuration and Front Matter
There is a default config lib/defaultConfig.yml. We can create _config.ymls or a wikic.config.js to override it.
There are two kinds of configuration, root config and sub config. A root config must be a wikic.config.js or a _config.yml in the working directory of a build (aka wikic.cwd). A sub config must be a _config.yml in the subdirectory of wikic.cwd.
Not all options work in sub configs and we can use some of the options such as
titlepage- options that Filters use, such as
toc,markdownItandtoc
There are inheritance chains of configuration:
- root config =
_config.yml(in thewikic.cwd) +wikic.config.js(in thewikic.cwd) - sub config =
_config.yml(closest to markdown file, in the subdirectory ofwikic.cwd) wikic.config= defaultConfig.yml + root configcontext.site=wikic.config+ a sub configcontext.page=context.page+context.site.page+ Front Matter in markdown
See Filter for details of context.
wikic.config.js Example:
module.exports = {
title: 'Wikic',
toc: {
selectors: 'h2, h3, h4',
},
}
Front Matter example:
---
title: Hello World # title of the page
toc: false # disable toc for this page
layout: docs # set layout for this page
---
Dev Server
We should use a server extension to run wikic build -s.
Server extension Example:
Layouts
We can create Nunjucks templates (extname is .njk) in layoutPath.
In order to specify default layout for markdowns in a specific path, create a _config.yml in the path and add lines to it:
page:
layout: customLayout
Also, we can set layout in Front Matter for a specific markdown.
Variables in Layouts
site,Object, reference tocontext.sitepage,Object, reference tocontext.pagepage.types,Array, markdown's dirnames
content, string, content of HTML built from markdown
Builtin Filters
typeMap: Get typeName set inwikic.config.typeMapbaseurl: Get a URL prefixed with base URLrelative: Receives a absolute path string, returns a url relative to current page.typeMaps: Receives aArray, Returnsarray.map(typeMap). Tips: get typeNames array{{ page.types | typeMaps }}
Nunjucks in Markdown
Variable site and page is available.
{{, }}, {#, #}, {%, %} in raw blocks and <code> blocks will be escaped.
<!-- markdown -->
{% raw %}
{{ page.title }}
{% endraw %}
<!-- output -->
{{ page.title }}
<!-- markdown -->
`{{ page.title }}`
<!-- output -->
<code>{{ page.title }}</code>
Filter
const filter = function(context, wikic) {
const newContext = Object.assign({}, context)
// do something with newContext
return newContext
}
A 'filter' is a Function, which receives a context and the wikic and returns a context.
The context returned by the filter will be passed to next filter.
context
A context is corresponding to a build of a markdown file.
context of the following types of filter is null
afterReadAllDocs: after reading all docs, before writing all docs.beforeBuild: before building all things.beforeBuildDocs: before building all docs.afterBuild: after building all things.afterBuildDocs: after building all docs.
context passed to following types of filter is an Object
afterRead: invoked after reading each markdown file.beforeWrite: invoked before writing each markdown file.beforeRender: invoked before rendering each markdown file.beforeWriteAsset: invoked before writing each asset.
The context may contains the following properties:
src: string, absolute path of sourcedist: string, absolute path of destinationdata: string, content of document;Buffer, for assetssite:Object, site configpage:Object, page configrenderContext:Object, nunjucks render context, contains variablesIS_DOC: boolean, whether indocsPath
We can use wikic.filter.register(type, filter) to register filters.
Suite
A suite should be a combination of filters.
It should be
- a
stringwhich is a module id relative towikic.cwd - a plain
Object - or a
Functionwhich receivesconfigand returns anObjector a falsy value.
Suite objects' property name should be a filter's type name.
Example
Register suites in wikic.config.js
Use Object
module.exports = {
suites: [
{
beforeBuild: function() {
console.time('build')
},
afterBuild: function() {
console.timeEnd('build')
},
},
],
}
Use Function
const showBuildTime = function(config) {
// if option `time` is falsy, do not add suite
if (!config.time) return null
return {
beforeBuild: function() {
console.time('build')
},
afterBuild: function() {
console.timeEnd('build')
},
}
}
module.exports = {
suites: [showBuildTime],
}
Use module ID
module.exports = {
suites: ['wikic-suite-docslist'],
}
We can also use wikic.registerSuite(suite) to add suites.
Watch handlers
Built-in handlers
Three built-in handlers:
setupAndBuild: Receives new config and then rebuildbuild: Rebuild the whole sitebuildStaticFile: When a static file changed which wasn't ignored byconfig.excludesorconfig.publicExcludes, build the static file (copy or generate html) and executeafterBuildfilter
We can set their values to matchers in anymatch.
The default value is like following wikic.config.js
module.exports = {
watchHandlers: {
setupAndBuild: ['**/wikic.config.js', '**/_config.yml'],
build: [`${config.layoutPath}/**`, `${config.docsPath}/**`],
buildStaticFile: '**/*',
},
}
Custom handlers
We can add handlers for files that won't be handled by built-in handlers like the example:
module.exports = {
publicExcludes: ['sw-template.js'],
watchHandlers: {
custom: {
sw: {
matcher: ['sw-template.js'],
handler: (filePath, wikic) => {
try {
genSW(wikic.publicPath)
} catch (err) {
console.log('oops, something wrong when generating sw.js')
return false
// Return false to find a next matched handler
}
},
},
},
},
}
Priority
The order of finding handler: setupAndBuild > build > buildStaticFile > custom
Thanks
API
See JSDoc in lib/wikic/index.js