📒 a simple static site generator | 一款基于 Nunjucks 的静态网页生成器
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
bin
docs
example
lib
mocks
util
.eslintignore
.eslintrc
.gitignore
.npmignore
.travis.yml
LICENSE
README.md
package-lock.json
package.json

README.md

Wikic

Build Status Coveralls MIT License version Node

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

  • title
  • page
  • options that Filters use, such as toc, markdownIt and toc

There are inheritance chains of configuration:

  • root config = _config.yml(in the wikic.cwd) + wikic.config.js(in the wikic.cwd)
  • sub config = _config.yml (closest to markdown file, in the subdirectory of wikic.cwd)
  • wikic.config = defaultConfig.yml + root config
  • context.site = wikic.config + a sub config
  • context.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 to context.site
  • page, Object, reference to context.page
    • page.types, Array, markdown's dirnames
  • content, string, content of HTML built from markdown

Builtin Filters

  • typeMap: Get typeName set in wikic.config.typeMap
  • baseurl: Get a URL prefixed with base URL
  • relative: Receives a absolute path string, returns a url relative to current page.
  • typeMaps: Receives a Array, Returns array.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 source
  • dist: string, absolute path of destination
  • data: string, content of document; Buffer, for assets
  • site: Object, site config
  • page: Object, page config
  • renderContext: Object, nunjucks render context, contains variables
  • IS_DOC: boolean, whether in docsPath

We can use wikic.filter.register(type, filter) to register filters.

Suite

A suite should be a combination of filters.

It should be

  • a string which is a module id relative to wikic.cwd
  • a plain Object
  • or a Function which receives config and returns an Object or 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 rebuild
  • build: Rebuild the whole site
  • buildStaticFile: When a static file changed which wasn't ignored by config.excludes or config.publicExcludes, build the static file (copy or generate html) and execute afterBuild filter

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

LICENSE

MIT