I'm having an issue where I have a node serve task that watches .hbs files for changes and if a change occurs triggers another node task called 'styleguide'.
This style guide build task is using the node API version of Assemble (v0.23.0).
What's happening is that over time the build task is taking longer and longer to execute until eventually falling over with an error of Out of Memory followed by a JS stacktrace.
Here is the styleguide watch part of the serve task.
const styleguideWatchFiles = [
'./src/templates/layouts/styleguide.hbs',
'./src/templates/styleguide/**/*.hbs',
'./src/components/styleguide/**/*.hbs'
];
//watch STYLEGUIDE
chokidar.watch(styleguideWatchFiles, {
ignoreInitial: true
})
.on('error', error => log.error(error))
.on('all', (event, path) => {
log.file('File Changed', path);
run(styleguide).then(() => {
browserSync.reload('*.html');
}).catch(err => {
log.error(err);
});
});
Here is the styleguide build task.
/*eslint no-console: 0 */
/**
* styleguide.js
*
* Build script for handling styleguide html templates
* using category collections in front-matter to categorise parts of styleguide
* with Assemble and Handlebars.
*
* Handlebars: http://handlebarsjs.com/
* Assemble: https://github.com/assemble/assemble
*
*/
import assemble from 'assemble';
import yaml from 'js-yaml';
import plumber from 'gulp-plumber';
import log from './utils/log';
import getPageData from './utils/getPageData';
import renameExt from './utils/renameExtension';
import expand from './utils/expandMatter';
import { styleguidePathConfig as path } from '../config';
export default function styleguide() {
return new Promise( (resolve, reject) => {
// Create assemble instance
let templates = assemble();
templates.dataLoader('yml', function(str) {
return yaml.safeLoad(str);
});
templates.data(path.data);
templates.preRender(/\.(hbs|html)$/, expand(templates));
// Create styleguide pages
templates.task('preload', (cb) => {
// templates.task('styleguide', () => {
templates.partials(path.sgPartials);
templates.layouts(path.layouts);
// Register helpers
templates.helpers(path.helpers);
// Add pages
templates.pages(path.sgPages);
// Styleguide page data - used for building dynamic menus
templates.data({
coreItems: getPageData('./src/templates/styleguide/core-elements'),
componentItems: getPageData('./src/templates/styleguide/components'),
generalItems: getPageData('./src/templates/styleguide/general'),
sectionItems: getPageData('./src/templates/styleguide/sections')
});
cb();
});
templates.task('styleguide', ['preload'], () => {
// Render out the template files to 'dist/styleguide'
return templates.toStream('pages')
// TODO: Because assemble is based on gulp/node streams there's not an easy way to find template errors so we're relying on gulp-plumber to do this for us.
// We define our own handler for more error information.
.pipe(plumber({
errorHandler: err => {
// If we encounter this error on a build task, kill the promise
if (process.argv.includes('build')) return reject(err);
// log.error(`${err.message}: ${err.path.split('/').pop().split('\\').pop()}.`);
log.error(`${err.message} in ${err.path}.`);
}
}))
.pipe(templates.renderFile())
.pipe(plumber.stop())
.pipe(renameExt())
.pipe(templates.dest('dist/styleguide'));
});
// Run the Assemble build methods
templates.build('styleguide', err => {
if (err) return reject(err);
return resolve();
});
});
}
The getPageData just loops over the specified folder and builds an array of objects to be used by handlebars template to build out a dynamic menu based on the pages being compiled.
So my question is what's causing the memory leak?
Is is that every time the styleguide.js task is called on change the assemble() instance is not being garbage collected after the resolve is returned?
Do I need to be running the entire thing on watch; calling the 'preload' & styleguide tasks?
Thanks for reading.
via Tom Gillard
No comments:
Post a Comment