Skip to content

Instantly share code, notes, and snippets.

@ebanisadr
Created May 25, 2020 00:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ebanisadr/891f686ffbc09947bbcbfc0270c7225b to your computer and use it in GitHub Desktop.
Save ebanisadr/891f686ffbc09947bbcbfc0270c7225b to your computer and use it in GitHub Desktop.
Simple Javascript SSG
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const compile = require('./compiler');
const inputDir = 'content';
const outputDir = 'stage';
let overrides = {};
if (process.argv[2] === 'dev') {
overrides.baseurl = path.join(__dirname, outputDir) + '/';
}
function processFile(file) {
console.log('Processing:', file);
let extension = file.substring(file.lastIndexOf('.') + 1);
switch (extension) {
case 'md':
return {
path: file.replace(inputDir, outputDir).replace(/md$/, 'html'),
content: compile(file, overrides)
};
case'html':
return {
path: file.replace(inputDir, outputDir),
content: compile(file, overrides)
};
case 'css':
return {
path: file.replace(inputDir, outputDir),
content: fs.readFileSync(file, { encoding: 'utf-8' })
};
case 'jpg':
case 'png':
case 'pdf':
return {
path: file.replace(inputDir, outputDir),
content: fs.readFileSync(file)
}
default:
return undefined;
}
}
function processDir(dir) {
let contents = fs.readdirSync(dir);
let files = contents
.filter((name) => !fs.lstatSync(path.join(dir, name)).isDirectory());
let folders = contents
.filter((name) => fs.lstatSync(path.join(dir, name)).isDirectory());
files.forEach((file) => {
let output = processFile(path.join(dir, file));
if (output) {
console.log('Writing:', output.path);
fs.writeFileSync(output.path, output.content);
} else {
console.log('Unhandled file:', path.join(dir, file));
}
});
folders.forEach((folder) => {
let loc = path.join(dir, folder);
console.log('Making directory:', loc.replace(inputDir, outputDir));
fs.mkdirSync(loc.replace(inputDir, outputDir));
processDir(loc);
})
}
processDir('./content');
const path = require('path');
const hljs = require('highlight.js');
const yaml = require('js-yaml');
const mustache = require('mustache');
const fs = require('fs');
const md = require('markdown-it')({
html: true,
xhtmlOut: true,
breaks: false,
langPrefix: '',
linkify: true,
typographer: true,
quotes: '“”‘’',
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(lang, str).value;
} catch (e) {
console.err(e);
return '';
}
}
}
}).use(require('markdown-it-sub'))
.use(require('markdown-it-sup'))
.use(require('markdown-it-abbr'))
.use(require('markdown-it-footnote'))
.use(require('markdown-it-container'), 'warning');
// Consider: markdown-it-texmath
hljs.configure({
tabReplace: ' ',
//useBR: true;
classPrefix: ''
});
// Loads the files in the given directory into an object with this structure
// { file: 'file content' }
// where file is the filename without its extension
function loadDir(dir) {
return files = fs.readdirSync(dir)
.filter((filename) => !fs.lstatSync(path.join(dir, filename)).isDirectory())
.map((filename) => {
let name = filename.substring(0, filename.indexOf('.'));
let content = fs.readFileSync(path.join(dir, filename), { encoding: 'utf-8' });
let obj = {};
obj[name] = content;
return obj;
})
.reduce((name, partial) => Object.assign(name, partial), {});
}
// Load sitewide variables
const site = require('./site.json');
let templates = loadDir(site.templatesDir);
let partials = loadDir(site.partialsDir);
function compileMarkdown(filePath, siteOverrides) {
if (!fs.existsSync(filePath)) {
throw new Error("File not found: " + filePath);
}
const fileText = fs.readFileSync(filePath, { encoding: 'utf-8' });
let yamlEnd = fileText.indexOf('---', 4);
let fileYaml = yaml.load(fileText.substring(0, yamlEnd));
let fileMarkdown = fileText.substring(yamlEnd + 4);
let config = fileYaml;
config.site = site;
if (siteOverrides) {
Object.assign(config.site, siteOverrides);
}
let content = md.render(fileMarkdown);
let template = templates[config.template.toLowerCase()];
let vars = config;
vars.content = content;
return mustache.render(template, vars, partials);
}
function compileHtml(filePath, siteOverrides) {
if (!fs.existsSync(filePath)) {
throw new Error("File not found: " + filePath);
}
const fileText = fs.readFileSync(filePath, { encoding: 'utf-8' });
let config = { site: site };
if (siteOverrides) {
Object.assign(config.site, siteOverrides);
}
return mustache.render(fileText, config, partials);
}
module.exports = function compile(filePath, siteOverrides) {
switch (filePath.substring(filePath.lastIndexOf('.'))) {
case '.md':
return compileMarkdown(filePath, siteOverrides);
case '.html':
return compileHtml(filePath, siteOverrides);
default:
console.log("Don't know how to compile file:", filePath);
return '';
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment