Skip to content

Commit

Permalink
Live reload support for md and layouts
Browse files Browse the repository at this point in the history
  • Loading branch information
astronomersiva committed Aug 1, 2018
1 parent fe31a5c commit 89202ba
Show file tree
Hide file tree
Showing 12 changed files with 1,290 additions and 155 deletions.
2 changes: 2 additions & 0 deletions lib/lego.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const chalk = require('chalk');

const Site = require('./site');
const runTask = require('./utils/runTask');
const watch = require('./utils/watch');

module.exports = async function(args) {
try {
Expand All @@ -24,6 +25,7 @@ module.exports = async function(args) {
const [task] = args;
if (['s', 'server'].includes(task)) {
await runTask(server, site);
watch(site, runTask);
} else {
await runTask(build, site);
}
Expand Down
88 changes: 49 additions & 39 deletions lib/site.js
Original file line number Diff line number Diff line change
@@ -1,70 +1,80 @@
const path = require('path');
const fs = require('fs-extra');
const findUp = require('find-up');
const markdownIt = require('markdown-it');
const markdownItContainer = require('markdown-it-container');
const frontMatter = require('markdown-it-front-matter');

const filterFileList = require('./utils/filterFileList');
const yamlToObject = require('./utils/yamlToObject');

const { POSTS, LAYOUTS } = require('./utils/constants');

let _post = {};

const mdOptions = {
html: true
};

const md = markdownIt(mdOptions)
.use(frontMatter, function(fm) {
_post = yamlToObject(fm);
})
.use(markdownItContainer, 'include', {
validate: function(params) {
return params.endsWith(':::') && params.includes('include');
},

render: function(tokens, idx) {
let statement = tokens[idx];
if (statement.type === 'container_include_open') {
let [, elements] = statement.info.trim().split(' ');
return fs.readFileSync(`${LAYOUTS}/${elements}`).toString();
}

return '';
}
});
const generateHtmlFromMd = require('./utils/generateHtmlFromMd');
const { BUILD, POSTS } = require('./utils/constants');

class Site {
constructor() {
this._posts = [];
this._tags = [];

const configFile = findUp.sync('lego.js');
let configFile = findUp.sync('lego.js');
if (!configFile) {
// ignore for now
// throw new Error('lego.js not found. Are you sure this is a lego project?');
}

this._config = require(configFile);

const posts = fs.readdirSync(POSTS);
const filteredPages = filterFileList(posts, 'md');
let posts = fs.readdirSync(POSTS);
let filteredPages = filterFileList(posts, 'md');

for (const post of filteredPages) {
const pageContents = fs.readFileSync(`${POSTS}/${post}`).toString();
const renderedMarkdown = md.render(pageContents);
let pageContents = fs.readFileSync(`${POSTS}/${post}`).toString();
let { html, meta } = generateHtmlFromMd(pageContents);
let postData = Object.assign({
path: path.parse(post).name,
html: renderedMarkdown
}, _post);
html
}, meta);

this._posts.push(postData);
this._tags = this._tags.concat(postData.tags || []);
}
}

populateTags() {
let tags = [];
let posts = this._posts || {};
for (const post of posts) {
tags = tags.concat(post.tags || []);
}

this._tags = [...tags];
}

async handlePostChange(event, post) {
let postName = path.parse(post).name;
if (event === 'unlink') {
this._posts = this._posts.filter(post => post.path !== postName);
this.populateTags();

await fs.remove(`${BUILD}/${postName}`);
}

if (['add', 'change'].includes(event)) {
let pageContents = fs.readFileSync(post).toString();
let { html, meta } = generateHtmlFromMd(pageContents);
let postData = Object.assign({
path: postName,
html
}, meta);

if (event === 'add') {
this._posts.push(postData);
} else {
let changedPostIndex = this._posts
.findIndex(element => element.path === postName);

this._posts[changedPostIndex] = postData;
}

this.populateTags();
}
}

getPosts() {
// node-liquid is directly manipulating the params passed.
// This causes pages to break. As a workaround, pass a new copy each time.
Expand Down
2 changes: 1 addition & 1 deletion lib/tasks/copyMajorStaticAssets.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const uglifyJS = require('uglify-es');
const filterFileList = require('../utils/filterFileList');
const { STATIC, BUILD } = require('../utils/constants');

module.exports = async function() {
module.exports = async function(site, options) {
try {
let assets = glob.sync(`${STATIC}/+(js|css)/**/*`);
assets = filterFileList(assets, ['js', 'css']);
Expand Down
16 changes: 8 additions & 8 deletions lib/tasks/generatePages.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,26 @@ const { PAGES, BUILD } = require('../utils/constants');

module.exports = async function(site) {
try {
const posts = site.getPosts();
const pages = fs.readdirSync(PAGES);
const filteredPages = filterFileList(pages, 'html')
let posts = site.getPosts();
let pages = fs.readdirSync(PAGES);
let filteredPages = filterFileList(pages, 'html')
.filter(page => page !== '404.html');

for (const page of filteredPages) {
const pageContents = fs.readFileSync(`${PAGES}/${page}`).toString();
const htmlPath = `${BUILD}/${path.parse(page).name}`;
let pageContents = fs.readFileSync(`${PAGES}/${page}`).toString();
let htmlPath = `${BUILD}/${path.parse(page).name}`;
fs.mkdirp(htmlPath);

const renderedHtml = await generateHtmlFromLiquid(pageContents, { posts });
let renderedHtml = await generateHtmlFromLiquid(pageContents, { posts });
fs.writeFileSync(`${htmlPath}/index.html`, renderedHtml);
}

// copy index/index.html to index.html also
fs.copySync(`${BUILD}/index/index.html`, `${BUILD}/index.html`);

// generate 404 page
const pageContents = fs.readFileSync(`${PAGES}/404.html`).toString();
const renderedHtml = await generateHtmlFromLiquid(pageContents, { posts });
let pageContents = fs.readFileSync(`${PAGES}/404.html`).toString();
let renderedHtml = await generateHtmlFromLiquid(pageContents, { posts });
fs.writeFileSync(`${BUILD}/404.html`, renderedHtml);
} catch (error) {
throw error;
Expand Down
10 changes: 5 additions & 5 deletions lib/tasks/generatePagesForTags.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ const { BUILD, LAYOUTS } = require('../utils/constants');

module.exports = async function(site) {
try {
const baseTemplate = fs.readFileSync(`${LAYOUTS}/tag.html`).toString();
const tags = [...new Set(site.getTags())];
const posts = site.getPosts();
let baseTemplate = fs.readFileSync(`${LAYOUTS}/tag.html`).toString();
let tags = [...new Set(site.getTags())];
let posts = site.getPosts();

for (const tag of tags) {
const htmlPath = `${BUILD}/tag/${tag}`;
let htmlPath = `${BUILD}/tag/${tag}`;
fs.mkdirp(htmlPath);

const renderedHtml = await generateHtmlFromLiquid(baseTemplate, { posts, tag });
let renderedHtml = await generateHtmlFromLiquid(baseTemplate, { posts, tag });
fs.writeFileSync(`${htmlPath}/index.html`, renderedHtml);
}
} catch (error) {
Expand Down
8 changes: 4 additions & 4 deletions lib/tasks/generatePostsFromMarkdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ const { BUILD, LAYOUTS } = require('../utils/constants');

module.exports = async function(site) {
try {
const baseTemplate = fs.readFileSync(`${LAYOUTS}/post.html`).toString();
const posts = site.getPosts();
let baseTemplate = fs.readFileSync(`${LAYOUTS}/post.html`).toString();
let posts = site.getPosts();
for (const post of posts) {
const htmlPath = `${BUILD}/${post.path}`;
let htmlPath = `${BUILD}/${post.path}`;
fs.mkdirp(htmlPath);

const renderedHtml = await generateHtmlFromLiquid(baseTemplate, { post });
let renderedHtml = await generateHtmlFromLiquid(baseTemplate, { post });
fs.writeFileSync(`${htmlPath}/index.html`, renderedHtml);
}
} catch (error) {
Expand Down
2 changes: 1 addition & 1 deletion lib/tasks/generateSiteMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = async function(site) {
hostname: siteConfig.domain
};

const siteMapForSite = sitemap.createSitemap({ options });
let siteMapForSite = sitemap.createSitemap({ options });
fs.writeFileSync(`${BUILD}/sitemap.xml`, siteMapForSite.toString());
} catch (error) {
throw error;
Expand Down
38 changes: 38 additions & 0 deletions lib/utils/generateHtmlFromMd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const fs = require('fs-extra');
const markdownIt = require('markdown-it');
const markdownItContainer = require('markdown-it-container');
const frontMatter = require('markdown-it-front-matter');

const yamlToObject = require('./yamlToObject');
const { LAYOUTS } = require('./constants');

const mdOptions = {
html: true
};

let meta = {};

const md = markdownIt(mdOptions)
.use(frontMatter, function(fm) {
meta = yamlToObject(fm);
})
.use(markdownItContainer, 'include', {
validate: function(params) {
return params.endsWith(':::') && params.includes('include');
},

render: function(tokens, idx) {
let statement = tokens[idx];
if (statement.type === 'container_include_open') {
let [, elements] = statement.info.trim().split(' ');
return fs.readFileSync(`${LAYOUTS}/${elements}`).toString();
}

return '';
}
});

module.exports = function(pageContents) {
let html = md.render(pageContents);
return { html, meta };
}
10 changes: 7 additions & 3 deletions lib/utils/runTask.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
const Logger = require('./logger');
const tasks = require('./tasks');

module.exports = async function(task, site) {
module.exports = async function(task, site, options) {
const logger = new Logger();

try {
if (!Array.isArray(task)) {
task = [task];
}

for (const taskUnit of task) {
if (Array.isArray(taskUnit)) {
let taskUnitPromises = [];
for (const parallelTask of taskUnit) {
logger.setMessage(`Running ${parallelTask}`);
taskUnitPromises.push(tasks[parallelTask](site));
taskUnitPromises.push(tasks[parallelTask](site, options));
}

await Promise.all(taskUnitPromises);
} else {
await tasks[taskUnit](site);
await tasks[taskUnit](site, options);
}
}
} catch (error) {
Expand Down
44 changes: 44 additions & 0 deletions lib/utils/watch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const chokidar = require('chokidar');

const { STATIC } = require('./constants');

module.exports = function(site, runTask) {
let postsWatcher = chokidar.watch(['posts/*md', 'posts/*html'], {
ignored: /(^|[/\\])\../,
ignoreInitial: true
});

postsWatcher.on('all', async(event, path) => {
await site.handlePostChange(event, path);
// Need to further refine this to only rebuild changed files
runTask([
'generatePostsFromMarkdown',
'generatePages',
'generatePagesForTags'
], site);
});

let layoutsWatcher = chokidar.watch('layouts/*html', {
ignored: /(^|[/\\])\../,
ignoreInitial: true
});

layoutsWatcher.on('all', () => {
// Need to further refine this to only rebuild changed files
runTask([
'generatePostsFromMarkdown',
'generatePages',
'generatePagesForTags'
], site);
});

let majorAssetsWatcher = chokidar.watch([`${STATIC}/css/**/*css`, `${STATIC}/js/**/*js`], {
ignored: /(^|[/\\])\../,
ignoreInitial: true
});

majorAssetsWatcher.on('all', async(event, path) => {
// Need to further refine this to only rebuild changed files
runTask('copyMajorStaticAssets', site, { event, path });
});
}
Loading

0 comments on commit 89202ba

Please sign in to comment.