From a3fd3b316b04568cdd620243bd64f5bc50dfb670 Mon Sep 17 00:00:00 2001 From: Colin Rotherham Date: Fri, 23 Jun 2023 15:44:18 +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 | 66 ++++++++++++++++++++++++---------- 3 files changed, 63 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 5392368e20..bb0e10924b 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) // include environment variables for plugins to detect NODE_ENV .env(process.env) @@ -239,5 +247,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..8da9e6f0b2 100644 --- a/tasks/start.js +++ b/tasks/start.js @@ -1,22 +1,52 @@ 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 sources to watch for rebuilds + .watch([ + slash(paths.source), + slash(paths.views), + slash(dirname(require.resolve('govuk-frontend/package.json'))) + ]) + + // Build to destination directory + .build((err, files) => { + if (err) { + throw err + } + + if (metalsmith.watch()) { + if (bs) { + return + } + + // Setup synchronised browser testing + bs = browserSync.create() + + bs.init({ + // Configure output to watch for reloads + files: [ + join(paths.public, '**/*.html'), + 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 + }) + } + })