Look Ma, no CMS!

By  on  

I hate complexity. And when I say hate I really mean it. When you build websites several years, you start realizing that the simplicity is your best friend. As simple one system is as easy is to develop and maintain it. Nowadays, every user wants to control the content in its online appearance. For me, as a blogger, is important to work with good looking, fast and reliable CMS. The writing is difficult as its own, and if the process is tough the whole experience is not very good.

At the moment, if I want to publish an article on my blog I have to open the administration of my custom PHP CMS and make a new entry. However, I'm not happy with writing the content there, and I prepare the posts in Markdown format. When I'm ready, I transform the Markdown to HTML and publish it to the site. All the things written by me are stored in GitHub repositories.

So, as you can see, there are several steps that I have to follow before publishing something. Sometimes I'm just too lazy to do it, and I simply don't blog. Last few months I'm thinking about changing the way of how I write. I need something new and interesting that will replace the old LAMP system. I read few articles about flat file content management systems, and I decided to invest some time in developing such on top of Node.js. While I was working on the documentation of AbsurdJS, I made a short Node.js script that uses Gulp to convert Markdown to HTML. I like how everything works and decided to take this direction.

The new toy

Two days (and nights) later and Techy was born. That's a Node.js module that have all the characteristics of a simple flat CMS which I needed.

  • Simplicity - simply drop a markdown file and execute techy command. The module converts all the .md files into .html pages.
  • Predefined design - Techy copies the needed CSS and JavaScript (if any) into the root folder of the project.
  • Theming - of course, as every other CMS, it offers the usage of different themes. So you are able to change the main layout, the styles, the fonts, everything.
  • Partials support - along with the Markdown syntax you are able to write Techy expressions. In fact, this is just the good old JavaScript between <% and %> markers. There are some predefined methods and variables which are available. One of them is the template function. It accepts a relative path to HTML file.
  • Plain HTML support - sometimes the Markdown format is not enough. In such cases, the CMS should support adding of plain HTML.
  • Relation between the different pages - that's pretty important feature. In the popular solutions like WordPress, for example, information like date of creation or post's author is kept in the database. However, we do not have a database here. So, such information should be written directly into the pages. I found that this pretty useful approach, because it tights the characteristics of the article to its content.
  • Code syntax highlighter and icon font

Let's try it

Before to start using Techy, you need to install it.

npm install -g techy

The command will setup the library as a global command line tool. Create a new folder somewhere and add the following page.md file:

# That's a test page

Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Autem, maiores, ipsa, quos ratione consectetur facilis.

Navigate to the same directory, type techy and press Enter. You should see the following screen.

Techy

Techy generates page.html next to your page.md file. Along with that it brings new folder themes. It contains the main HTML layout, the CSS styles and the JavaScript (if any) code needed for your page. Techy has Prism and FontAwesome integrated. So you are able to publish code and use cool icons without additional setup. And because the CMS uses Gulp it automatically starts listening for changes in your Markdown files.

The content of page.html should be:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Techy</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="themes/default/public/font-awesome-4.0.3/css/font-awesome.min.css">
    <link rel="stylesheet" href="themes/default/public/styles.css">
    <link rel="stylesheet" href="themes/default/public/prism/prism.css" />
    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Open+Sans:400,800,700' type='text/css'>
</head>
<body>
    <div class="content">
        <h1 id="that-s-a-test-page">That's a test page</h1>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem, maiores, ipsa, quos ratione consectetur facilis.</p>
    </div>
    <script src="themes/default/public/prism/prism.js"></script>
    <script src="themes/default/public/scripts.js"></script>
</body>
</html>

Techy takes care for the boring stuff and leaves your file clean. The HTML that your content is put in is defined in themes/default/tpl/layouts/basic.html. You may change it to something else by using the following expression:

// it's looking in 
// themes/[theme name]/tpl directory
<% set('layout', 'layouts/mylayout.html') %>

You could even use your own theme. Just call the techy command with the following parameter:

techy --theme mythemename

Have in mind that the module is dealing with the paths in your files. Even if you have a deeply nested files the URLs of the CSS styles and JavaScript files will be set properly.

Now, to make the things a little bit more interesting, let's create a custom Techy function which returns a setting defined in another page. In order to do this, we need a new Markdown file. Create profile.md and put the following text inside:

<% set('name', 'profile') %>
<% set('profile', { name: 'John Black', job: 'web developer'}) %>

Hello, I'm <% get('profile').name %> and 
I'm working as <% get('profile').job %>.
This is my profile page.

set creates property in the current page and assigns a value to it. The same value could be fetched with the get method. Now, to define a new method like get or set we have to create a JavaScript file which name ends on techy.js. For example getprofile.techy.js.

module.exports = function() {
    var profilePage = this.page('profile');
    return profilePage.get('profile');
}

The this keyword inside the function's body points to the page that is running the method. this.page is a predefined function which accepts a name of the page. And because we defined profile property in profile.md we are now able to get its value and return it. If we update page.md with the following code:

