From 9a80da1e5db00e639a001925af82a5154cdf0c43 Mon Sep 17 00:00:00 2001 From: Colin Rotherham Date: Wed, 21 Jun 2023 16:52:40 +0100 Subject: [PATCH] Set up Browsersync with partial rebuild support See: https://github.com/alphagov/govuk-design-system/pull/2750#issuecomment-1590231569 --- lib/metalsmith-browser-sync.js | 53 ------------------------- lib/metalsmith.js | 17 +++++++- tasks/start.js | 72 +++++++++++++++++++++++++--------- 3 files changed, 69 insertions(+), 73 deletions(-) delete mode 100644 lib/metalsmith-browser-sync.js diff --git a/lib/metalsmith-browser-sync.js b/lib/metalsmith-browser-sync.js deleted file mode 100644 index 5583611ab6..0000000000 --- a/lib/metalsmith-browser-sync.js +++ /dev/null @@ -1,53 +0,0 @@ -// Based on metalsmith-browser-sync (Copyright (c) 2015 Mike Dvorscak) -// https://github.com/mdvorscak/metalsmith-browser-sync - -const bs = require('browser-sync').create() - -const PLUGIN_NAME = 'browser-sync' - -const defaultOptions = { - server: './app' -} - -/** - * Metalsmith Browsersync plugin - */ -function browserSyncPlugin (userOptions, callback) { - function plugin (files, metalsmith, done) { - // We only need one browser-sync server active, so on the first build, we - // remove ourselves from the list of plugins, as we're going to be - // rebuilding every time source files are edited - metalsmith.plugins.forEach(function (plugin, index) { - if (plugin._pluginName === PLUGIN_NAME) { - metalsmith.plugins.splice(index, 1) - } - }) - - const finalOptions = { ...defaultOptions, ...userOptions } - - function rebuild () { - if (!bs.paused) { - bs.pause() - console.log('Re-running Metalsmith build.') - metalsmith.build(function (err) { - if (err) { console.error(err) } - - bs.resume() - bs.reload() - }) - } - } - - const watched = finalOptions.files - delete finalOptions.files - - bs.watch(watched, { ignored: '*.map', ignoreInitial: true }).on('all', rebuild) - bs.init(finalOptions, callback || undefined) - - done() - } - plugin._pluginName = PLUGIN_NAME - return plugin -} - -module.exports = browserSyncPlugin diff --git a/lib/metalsmith.js b/lib/metalsmith.js index 2a15fafe45..21175ccc06 100644 --- a/lib/metalsmith.js +++ b/lib/metalsmith.js @@ -31,6 +31,9 @@ const titleChecker = require('./metalsmith-title-checker.js') const navigation = require('./navigation.js') // navigation plugin const rollup = require('./rollup') // used to build GOV.UK Frontend JavaScript +// Flag production mode (to skip plugins in development) +const isProduction = process.env.NODE_ENV !== 'development' + // Nunjucks engine options const nunjucksOptions = { noCache: true, // never use a cache and recompile templates each time @@ -66,14 +69,19 @@ const nunjucksOptions = { // static site generator module.exports = metalsmith(resolve(__dirname, '../')) + // notify build starting + .use((files, metalsmith) => metalsmith.watch() && + console.log('Metalsmith build running') + ) + // source directory .source(paths.source) // destination directory .destination(paths.public) - // clean destination before build - .clean(true) + // clean destination for production builds + .clean(isProduction) // global variables used in layout files .metadata({ @@ -236,5 +244,10 @@ module.exports = metalsmith(resolve(__dirname, '../')) pattern: ['**/*.html', '!**/default/*.html'] })) + // notify build starting + .use((files, metalsmith) => metalsmith.watch() && + console.log('Metalsmith build complete') + ) + // Debug // .use(debug()) diff --git a/tasks/start.js b/tasks/start.js index 3882a9bd54..f47cd52f3a 100644 --- a/tasks/start.js +++ b/tasks/start.js @@ -1,22 +1,58 @@ const { dirname, join } = require('path') +const browserSync = require('browser-sync') +const slash = require('slash') + const { paths } = require('../config') // specify paths to main working directories const metalsmith = require('../lib/metalsmith') // configured static site generator -const browsersync = require('../lib/metalsmith-browser-sync') // setup synchronised browser testing - -// setup synchronised browser testing -metalsmith.use(browsersync({ - ghostMode: false, // Ghost mode tries to check the same input across examples. - open: false, // When making changes to the server, we don't want multiple windows opening. - server: paths.public, // server directory - files: [ - join(paths.source, '**/*'), - join(paths.views, '**/*'), - join(dirname(require.resolve('govuk-frontend/package.json')), '**/*') - ] // files to watch -})) - -// build to destination directory -metalsmith.build(function (err, files) { - if (err) { throw err } -}) + +let bs + +metalsmith + + // configure files to watch for partial rebuilds + .watch([ + slash(join(paths.source, '**/*')), + slash(join(paths.views, '**/*')), + slash(join(dirname(require.resolve('govuk-frontend/package.json')), '**/*')) + ]) + + // build to destination directory + .build((err) => { + if (err) { + throw err + } + + // setup synchronised browser testing + if (!bs) { + bs = browserSync.create() + + bs.init({ + files: [ + join(paths.public, 'javascripts/**/*.js'), + join(paths.public, 'stylesheets/**/*.css') + ], + + // Prevent browser mirroring + ghostMode: false, + + // Prevent browser opening + open: false, + + // Serve files from directory + server: paths.public, + + // Browser paths to files being watched + serveStatic: [ + { + route: '/javascripts', + dir: join(paths.public, 'javascripts') + }, + { + route: '/stylesheets', + dir: join(paths.public, 'stylesheets') + } + ] + }) + } + })