npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

wit-cms

v5.0.3

Published

A file-based blog-aware content-management system for Express.

Downloads

42

Readme

Build Status npm npm

wit-cms

wit-cms is a flat-file, "blog aware", publishing platform for Express. It's designed for those who want WordPress-like functionality without the heft and attack-surface of a WordPress installation. It emphasizes simplicity, security, and performance.

Overview

Page and post content is declared by creating markdown files within the appropriate directories. wit-cms will generate everything else automatically, including:

  • express routes (both sync and async)
  • a "home" page
  • "pages" and "posts" (with "read more" links and pagination)
  • "tag" and "category" taxonomies
  • blog search and archive
  • a sitemap.xml
  • an RSS feed
  • syntax-highlighting on all content via highlight.js.

On application start, wit-cms loads all site content into an in-memory object, making it possible to serve content without reading a disk. This makes it faster than traditional database-backed content-management systems.

wit-cms seeks to offer a compromise between the full-featuredness of WordPress and the ultra-minimalism of Jekyll, and strives to be a viable alternative to those who may be dissatisfied with either.

Quick Start

To install only the wit-cms module, run:

npm install wit-cms

To spare yourself the tedium of having to write boilerplate templating, however, it may be preferable to clone the wit-cms-bootstrap repository and modify from there. This is the recommended approach for using wit-cms:

https://github.com/chrisallenlane/wit-cms-bootstrap

Creating Content

In order to create a "post" (a blog entry) or a "page" (content that exists outside of the blog context), simply create a markdown file of the appropriate name, and in the appropriate location. By default, markdown files that source page content live in <webroot>/pages/, and markdown files that source blog posts live in <webroot>/posts/.

Page and post urls will be generated based off of the filename of the corresponding markdown file. For example, the source markdown for a "Hello World" blog post should be saved to <webroot>/posts/hello-world.md, and its URL would be /blog/post/hello-world.

Front-matter

As with Jekyll, wit reads page and post metadata (title, date, author, categories, tags, etc.) out of front-matter embedded within each post or page via the json-front-matter module.

For example, all posts should contain a header like the following:

{{{
"title"       : "Hello World (of node blogging)",
"description" : "The post description."
"author"      : "John Doe",
"categories"  : [ "node", "blogging" ],
"tags"        : [ "javascript", "express" ],
"date"        : "2012-09-15"
}}}

Pages will have a similar, but sparser, header:

{{{
"title"       : "About Me",
"description" : "The page description."
"url"         : /about-me,
"searchable"  : true
}}}

The url property provides a mechanism to specify the URL at which the page should be published. This parameter is optional, and defaults to the name of the corresponding markdown file. (Example: about-me.md will publish by default to /about-me.)

The searchable property provides a mechanism for excluding pages from appearing in search results. The searchable parameter is optional, and defaults to true.

Beyond the above, any additional properties specified in front-matter will be made available to the corresponding rendered views as page locals.

Routes

wit-cms automatically generates the following routes:

Synchronous

  • /
  • /:page
  • /page/search
  • /blog/
  • /blog/post/:name
  • /blog/category/:category
  • /blog/tag/:tag
  • /blog/archive/:year/:month?/:day?
  • /blog/search
  • /search
  • /feed
  • /feed.xml
  • /sitemap.xml

Asynchronous

  • /async/pages
  • /async/pages/search
  • /async/pages/:page
  • /async/blog/
  • /async/blog/post/:name
  • /async/blog/category/:category
  • /async/blog/tag/:tag
  • /async/blog/archive/:year/:month?/:day?
  • /async/blog/search
  • /async/tags
  • /async/categories
  • /async/params

The asyncronous routes return JSON responses.

Objects

wit-cms buffers all site content in a wit object. Here is an example of its structure:

wit {
  pages: {
    "about"     : aPageObject,
    "contact"   : aPageObject,
    "portfolio" : aPageObject,
  },

  posts: {
    "website-redesign" : aPostObject,
    "blogging-in-node" : aPostObject,
    "wit-vs-wordpress" : aPostObject,
  },

  tags: [
    'the-first-tag',
    'the-second-tag',
    'the-third-tag',
    'etc',
  ],

  categories: [
    'the-first-category',
    'the-second-category',
    'the-third-category',
    'etc',
  ],

  index: {
    page: aLunrIndex,
    post: aLunrIndex,
  },

  params: {
    // arbitrary params specified on initialization
  },

}

Whereby a post object takes the following shape:

 {
  title      : 'The Post Name',
  name       : 'the-post-name',
  url        : '/blog/post/the-post-name',
  author     : 'John Doe',
  categories : [ 'foo', 'bar' ],
  tags       : [ 'alpha', 'bravo', 'charlie' ],
  date: {
    datetime : '2012-09-12T00:00:00-04:00',
    day      : '02',
    month    : '04',
    pretty   : '2 April 2014', // configurable
    unix     : '1396411200',
    year     : '2014',
  excerpt: '<p>Content before the break.</p>',
  content: '<p>The page content.</p>',
}

And a page object takes the following shape:

 {
  title       : 'The Page Name',
  name        : 'the-page-name',
  url         : '/the-page-name',
  author      : 'John Doe',
  description : 'A descripton for the page.',
  content     : '<p>The full page content.</p>'
}

Initializing

The wit-cms module will export a single function that will decorate an initialized Express app. Upon invokation, the function will also return a wit object that contains the entirety of the wit data.

const express = require('express');
const path    = require('path');
const Wit     = require('wit-cms');
var app       = express();

// express configs
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// wit configs
var config = {

  // template params
  params: {
    author  : 'John Doe',
    fqdn    : 'https://example.com',
    name    : 'Example Website',
    tagLine : 'An example site made using wit-cms',
  },

  // 302 redirect '/' to this page
  pages: {
    home: '/about-me'
  },
  
};

// initialize the wit instance
const wit = Wit(app, config);

Note that arbitrary properties may be attached to config.params. These properties will be made available to page templates via the returned wit object as wit.params.

Searching

wit-cms provides for searching among pages and blog posts via the lunr module.

Commenting

Because wit-cms stores its content in flat files instead of a database, it does not and can not natively support a reader commeting system. If you'd like to enable commenting on your blog, consider using Disqus or isso.

Security

wit-cms neither implements administrative access controls, nor requires a database back-end. As such, it is immune to many classes of attacks to which other content-management systems may be vulnerable.

It is not "hack proof", however. Its attack-surface consists (at least) of:

  1. Inputs that write to the DOM (search boxes, URLs, etc.)
  2. The attack-surface of Express
  3. The attack-surface of nodejs

As a defense against Cross-Site Scripting attacks, wit-cms internally relies on the xss module to sanitize user inputs that may be written back to the DOM. Regardless, it is still prudent to use a templating engine (ejs, hogan, etc.) when authoring views.

Lastly - though this should go without saying - the node application should never be run as root.

Upgrading

[email protected] is backwards-incompatible with prior versions. See the wiki for upgrading instructions.

License

wit-cms is released under the MIT license. See LICENSE.txt for details.