Commandbox-jasper Part Deux
Continuing development on commandbox-jasper cfml commandboxJuly 5, 2022 / Robert Zehnder
Photo by Kaitlyn Baker on Unsplash
I just completed the first iteration of commandbox-jasper, a CommandBox module for generating static sites, and showed what I had to my SSG expert. He asked if it could handle any file structure or if it was tied to the blog format.
I was honest, "Yeah, you are kind of locked in the the blog format at the moment."
He suggested I take a look at how 11ty handles things and try to emulate what they do. That is just what I did.
I started cleaning jasper-cli. The eleveny-base-blog seemed like a great place to start so I began reorganizing jasper's directory structure.
The jasperconfig.json
file has been moved into the _data
folder. Any data files generated by the build process will also be stored here.
The assets/
folder in the root will be copied to the _site
folder at build, but that functionality has not been added yet.
The ColdFusion files used to generate the static content have been moved to the _includes
directory. I have a very basic layout/view system working with Jasper. If no layout is specified it will default to the main
layout.
It is now also possible to use CFML files as templates. You can specify front matter in a CFML file by adding a ColdFusion comment on the first line of the file. The front matter values will be available in the prc
scope on the page. Here is an example adding setting YAML in a ColdFusion comment.
<!---
layout: main
something: else
weird:
- an
- array
- of
- stuff
--->
<cfoutput>
<div class="container">
<cfloop array="#prc.posts#" index="i">
<a href="/posts/#i.slug#">#i.title#</a><br />
</cfloop>
</div>
<cfdump var="#prc#" />
</cfoutput>
Here we can see the results.
There are two markdown files in the posts/
folder to getting started, but the new jasper build
looks for any valid template in the root directory and subdirectories (currently .md and.cfm files), attempts to read the front matter from each file, and write the HTML to disk. Special directorys such as _data
and _includes
are ignored.
component extends="commandbox.system.BaseCommand" {
property name="JasperService" inject="JasperService@commandbox-jasper";
function run() {
command( "jasper cache build" ).run();
var conf = deserializeJSON( fileRead( resolvePath( "_data/jasperconfig.json" ), "utf-8" ) );
var posts = deserializeJSON( fileRead( resolvePath( "_data/post-cache.json" ), "utf-8" ) );
var tags = JasperService.getTags( posts );
var rootDir = resolvePath( "." );
rootDir = left( rootDir, len( rootDir ) - 1 )
print.line( "Building source directory: " & rootDir );
var templateList = JasperService.list( rootDir );
templateList.each( ( template ) => {
var fragment = "";
var content = "";
var renderedHTML = "";
var isCFM = template.name.findNoCase( ".cfm" ) ? true : false;
var prc = {
"meta" : {},
"content" : "",
"tagCloud" : tags,
"type" : "page",
"posts" : posts
};
prc.append( conf );
// Try reading the front matter from the template
prc.append( JasperService.getPostData( fname = template.directory & "/" & template.name ) );
// render the view
if ( prc.keyExists( "type" ) && prc.type == "page" ) {
if ( isCFM ) {
// we are rending a CFM file, just include it
savecontent variable="fragment" {
include resolvePath( template.directory & "/" & template.name );
}
} else {
// use the page template
savecontent variable="fragment" {
include resolvePath( "_includes/page.cfm" );
}
}
} else {
// use the post template
savecontent variable="fragment" {
include resolvePath( "_includes/post.cfm" );
}
}
// content is referenced in the layout
content = fragment;
// render the layout
savecontent variable="fragment" {
include resolvePath( "_includes/layouts/" & prc.layout & ".cfm" );
}
// renderedHTML is the combined view and layout
renderedHTML = fragment;
// write the rendered HTML to disk
var computedPath = template.directory.replace( rootDir, "" );
try {
directoryCreate( resolvePath( "_site" & computedPath ) );
print.line( "Creating " & resolvePath( "_site" & computedPath ) );
} catch ( any e ) {
// fail
}
if ( prc.keyExists( "type" ) && prc.type == "page" ) {
fileWrite(
resolvePath( "_site" & computedPath & "/" & listFirst( template.name, "." ) & ".html" ),
renderedHTML
);
print.line( "_site" & computedPath & "/" & listFirst( template.name, "." ) & ".html" );
} else {
print.line( "_site" & computedPath & "/" & prc.slug & ".html" );
fileWrite( resolvePath( "_site" & computedPath & "/" & prc.slug & ".html" ), renderedHTML );
}
} );
}
}
The jasper builld
command has been completely rewritten to support layouts and views, as well as handling *.cfm
files.
The default front matter has changed a bit, layout
and type
attribute are required since jasper build
uses these values. CFM files that are not in the _includes
directory should start with a CFML comment and have a layout set. It should default to main in the front matter, but it might break stuff if you do not have it for the moment.
---
layout: main
type: post
slug: getting-started
title: Getting Started
author: Jasper
description: It is pretty easy to get started with Jasper, here are some steps to help you move forward
tags:
- Jasper
- Getting Started
image: https://static.kisdigital.com/images/jasper/getting-started-00-cover.jpeg
published: true
date: 2020-05-30
---
I have really enjoyed working with CommandBox so far, the flexibility is amazing.