diff --git a/Gruntfile.js b/Gruntfile.js index 2dfa9be8a..2f5dc2ad3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -15,52 +15,52 @@ module.exports = function (grunt) { banner: '/* \n * <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy") %> \n * \n * <%= pkg.author %>, and the web community.\n * Licensed under the <%= pkg.license %> license. \n * \n * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice. \n *\n */\n\n', }, patternlab: { - src: './builder/patternlab.js', - dest: './builder/patternlab.js' + src: './core/lib/patternlab.js', + dest: './core/lib/patternlab.js' }, object_factory: { - src: './builder/object_factory.js', - dest: './builder/object_factory.js' + src: './core/lib/object_factory.js', + dest: './core/lib/object_factory.js' }, lineage: { - src: './builder/lineage_hunter.js', - dest: './builder/lineage_hunter.js' + src: './core/lib/lineage_hunter.js', + dest: './core/lib/lineage_hunter.js' }, media_hunter: { - src: './builder/media_hunter.js', - dest: './builder/media_hunter.js' + src: './core/lib/media_hunter.js', + dest: './core/lib/media_hunter.js' }, patternlab_grunt: { - src: './builder/patternlab_grunt.js', - dest: './builder/patternlab_grunt.js' + src: './core/lib/patternlab_grunt.js', + dest: './core/lib/patternlab_grunt.js' }, patternlab_gulp: { - src: './builder/patternlab_gulp.js', - dest: './builder/patternlab_gulp.js' + src: './core/lib/patternlab_gulp.js', + dest: './core/lib/patternlab_gulp.js' }, parameter_hunter: { - src: './builder/parameter_hunter.js', - dest: './builder/parameter_hunter.js' + src: './core/lib/parameter_hunter.js', + dest: './core/lib/parameter_hunter.js' }, pattern_exporter: { - src: './builder/pattern_exporter.js', - dest: './builder/pattern_exporter.js' + src: './core/lib/pattern_exporter.js', + dest: './core/lib/pattern_exporter.js' }, pattern_assembler: { - src: './builder/pattern_assembler.js', - dest: './builder/pattern_assembler.js' + src: './core/lib/pattern_assembler.js', + dest: './core/lib/pattern_assembler.js' }, pseudopattern_hunter: { - src: './builder/pseudopattern_hunter.js', - dest: './builder/pseudopattern_hunter.js' + src: './core/lib/pseudopattern_hunter.js', + dest: './core/lib/pseudopattern_hunter.js' }, list_item_hunter: { - src: './builder/list_item_hunter.js', - dest: './builder/list_item_hunter.js' + src: './core/lib/list_item_hunter.js', + dest: './core/lib/list_item_hunter.js' }, style_modifier_hunter: { - src: './builder/style_modifier_hunter.js', - dest: './builder/style_modifier_hunter.js' + src: './core/lib/style_modifier_hunter.js', + dest: './core/lib/style_modifier_hunter.js' } }, copy: { @@ -142,7 +142,7 @@ module.exports = function (grunt) { options: { configFile: './.eslintrc' }, - target: ['./builder/*'] + target: ['./core/lib/*'] }, bsReload: { css: path.resolve(paths().public.root + '**/*.css') @@ -153,7 +153,7 @@ module.exports = function (grunt) { require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); //load the patternlab task - grunt.task.loadTasks('./builder/'); + grunt.task.loadTasks('./core/lib/'); grunt.registerTask('default', ['patternlab', 'copy:main', 'copy:styleguide']); diff --git a/README.md b/README.md index 156abd8ac..22df180af 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,8 @@ This repository ships with two `package.json` files, a `Gruntfile.js`, and a `gu To run patternlab-node using grunt, do the following in the directory you downloaded and extracted the zipped release: 1. Run `npm install` from the command line -2. Optionally, delete `package.gulp.json`, `gulpfile.js`, and `builder/patternlab_gulp.js` files if you are certain you don't need it. -* Not deleting `builder/patternlab_gulp.js` may cause a harmless error when running grunt. Delete it. +2. Optionally, delete `package.gulp.json`, `gulpfile.js`, and `core/lib/patternlab_gulp.js` files if you are certain you don't need it. +* Not deleting `core/lib/patternlab_gulp.js` may cause a harmless error when running grunt. Delete it. 3. Run `grunt` or `grunt serve` from the command line This creates all patterns, the styleguide, and the pattern lab site. It's strongly recommended to run `grunt serve` to have BrowserSync spin up and serve the files to you. @@ -164,6 +164,16 @@ Pattern states should be lowercase and use hyphens where spaces are present. Coupled with exported css (much easier to extract with existing tools like [grunt-contrib-copy](https://github.com/gruntjs/grunt-contrib-copy)), pattern export can help to maintain the relevancy of the design system by directly placing partials in a directory of your choosing. +##### cacheBust +`config.json` has this flag to instruct Pattern Lab to append a unique query string to Javascript and CSS assets throughout the frontend. + +``` +"cacheBust": true +``` + +Default: true + + ##### baseurl If your instance of Pattern Lab lives in a subdirectory of your server, for instance on github pages (ex: yourusername.github.io/patterns-demo/), then add the baseurl here. The baseurl is everything after the hostname - ie: `patterns-demo` diff --git a/config.json b/config.json index 187e8955d..4d42d0bc5 100644 --- a/config.json +++ b/config.json @@ -5,7 +5,7 @@ "patterns" : "./source/_patterns/", "data" : "./source/_data/", "styleguide" : "./core/styleguide/", - "patternlabFiles" : "./source/_patternlab-files/", + "patternlabFiles" : "./core/", "js" : "./source/js", "images" : "./source/images", "fonts" : "./source/fonts", @@ -53,5 +53,6 @@ }, "patternExportKeys": [], "patternExportDirectory": "./pattern_exports/", - "baseurl" : "" + "baseurl" : "", + "cacheBust": true } diff --git a/builder/lineage_hunter.js b/core/lib/lineage_hunter.js similarity index 100% rename from builder/lineage_hunter.js rename to core/lib/lineage_hunter.js diff --git a/builder/list_item_hunter.js b/core/lib/list_item_hunter.js similarity index 100% rename from builder/list_item_hunter.js rename to core/lib/list_item_hunter.js diff --git a/builder/media_hunter.js b/core/lib/media_hunter.js similarity index 100% rename from builder/media_hunter.js rename to core/lib/media_hunter.js diff --git a/builder/object_factory.js b/core/lib/object_factory.js similarity index 100% rename from builder/object_factory.js rename to core/lib/object_factory.js diff --git a/builder/parameter_hunter.js b/core/lib/parameter_hunter.js similarity index 100% rename from builder/parameter_hunter.js rename to core/lib/parameter_hunter.js diff --git a/builder/pattern_assembler.js b/core/lib/pattern_assembler.js similarity index 100% rename from builder/pattern_assembler.js rename to core/lib/pattern_assembler.js diff --git a/builder/pattern_exporter.js b/core/lib/pattern_exporter.js similarity index 100% rename from builder/pattern_exporter.js rename to core/lib/pattern_exporter.js diff --git a/builder/patternlab.js b/core/lib/patternlab.js similarity index 81% rename from builder/patternlab.js rename to core/lib/patternlab.js index b4705deaf..1d7dcf62a 100644 --- a/builder/patternlab.js +++ b/core/lib/patternlab.js @@ -22,7 +22,7 @@ var patternlab_engine = function (config) { patternlab = {}; patternlab.package = fs.readJSONSync('./package.json'); - patternlab.config = config || fs.readJSONSync(path.resolve(__dirname, '../config.json')); + patternlab.config = config || fs.readJSONSync(path.resolve(__dirname, '../../config.json')); var paths = patternlab.config.paths; @@ -54,15 +54,29 @@ var patternlab_engine = function (config) { } } + function setCacheBust() { + if (patternlab.config.cacheBust) { + if (patternlab.config.debug) { + console.log('setting cacheBuster value for frontend assets.'); + } + patternlab.cacheBuster = new Date().getTime(); + } else { + patternlab.cacheBuster = 0; + } + } + function buildPatterns(deletePatternDir) { patternlab.data = fs.readJSONSync(path.resolve(paths.source.data, 'data.json')); patternlab.listitems = fs.readJSONSync(path.resolve(paths.source.data, 'listitems.json')); - patternlab.header = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'pattern-header-footer/header.html'), 'utf8'); - patternlab.footer = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'pattern-header-footer/footer.html'), 'utf8'); + patternlab.header = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/pattern-header-footer/header.html'), 'utf8'); + patternlab.footerPattern = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/pattern-header-footer/footer-pattern.html'), 'utf8'); + patternlab.footer = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/pattern-header-footer/footer.html'), 'utf8'); patternlab.patterns = []; patternlab.partials = {}; patternlab.data.link = {}; + setCacheBust(); + var pattern_assembler = new pa(), entity_encoder = new he(), pattern_exporter = new pe(), @@ -116,6 +130,25 @@ var patternlab_engine = function (config) { pattern_assembler.process_pattern_recursive(path.resolve(file), patternlab); }); + //set user defined head and foot if they exist + try { + patternlab.userHead = pattern_assembler.get_pattern_by_key('atoms-head', patternlab); + } + catch(ex) { + if (patternlab.config.debug) { + console.log(ex); + console.log('Could not find optional user-defined header, atoms-head pattern. It was likely deleted.'); + } + } + try { + patternlab.userFoot = pattern_assembler.get_pattern_by_key('atoms-foot', patternlab); + } + catch(ex) { + if (patternlab.config.debug) { + console.log(ex); + console.log('Could not find optional user-defined footer, atoms-foot pattern. It was likely deleted.'); + } + } //now that all the main patterns are known, look for any links that might be within data and expand them //we need to do this before expanding patterns & partials into extendedTemplates, otherwise we could lose the data -> partial reference @@ -126,21 +159,43 @@ var patternlab_engine = function (config) { fs.emptyDirSync(paths.public.patterns); } + //set pattern-specific header if necessary + var head; + if (patternlab.userHead) { + head = patternlab.userHead.extendedTemplate.replace('{% pattern-lab-head %}', patternlab.header); + } else { + head = patternlab.header; + } + //render all patterns last, so lineageR works patternlab.patterns.forEach(function (pattern) { + pattern.header = head; + //render the pattern, but first consolidate any data we may have var allData = JSON.parse(JSON.stringify(patternlab.data)); allData = pattern_assembler.merge_data(allData, pattern.jsonFileData); + //also add the cachebuster value. slight chance this could collide with a user that has defined cacheBuster as a value + allData.cacheBuster = patternlab.cacheBuster; + pattern.cacheBuster = patternlab.cacheBuster; + + //render the pattern-specific header + var headHtml = pattern_assembler.renderPattern(pattern.header, allData); + //render the extendedTemplate with all data pattern.patternPartial = pattern_assembler.renderPattern(pattern.extendedTemplate, allData); - //add footer info before writing - var patternFooter = pattern_assembler.renderPattern(patternlab.footer, pattern); + //set the pattern-specific footer if necessary + if (patternlab.userFoot) { + var userFooter = patternlab.userFoot.extendedTemplate.replace('{% pattern-lab-foot %}', patternlab.footerPattern + patternlab.footer); + pattern.footer = pattern_assembler.renderPattern(userFooter, pattern); + } else { + pattern.footer = pattern_assembler.renderPattern(patternlab.footerPattern, pattern); + } //write the compiled template to the public patterns directory - fs.outputFileSync(paths.public.patterns + pattern.patternLink, patternlab.header + pattern.patternPartial + patternFooter); + fs.outputFileSync(paths.public.patterns + pattern.patternLink, headHtml + pattern.patternPartial + pattern.footer); //write the mustache file too fs.outputFileSync(paths.public.patterns + pattern.patternLink.replace('.html', '.mustache'), entity_encoder.encode(pattern.template)); @@ -211,11 +266,20 @@ var patternlab_engine = function (config) { styleguidePatterns = patternlab.patterns; } + //also add the cachebuster value. slight chance this could collide with a user that has defined cacheBuster as a value + patternlab.data.cacheBuster = patternlab.cacheBuster; + + //get the main page head and foot + var mainPageHead = patternlab.userHead.extendedTemplate.replace('{% pattern-lab-head %}', patternlab.header); + var mainPageHeadHtml = pattern_assembler.renderPattern(mainPageHead, patternlab.data); + var mainPageFoot = patternlab.userFoot.extendedTemplate.replace('{% pattern-lab-foot %}', patternlab.footer); + var mainPageFootHtml = pattern_assembler.renderPattern(mainPageFoot, patternlab.data); + //build the styleguide - var styleguideTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'styleguide.mustache'), 'utf8'), - styleguideHtml = pattern_assembler.renderPattern(styleguideTemplate, {partials: styleguidePatterns}); + var styleguideTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/styleguide.mustache'), 'utf8'), + styleguideHtml = pattern_assembler.renderPattern(styleguideTemplate, {partials: styleguidePatterns, cacheBuster: patternlab.cacheBuster}); - fs.outputFileSync(path.resolve(paths.public.styleguide, 'html/styleguide.html'), styleguideHtml); + fs.outputFileSync(path.resolve(paths.public.styleguide, 'html/styleguide.html'), mainPageHeadHtml + styleguideHtml + mainPageFootHtml); //build the viewall pages var prevSubdir = '', @@ -255,9 +319,9 @@ var patternlab_engine = function (config) { } } - var viewAllTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'viewall.mustache'), 'utf8'); - var viewAllHtml = pattern_assembler.renderPattern(viewAllTemplate, {partials: viewAllPatterns, patternPartial: patternPartial}); - fs.outputFileSync(paths.public.patterns + pattern.subdir.slice(0, pattern.subdir.indexOf(pattern.patternGroup) + pattern.patternGroup.length) + '/index.html', viewAllHtml); + var viewAllTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/viewall.mustache'), 'utf8'); + var viewAllHtml = pattern_assembler.renderPattern(viewAllTemplate, {partials: viewAllPatterns, patternPartial: patternPartial, cacheBuster: patternlab.cacheBuster }); + fs.outputFileSync(paths.public.patterns + pattern.subdir.slice(0, pattern.subdir.indexOf(pattern.patternGroup) + pattern.patternGroup.length) + '/index.html', mainPageHead + viewAllHtml + mainPageFoot); } // create the view all for the subsection @@ -282,14 +346,14 @@ var patternlab_engine = function (config) { } } - var viewAllTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'viewall.mustache'), 'utf8'); - var viewAllHtml = pattern_assembler.renderPattern(viewAllTemplate, {partials: viewAllPatterns, patternPartial: patternPartial}); - fs.outputFileSync(paths.public.patterns + pattern.flatPatternPath + '/index.html', viewAllHtml); + var viewAllTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/viewall.mustache'), 'utf8'); + var viewAllHtml = pattern_assembler.renderPattern(viewAllTemplate, {partials: viewAllPatterns, patternPartial: patternPartial, cacheBuster: patternlab.cacheBuster}); + fs.outputFileSync(paths.public.patterns + pattern.flatPatternPath + '/index.html', mainPageHeadHtml + viewAllHtml + mainPageFootHtml); } } //build the patternlab website - var patternlabSiteTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'index.mustache'), 'utf8'); + var patternlabSiteTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/index.mustache'), 'utf8'); //loop through all patterns.to build the navigation //todo: refactor this someday @@ -462,24 +526,24 @@ var patternlab_engine = function (config) { //the patternlab site requires a lot of partials to be rendered. //patternNav - var patternNavTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'partials/patternNav.mustache'), 'utf8'); + var patternNavTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/partials/patternNav.mustache'), 'utf8'); var patternNavPartialHtml = pattern_assembler.renderPattern(patternNavTemplate, patternlab); //ishControls - var ishControlsTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'partials/ishControls.mustache'), 'utf8'); + var ishControlsTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/partials/ishControls.mustache'), 'utf8'); patternlab.config.mqs = patternlab.mediaQueries; var ishControlsPartialHtml = pattern_assembler.renderPattern(ishControlsTemplate, patternlab.config); //patternPaths - var patternPathsTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'partials/patternPaths.mustache'), 'utf8'); + var patternPathsTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/partials/patternPaths.mustache'), 'utf8'); var patternPathsPartialHtml = pattern_assembler.renderPattern(patternPathsTemplate, {'patternPaths': JSON.stringify(patternlab.patternPaths)}); //viewAllPaths - var viewAllPathsTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'partials/viewAllPaths.mustache'), 'utf8'); + var viewAllPathsTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/partials/viewAllPaths.mustache'), 'utf8'); var viewAllPathsPartialHtml = pattern_assembler.renderPattern(viewAllPathsTemplate, {'viewallpaths': JSON.stringify(patternlab.viewAllPaths)}); //render the patternlab template, with all partials - var patternlabSiteHtml = pattern_assembler.renderPattern(patternlabSiteTemplate, {}, { + var patternlabSiteHtml = pattern_assembler.renderPattern(patternlabSiteTemplate, {cacheBuster: patternlab.cacheBuster}, { 'ishControls': ishControlsPartialHtml, 'patternNav': patternNavPartialHtml, 'patternPaths': patternPathsPartialHtml, diff --git a/builder/patternlab_grunt.js b/core/lib/patternlab_grunt.js similarity index 100% rename from builder/patternlab_grunt.js rename to core/lib/patternlab_grunt.js diff --git a/builder/patternlab_gulp.js b/core/lib/patternlab_gulp.js similarity index 100% rename from builder/patternlab_gulp.js rename to core/lib/patternlab_gulp.js diff --git a/builder/pseudopattern_hunter.js b/core/lib/pseudopattern_hunter.js similarity index 100% rename from builder/pseudopattern_hunter.js rename to core/lib/pseudopattern_hunter.js diff --git a/builder/style_modifier_hunter.js b/core/lib/style_modifier_hunter.js similarity index 100% rename from builder/style_modifier_hunter.js rename to core/lib/style_modifier_hunter.js diff --git a/source/_patternlab-files/README b/core/templates/README.txt similarity index 100% rename from source/_patternlab-files/README rename to core/templates/README.txt diff --git a/source/_patternlab-files/index.mustache b/core/templates/index.mustache similarity index 69% rename from source/_patternlab-files/index.mustache rename to core/templates/index.mustache index 1688121dd..e3c1be462 100644 --- a/source/_patternlab-files/index.mustache +++ b/core/templates/index.mustache @@ -3,11 +3,19 @@