# That's a test page

* Name: <% getprofile().name %>
* Job: <% getprofile().job %>

the result will be:

<h1 id="that-s-a-test-page">That's a test page</h1>
<ul>
    <li>Name: John Black</li>
    <li>Job: web developer</li>
</ul>

There is also pages function that returns and array of all the pages in the project. So, in theory we are able to implement whatever we need, because we have access to every single page and its defined properties.

Why you should consider the usage of flat file CMS like Techy

I could see three big benefits:

  • No database - this means that the overall page load will be reduced dramatically. You are serving only static HTML files.
  • No additional setup - you just need the files uploaded. There is no back-end technology involved. You may generate the HTML locally.
  • Super fast and easy migration - there are no configurations or database dumps for importing

Summary

Techy is an open source project available at GitHub. Its repository is located here. Feel free to fork it and make modifications, new functions or themes. I'll be happy to push the module forward.

The official page of the tool krasimir.github.io/techy is also generated with Techy. The code could be seen here.

Krasimir Tsonev

About Krasimir Tsonev

Krasimir Tsonev is a coder with over ten years of experience in web development. With a strong focus on quality and usability, he is interested in delivering cutting edge applications. Currently, with the rise of the mobile development, Krasimir is enthusiastic to work on responsive applications targeted to various devices. Living and working in Bulgaria, he graduated at the Technical University of Varna with a bachelor and master degree in computer science. If you'd like to stay up to date on his activities, refer to his blog or follow him on Twitter.

Recent Features

  • By
    5 HTML5 APIs You Didn&#8217;t Know Existed

    When you say or read "HTML5", you half expect exotic dancers and unicorns to walk into the room to the tune of "I'm Sexy and I Know It."  Can you blame us though?  We watched the fundamental APIs stagnate for so long that a basic feature...

  • By
    JavaScript Promise API

    While synchronous code is easier to follow and debug, async is generally better for performance and flexibility. Why "hold up the show" when you can trigger numerous requests at once and then handle them when each is ready?  Promises are becoming a big part of the JavaScript world...

Incredible Demos

  • By
    Using Opacity to Show Focus with MooTools

    I'm a huge fan of using subtle effects like link nudging (jQuery, MooTools) to enhance the user experience and increase the perceived dynamism of my websites. Trust me -- a lot of little things are what take websites to the next level.

  • By
    iPhone Checkboxes Using MooTools

    One of the sweet user interface enhancements provided by Apple's iPhone is their checkbox-slider functionality. Thomas Reynolds recently released a jQuery plugin that allows you to make your checkboxes look like iPhone sliders. Here's how to implement that functionality using the beloved...

Discussion

  1. Markus

    since you already do all the stuff on github, why don’t you use github pages?

    https://pages.github.com/

  2. Actually I’m using github pages for some things, but for my personal blog I prefer to be on its own domain.

  3. Markus

    even this is possible with a CNAME file, see
    https://help.github.com/articles/setting-up-a-custom-domain-with-pages

    Nevertheless your article describes a good alternative with its own pros and cons. Therefore thanks, enjoyed reading it.

  4. outrunthewolf

    Why didn’t you just use Jekyll?

  5. outrunthewolf: as far as I can see Jekyll doesn’t offer that level of programming. I needed something much more flexible. In Techy every page is like a JavaScript class and could have properties, methods and so on.

  6. @Markus: ha … I didn’t know that this is possible. I’ll use it probably with some of my existing projects.

  7. Pedro Perez

    Hi,
    Why is not working? I do all but i get “env: node\r: No such file or directory”
    What i am doing wrong?

  8. Hm … strange. What is your node’s version.
    P.S.
    I’ll suggest to post an issue here https://github.com/krasimir/techy/issues so we don’t flood this comments thread with q/a.

  9. My Javascript bootstraper structureJS keeps things much more simple than requireJS and adds some nice features like minification using your browser. Give it a try on your next app. Get it here: https://github.com/ShamariFeaster/structureJS

  10. Abhisekh

    Hi Krasimir,

    I am using markdown to generate static website templates. The content will be read from markdown and html will be generated accordingly.
    Problem statement is, I have different sections in websites (like services, contact us , work we do etc..). Each section will have its own markdown, css and animations.I am looking forward to generate individual md files then combine all templates files into one file and have the final website.html. What feature of techy will help me write individuals md and have a layout with different div for each getContent

  11. Miroslav

    It’s seems that windows 7 need additional nodejs packages for techy to work correct after install. After executing techy command in nodejs command prompt, only file created is _dist/test.html based on the already created test.md file – no adittional files are created for some reason – no javascript or theme files.This is after techy command executed:

    +Pages comleted
    Techy is listening for changes

  12. choice of nodejs is very unfortunate – all I needed was a tool that works, now it pushes me down the rabbit hole of ‘that dependency conflicts with that dependency, run this tool. no, still broken, run this tool….’. It supposed to be easy.

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!