diff --git a/core/lib/changes_hunter.js b/core/lib/changes_hunter.js index 0e51e6e0d..9d1d31683 100644 --- a/core/lib/changes_hunter.js +++ b/core/lib/changes_hunter.js @@ -27,13 +27,23 @@ ChangesHunter.prototype = { let renderedTemplatePath = patternlab.config.paths.public.patterns + pattern.getPatternLink(patternlab, 'rendered'); + //write the compiled template to the public patterns directory + let markupOnlyPath = + patternlab.config.paths.public.patterns + pattern.getPatternLink(patternlab, 'markupOnly'); + if (!pattern.compileState) { pattern.compileState = CompileState.NEEDS_REBUILD; } try { - // Prevent error message if file does not exist - fs.accessSync(renderedTemplatePath, fs.F_OK); + + // renderedTemplatePath required to display a single element + // Markup only is required for "View All" pages. It will get loaded later on. + // If any of these is missing, mark pattern for recompile + [renderedTemplatePath, markupOnlyPath].forEach(renderedFile => + // Prevent error message if file does not exist + fs.accessSync(renderedFile, fs.F_OK) + ); let outputLastModified = fs.statSync(renderedTemplatePath).mtime.getTime(); if (pattern.lastModified && outputLastModified > pattern.lastModified) { @@ -76,6 +86,13 @@ ChangesHunter.prototype = { // Ignore, not a regular file } } + }, + + needsRebuild: function(lastModified, p) { + if (p.compileState !== CompileState.CLEAN || ! p.lastModified) { + return true; + } + return p.lastModified >= lastModified; } }; diff --git a/core/lib/pattern_assembler.js b/core/lib/pattern_assembler.js index bfd2c927b..b85867d88 100644 --- a/core/lib/pattern_assembler.js +++ b/core/lib/pattern_assembler.js @@ -1,6 +1,7 @@ "use strict"; var path = require('path'), + _ = require('lodash'), fs = require('fs-extra'), Pattern = require('./object_factory').Pattern, CompileState = require('./object_factory').CompileState, @@ -406,13 +407,40 @@ var pattern_assembler = function () { decomposePattern(currentPattern, patternlab); } - function findModifiedPatterns(lastModified, patternlab) { - return patternlab.patterns.filter(p => { - if (p.compileState !== CompileState.CLEAN || ! p.lastModified) { - return true; + + /** + * Finds patterns that were modified and need to be rebuilt. For clean patterns load the already + * rendered markup. + * + * @param lastModified + * @param patternlab + */ + function markModifiedPatterns(lastModified, patternlab) { + /** + * If the given array exists, apply a function to each of its elements + * @param {Array} array + * @param {Function} func + */ + const forEachExisting = (array, func) => { + if (array) { + array.forEach(func); } - return p.lastModified >= lastModified; + }; + const modifiedOrNot = _.groupBy( + patternlab.patterns, + p => changes_hunter.needsRebuild(lastModified, p) ? 'modified' : 'notModified'); + + // For all unmodified patterns load their rendered template output + forEachExisting(modifiedOrNot.notModified, cleanPattern => { + const xp = path.join(patternlab.config.paths.public.patterns, cleanPattern.getPatternLink(patternlab, 'markupOnly')); + + // Pattern with non-existing markupOnly files were already marked for rebuild and thus are not "CLEAN" + cleanPattern.patternPartialCode = fs.readFileSync(xp, 'utf8'); }); + + // For all patterns that were modified, schedule them for rebuild + forEachExisting(modifiedOrNot.modified, p => p.compileState = CompileState.NEEDS_REBUILD); + return modifiedOrNot; } function expandPartials(foundPatternPartials, list_item_hunter, patternlab, currentPattern) { @@ -528,8 +556,8 @@ var pattern_assembler = function () { } return { - find_modified_patterns: function (lastModified, patternlab) { - return findModifiedPatterns(lastModified, patternlab); + mark_modified_patterns: function (lastModified, patternlab) { + return markModifiedPatterns(lastModified, patternlab); }, find_pattern_partials: function (pattern) { return pattern.findPartials(); diff --git a/core/lib/patternlab.js b/core/lib/patternlab.js index 4a0726cfd..ab2f29258 100644 --- a/core/lib/patternlab.js +++ b/core/lib/patternlab.js @@ -564,12 +564,7 @@ var patternlab_engine = function (config) { // TODO Find created or deleted files let now = new Date().getTime(); - let modified = pattern_assembler.find_modified_patterns(now, patternlab); - - // First mark all modified files - for (let p of modified) { - p.compileState = CompileState.NEEDS_REBUILD; - } + pattern_assembler.mark_modified_patterns(now, patternlab); patternsToBuild = patternlab.graph.compileOrder(); } else { // build all patterns, mark all to be rebuilt diff --git a/test/pattern_assembler_tests.js b/test/pattern_assembler_tests.js index e3dc5bdfe..fa1cf92d2 100644 --- a/test/pattern_assembler_tests.js +++ b/test/pattern_assembler_tests.js @@ -14,6 +14,9 @@ function emptyPatternLab() { } } +const patterns_dir = './test/files/_patterns'; +const public_dir = './test/public'; + tap.test('process_pattern_recursive recursively includes partials', function(test) { //tests inclusion of partial that will be discovered by diveSync later in iteration than parent @@ -23,8 +26,6 @@ tap.test('process_pattern_recursive recursively includes partials', function(tes var pa = require('../core/lib/pattern_assembler'); var plMain = require('../core/lib/patternlab'); var pattern_assembler = new pa(); - var patterns_dir = './test/files/_patterns'; - var public_dir = './test/public'; var patternlab = emptyPatternLab(); patternlab.config = fs.readJSONSync('./patternlab-config.json'); patternlab.config.paths.source.patterns = patterns_dir; @@ -662,14 +663,24 @@ tap.test('addPattern - adds pattern template to patternlab partial object if ext test.end(); }); -tap.test('findModifiedPatterns - finds patterns modified since a given date', function(test){ +tap.test('markModifiedPatterns - finds patterns modified since a given date', function(test){ + const fs = require('fs-extra'); + // test/myModule.test.js + var rewire = require("rewire"); + + var pattern_assembler_mock = rewire("../core/lib/pattern_assembler"); + var fsMock = { + readFileSync: function (path, encoding, cb) { + return ""; + } + }; + pattern_assembler_mock.__set__("fs", fsMock); //arrange - var pattern_assembler = new pa(); + var pattern_assembler = new pattern_assembler_mock(); var patternlab = emptyPatternLab(); - patternlab.partials = {}; - patternlab.data = {link: {}}; - patternlab.config = { debug: false }; - patternlab.config.outputFileSuffixes = {rendered : ''}; + patternlab.config = fs.readJSONSync('./patternlab-config.json'); + patternlab.config.paths.public.patterns = public_dir + "/patterns"; + patternlab.config.outputFileSuffixes = {rendered: '', markupOnly: '.markup-only'}; var pattern = new Pattern('00-test/01-bar.mustache'); pattern.extendedTemplate = undefined; @@ -681,17 +692,19 @@ tap.test('findModifiedPatterns - finds patterns modified since a given date', fu patternlab.patterns = [pattern]; var lastCompilationRun = new Date("2016-01-01").getTime(); - var p = pattern_assembler.find_modified_patterns(lastCompilationRun, patternlab); + var modifiedOrNot = pattern_assembler.mark_modified_patterns(lastCompilationRun, patternlab); - test.same(p.length, 1, "The pattern was modified after the last compilation"); + test.same(modifiedOrNot.modified.length, 1, "The pattern was modified after the last compilation"); + // Reset the compile state as it was previously set by pattern_assembler.mark_modified_patterns + pattern.compileState = CompileState.CLEAN; lastCompilationRun = new Date("2016-12-31").getTime(); - p = pattern_assembler.find_modified_patterns(lastCompilationRun, patternlab); - test.same(p.length, 0, "Pattern was already compiled and hasn't been modified since last compile"); + modifiedOrNot = pattern_assembler.mark_modified_patterns(lastCompilationRun, patternlab); + test.same(modifiedOrNot.notModified.length, 1, "Pattern was already compiled and hasn't been modified since last compile"); test.end(); -}) +}); -tap.test('findModifiedPatterns - finds patterns when modification date is missing', function(test){ +tap.test('markModifiedPatterns - finds patterns when modification date is missing', function(test){ //arrange var pattern_assembler = new pa(); var patternlab = emptyPatternLab(); @@ -706,13 +719,13 @@ tap.test('findModifiedPatterns - finds patterns when modification date is missin pattern.lastModified = undefined; patternlab.patterns = [pattern]; - let p = pattern_assembler.find_modified_patterns(1000, patternlab); - test.same(p.length, 1); + let p = pattern_assembler.mark_modified_patterns(1000, patternlab); + test.same(p.modified.length, 1); test.end(); }); // This is the case when we want to force recompilation -tap.test('findModifiedPatterns - finds patterns via compile state', function(test){ +tap.test('markModifiedPatterns - finds patterns via compile state', function(test){ //arrange var pattern_assembler = new pa(); var patternlab = emptyPatternLab(); @@ -728,8 +741,8 @@ tap.test('findModifiedPatterns - finds patterns via compile state', function(tes pattern.compileState = CompileState.NEEDS_REBUILD; patternlab.patterns = [pattern]; - let p = pattern_assembler.find_modified_patterns(1000, patternlab); - test.same(p.length, 1); + let p = pattern_assembler.mark_modified_patterns(1000, patternlab); + test.same(p.modified.length, 1); test.end(); });