diff --git a/docs/userGuide/glossary.md b/docs/userGuide/glossary.md
index f6e9234b1b..f1d506140b 100644
--- a/docs/userGuide/glossary.md
+++ b/docs/userGuide/glossary.md
@@ -10,6 +10,8 @@
**_Live preview_** is:
- Regeneration of affected content upon any change to source files, then reloading the updated site in the Browser.
+- Regeneration will also occur upon any modification to attributes in `site.json` with the exception of [`baseUrl`](siteJsonFile.md#baseurl).
+
- Copying assets to the site output folder.
Use [the `serve` command](cliCommands.html#serve-command) to launch a live preview.
diff --git a/docs/userGuide/siteJsonFile.md b/docs/userGuide/siteJsonFile.md
index e11643633b..e3b728822a 100644
--- a/docs/userGuide/siteJsonFile.md
+++ b/docs/userGuide/siteJsonFile.md
@@ -81,6 +81,10 @@ Here is a typical `site.json` file:
+
+
+Note: `baseUrl` does not support [live preview](glossary.md#live-preview) as there is no use case for changing it in during `markbind serve`.
+
#### **`faviconPath`**
diff --git a/packages/core/src/Site/index.js b/packages/core/src/Site/index.js
index 40d0d956ca..f12773bd06 100644
--- a/packages/core/src/Site/index.js
+++ b/packages/core/src/Site/index.js
@@ -540,6 +540,13 @@ class Site {
this.baseUrlMap = new Set(candidates.map(candidate => path.dirname(candidate)));
this.variableProcessor = new VariableProcessor(this.rootPath, this.baseUrlMap);
+ this.buildManagers();
+ }
+
+ /**
+ * Set up the managers used with the configurations.
+ */
+ buildManagers() {
const config = {
baseUrlMap: this.baseUrlMap,
baseUrl: this.siteConfig.baseUrl,
@@ -633,7 +640,7 @@ class Site {
await this.buildAssets();
await (this.onePagePath ? this.lazyBuildSourceFiles() : this.buildSourceFiles());
await this.copyCoreWebAsset();
- await this.copyBootswatchTheme();
+ await this.copyBootstrapTheme(false);
await this.copyFontAwesomeAsset();
await this.copyOcticonsAsset();
await this.writeSiteData();
@@ -773,7 +780,7 @@ class Site {
}
async _rebuildSourceFiles() {
- logger.info('Page added or removed, updating list of site\'s pages...');
+ logger.info('Pages or site config modified, updating pages...');
this.beforeSiteGenerate();
this.layoutManager.removeLayouts();
@@ -844,9 +851,19 @@ class Site {
}
async reloadSiteConfig() {
+ const oldSiteConfig = this.siteConfig;
const oldAddressablePages = this.addressablePages.slice();
const oldPagesSrc = oldAddressablePages.map(page => page.src);
await this.readSiteConfig();
+ await this.handleIgnoreReload(oldSiteConfig.ignore);
+ await this.handlePageReload(oldAddressablePages, oldPagesSrc, oldSiteConfig);
+ await this.handleStyleReload(oldSiteConfig.style);
+ }
+
+ /**
+ * Handles the rebuilding of modified pages
+ */
+ async handlePageReload(oldAddressablePages, oldPagesSrc, oldSiteConfig) {
this.collectAddressablePages();
// Comparator for the _differenceWith comparison below
@@ -856,8 +873,24 @@ class Site {
const removedPages = _.differenceWith(oldAddressablePages, this.addressablePages, isNewPage)
.map(filePath => Site.setExtension(filePath.src, '.html'));
- if (!_.isEmpty(addedPages) || !_.isEmpty(removedPages)) {
+ // Checks if any attributes of site.json requiring a global rebuild are modified
+ const isGlobalConfigModified = () => !_.isEqual(oldSiteConfig.faviconPath, this.siteConfig.faviconPath)
+ || !_.isEqual(oldSiteConfig.titlePrefix, this.siteConfig.titlePrefix)
+ || !_.isEqual(oldSiteConfig.style, this.siteConfig.style)
+ || !_.isEqual(oldSiteConfig.externalScripts, this.siteConfig.externalScripts)
+ || !_.isEqual(oldSiteConfig.globalOverride, this.siteConfig.globalOverride)
+ || !_.isEqual(oldSiteConfig.plugins, this.siteConfig.plugins)
+ || !_.isEqual(oldSiteConfig.pluginsContext, this.siteConfig.pluginsContext)
+ || !_.isEqual(oldSiteConfig.headingIndexingLevel, this.siteConfig.headingIndexingLevel)
+ || !_.isEqual(oldSiteConfig.enableSearch, this.siteConfig.enableSearch)
+ || !_.isEqual(oldSiteConfig.disableHtmlBeautify, this.siteConfig.disableHtmlBeautify)
+ || !_.isEqual(oldSiteConfig.timeZone, this.siteConfig.timeZone)
+ || !_.isEqual(oldSiteConfig.locale, this.siteConfig.locale)
+ || !_.isEqual(oldSiteConfig.intrasiteLinkValidation, this.siteConfig.intrasiteLinkValidation);
+
+ if (isGlobalConfigModified() || !_.isEmpty(addedPages) || !_.isEmpty(removedPages)) {
await this.removeAsset(removedPages);
+ this.buildManagers();
await this._rebuildSourceFiles();
await this.writeSiteData();
} else {
@@ -889,6 +922,29 @@ class Site {
});
}
+ /**
+ * Handles the reloading of ignore attributes
+ */
+ async handleIgnoreReload(oldIgnore) {
+ const assetsToRemove = _.difference(this.siteConfig.ignore, oldIgnore);
+
+ if (!_.isEqual(oldIgnore, this.siteConfig.ignore)) {
+ await this._removeMultipleAssets(assetsToRemove);
+ this.buildManagers();
+ await this.buildAssets();
+ }
+ }
+
+ /**
+ * Handles the reloading of the style attribute if it has been modified
+ */
+ async handleStyleReload(oldStyle) {
+ if (!_.isEqual(oldStyle.bootstrapTheme, this.siteConfig.style.bootstrapTheme)) {
+ await this.copyBootstrapTheme(true);
+ logger.info('Updated bootstrap theme');
+ }
+ }
+
/**
* Checks if a specified file path is a dependency of a page
* @param {string} filePath file path to check
@@ -1223,15 +1279,23 @@ class Site {
}
/**
- * Copies bootswatch theme to the assets folder if a valid theme is specified
+ * Copies bootstrap theme to the assets folder if a valid theme is specified
+ * @param {Boolean} isRebuild only true if it is a rebuild
*/
- copyBootswatchTheme() {
+ copyBootstrapTheme(isRebuild) {
const { theme } = this.siteConfig;
- if (!theme || !_.has(SUPPORTED_THEMES_PATHS, theme)) {
+
+ /**
+ * If it is the initial build using the default theme or if the theme specified
+ * is not valid, then do nothing.
+ */
+ if ((!isRebuild && !theme) || (theme && !_.has(SUPPORTED_THEMES_PATHS, theme))) {
return _.noop;
}
- const themeSrcPath = SUPPORTED_THEMES_PATHS[theme];
+ const themeSrcPath = !theme
+ ? require.resolve('@markbind/core-web/asset/css/bootstrap.min.css')
+ : SUPPORTED_THEMES_PATHS[theme];
const themeDestPath = path.join(this.siteAssetsDestPath, 'css', 'bootstrap.min.css');
return fs.copy(themeSrcPath, themeDestPath);