diff --git a/docs/_markbind/variables.md b/docs/_markbind/variables.md index 2b3c6ed935..2dfa5f3779 100644 --- a/docs/_markbind/variables.md +++ b/docs/_markbind/variables.md @@ -11,8 +11,8 @@ :fas-check-circle: :fas-lightbulb: :fas-thumbs-down: -Example: -Examples: +Example +Examples :fas-info-circle: :far-check-square: diff --git a/docs/userGuide/cliCommands.md b/docs/userGuide/cliCommands.md index 857298002d..cc30ca2aaa 100644 --- a/docs/userGuide/cliCommands.md +++ b/docs/userGuide/cliCommands.md @@ -26,8 +26,10 @@ Usage: markbind
### `init` Command +
+ +**Format:** `markbind init [options] [root]` -**Format:** `markbind init [options] [root]`
**Alias:** `markbind i` **Description:** Initializes a directory into a MarkBind site by creating a skeleton structure for the website which includes a `index.md` and a `site.json`. @@ -37,7 +39,10 @@ Usage: markbind Root directory. Default is the current directory.
{{ icon_example }} `./myWebsite` -**`options`:** + + +**Options** :fas-cogs: + * `-c`, `--convert`
Convert an existing GitHub wiki or `docs` folder into a MarkBind website. See [Converting an existing Github project]({{ baseUrl }}/userGuide/markBindInTheProjectWorkflow.html#converting-existing-project-documentation-wiki) for more information. @@ -46,11 +51,15 @@ Usage: markbind * `markbind init ./myWebsite` : Initializes the site in `./myWebsite` directory. * `markbind init --convert` : Converts the Github wiki or `docs` folder in the current working directory into a MarkBind website. +
+
### `serve` Command +
+ +**Format:** `markbind serve [options] [root]` -**Format:** `markbind serve [options] [root]`
**Alias:** `markbind s` **Description:** Does the following steps: @@ -64,33 +73,55 @@ Usage: markbind **Arguments:** * `[root]`
- Root directory. Default is the current directory.
+ Root directory. The default is the directory where this command was executed.
{{ icon_example }} `./myWebsite` -**`options`:** -* `-f`, `--force-reload`
- Force live reload to process all files in the site, instead of just the relevant files. This option is useful when you are modifying a file that is not a file type monitored by the live preview feature. -* `-n`, `--no-open`
- Don't open a live preview in the browser automatically. + + +**Options** :fas-cogs: + * `-o `, `--one-page `
- Render and serve only a single page from your website.
- {{ icon_example }} `--one-page guide/index.md` -* `-p `, `--port `
- Serve the website in the specified port. + Serves only a single page from your website **initially**. If `` is not specified, it defaults to `index.md/mbf/mbdf`.
+ * Thereafter, when changes to source files have been made, only the page being viewed will be rebuilt if it was affected.
+ * Navigating to a new page will build the new page, if it has not been built before, or there were some changes to source files that affected it before navigating to it.
+ * {{ icon_example }} `--one-page guide/index.md` + + + +Essentially, this optional feature is very useful when writing content, more so if your build times are starting to slow down! + +The caveat is that not building all pages during the initial process, or not rebuilding all affected pages when a file changes, will cause your search results for these pages to be empty or outdated, until you navigate to them to trigger a rebuild. + + + * `-s `, `--site-config `
Specify the site config file (default: `site.json`)
{{ icon_example }} `-s otherSite.json` +* `-n`, `--no-open`
+ Don't open a live preview in the browser automatically. + +* `-f`, `--force-reload`
+ Force live reload to process all files in the site, instead of just the relevant files. This option is useful when you are modifying a file that is not a file type monitored by the live preview feature. + +* `-p `, `--port `
+ Serve the website in the specified port. + + {{ icon_examples }} * `markbind serve` * `markbind serve ./myWebsite` * `markbind serve -p 8888 -s otherSite.json` +
+
### `build` Command +
+ +**Format:** `markbind build [options] [root] [output]` -**Format:** `markbind build [options] [root] [output]`
**Alias:** `markbind b` **Description:** Generates the site to the directory named `_site` in the current directory. @@ -99,14 +130,19 @@ Usage: markbind * `[output]`
Put the generated files in the specified directory
{{ icon_example }} `../myOutDir` + * `[root] [output]`
Read source files from the `[root]` directory and put the generated files in the specified `[output]` directory
{{ icon_example }} `./myWebsite ../myOutDir` -**`options`:** + + +**Options** :fas-cogs: + * `--baseUrl `
Override the `baseUrl` property (read from the `site.json`) with the give `` value.
{{ icon_example }} `--baseUrl staging` + * `-s `, `--site-config `
Specify the site config file (default: `site.json`)
{{ icon_example }} `-s otherSite.json` @@ -116,27 +152,38 @@ Usage: markbind * `markbind build ./myWebsite ./myOutDir` * `markbind build ./stagingDir --baseUrl staging` +
+
### `deploy` Command +
+ +**Format:** `markbind deploy [options]` -**Format:** `markbind deploy [options]`
**Alias:** `markbind d` **Description:** Deploys the site to the repo's Github pages by pushing everything in the generated site (default dir: `_site`) to the `gh-pages` branch of the current git working directory's remote repo. -**`options`:** + + +**Options** :fas-cogs: + * `-t `, `--travis `
Deploy the site in Travis CI using the GitHub personal access token stored in ``. (default: `GITHUB_TOKEN`)
{{ icon_example }} `-t PA_TOKEN` %%{{ icon_info }} Related: [User Guide: Deploying the Website](deployingTheSite.html).%% +
+
### `--help` Option +
+ +**Format:** `markbind [command] --help` -**Format:** `markbind [command] --help`
**Alias:** `markbind [command] -h` **Description:** Prints a summary of MarkBind commands or a detailed usage guide for the given `command`. diff --git a/index.js b/index.js index 518daea50d..03d279b750 100755 --- a/index.js +++ b/index.js @@ -21,6 +21,8 @@ const Site = require('./src/Site'); const { ACCEPTED_COMMANDS, ACCEPTED_COMMANDS_ALIAS, + INDEX_MARKDOWN_FILE, + LAZY_LOADING_SITE_FILE_NAME, } = require('./src/constants'); const CLI_VERSION = require('./package.json').version; @@ -95,26 +97,30 @@ program .description('build then serve a website from a directory') .option('-f, --force-reload', 'force a full reload of all site files when a file is changed') .option('-n, --no-open', 'do not automatically open the site in browser') - .option('-o, --one-page ', 'render and serve only a single page in the site') + .option('-o, --one-page [file]', 'build and serve only a single page in the site initially,' + + 'building more pages when they are navigated to. Also lazily rebuilds only the page being viewed when' + + 'there are changes to the source files (if needed), building others when navigated to') .option('-p, --port ', 'port for server to listen on (Default is 8080)') .option('-s, --site-config ', 'specify the site config file (default: site.json)') .action((userSpecifiedRoot, options) => { let rootFolder; try { rootFolder = cliUtil.findRootFolder(userSpecifiedRoot, options.siteConfig); + + if (options.forceReload && options.onePage) { + handleError(new Error('Oops! You shouldn\'t need to use the --force-reload option with --one-page.')); + process.exit(); + } } catch (err) { handleError(err); } const logsFolder = path.join(rootFolder, '_markbind/logs'); const outputFolder = path.join(rootFolder, '_site'); - if (options.onePage) { - // replace slashes for paths on Windows - // eslint-disable-next-line no-param-reassign - options.onePage = ensurePosix(options.onePage); - } + let onePagePath = options.onePage === true ? INDEX_MARKDOWN_FILE : options.onePage; + onePagePath = onePagePath ? ensurePosix(onePagePath) : onePagePath; - const site = new Site(rootFolder, outputFolder, options.onePage, options.forceReload, options.siteConfig); + const site = new Site(rootFolder, outputFolder, onePagePath, options.forceReload, options.siteConfig); const addHandler = (filePath) => { logger.info(`[${new Date().toLocaleTimeString()}] Reload for file add: ${filePath}`); @@ -152,12 +158,15 @@ program }); }; + const onePageHtmlUrl = onePagePath && `/${onePagePath.replace(/\.(md|mbd|mbdf)$/, '.html')}`; + // server config const serverConfig = { - open: options.open && (options.onePage ? `/${options.onePage.replace(/\.(md|mbd)$/, '.html')}` : true), + open: options.open && (onePageHtmlUrl || true), logLevel: 0, root: outputFolder, port: options.port || 8080, + middleware: [], mount: [], }; @@ -167,6 +176,30 @@ program .readSiteConfig() .then((config) => { serverConfig.mount.push([config.baseUrl || '/', outputFolder]); + + if (onePagePath) { + const lazyReloadMiddleware = function (req, res, next) { + const isHtmlFile = req.url.endsWith('.html'); + + if (isHtmlFile) { + const isDynamicIncludeHtmlFile = req.url.endsWith('._include_.html'); + + if (!isDynamicIncludeHtmlFile) { + const urlWithoutBaseUrl = req.url.replace(config.baseUrl, ''); + const urlWithoutExtension = fsUtil.removeExtension(urlWithoutBaseUrl); + + const didInitiateRebuild = site.changeCurrentPage(urlWithoutExtension); + if (didInitiateRebuild) { + req.url = ensurePosix(path.join(config.baseUrl || '/', LAZY_LOADING_SITE_FILE_NAME)); + } + } + } + next(); + }; + + serverConfig.middleware.push(lazyReloadMiddleware); + } + return site.generate(); }) .then(() => { diff --git a/src/LazyLiveReloadLoadingSite.html b/src/LazyLiveReloadLoadingSite.html new file mode 100644 index 0000000000..834773557c --- /dev/null +++ b/src/LazyLiveReloadLoadingSite.html @@ -0,0 +1,66 @@ + + + + + Building ... + + +
+
... building your page ...
+ + + + diff --git a/src/Site.js b/src/Site.js index c7b4afca69..916cf0b9d7 100644 --- a/src/Site.js +++ b/src/Site.js @@ -48,6 +48,9 @@ const { LAYOUT_DEFAULT_NAME, LAYOUT_FOLDER_PATH, LAYOUT_SITE_FOLDER_NAME, + LAZY_LOADING_SITE_FILE_NAME, + LAZY_LOADING_BUILD_TIME_RECOMMENDATION_LIMIT, + LAZY_LOADING_REBUILD_TIME_RECOMMENDATION_LIMIT, MARKBIND_PLUGIN_PREFIX, MARKBIND_WEBSITE_URL, PAGE_TEMPLATE_NAME, @@ -124,11 +127,17 @@ class Site { this.addressablePages = []; this.baseUrlMap = new Set(); this.forceReload = forceReload; - this.onePagePath = onePagePath; this.plugins = {}; this.siteConfig = {}; this.siteConfigPath = siteConfigPath; this.userDefinedVariablesMap = {}; + + // Lazy reload properties + this.onePagePath = onePagePath; + this.currentPageViewed = onePagePath + ? path.resolve(this.rootPath, FsUtil.removeExtension(onePagePath)) + : ''; + this.toRebuild = new Set(); } /** @@ -170,6 +179,22 @@ class Site { }); } + /** + * Changes the site variable of the current page being viewed, building it if necessary. + * @param normalizedUrl BaseUrl-less and extension-less url of the page + * @return Boolean of whether the page needed to be rebuilt + */ + changeCurrentPage(normalizedUrl) { + this.currentPageViewed = path.join(this.rootPath, normalizedUrl); + + if (this.toRebuild.has(this.currentPageViewed)) { + this.rebuildPageBeingViewed(this.currentPageViewed); + return true; + } + + return false; + } + readSiteConfig(baseUrl) { return new Promise((resolve, reject) => { const siteConfigPath = path.join(this.rootPath, this.siteConfigPath); @@ -405,10 +430,11 @@ class Site { * Updates the paths to be traversed as addressable pages and returns a list of filepaths to be deleted */ updateAddressablePages() { - const oldAddressablePages = this.addressablePages.slice(); + const oldAddressablePagesSources = this.addressablePages.slice().map(page => page.src); this.collectAddressablePages(); - return _.difference(oldAddressablePages.map(page => page.src), - this.addressablePages.map(page => page.src)) + const newAddressablePagesSources = this.addressablePages.map(page => page.src); + + return _.difference(oldAddressablePagesSources, newAddressablePagesSources) .map(filePath => Site.setExtension(filePath, '.html')); } @@ -521,7 +547,9 @@ class Site { fs.emptydirSync(this.tempPath); // Clean the output folder; create it if not exist. fs.emptydirSync(this.outputPath); - logger.info(`Website generation started at ${startTime.toLocaleTimeString()}`); + const lazyWebsiteGenerationString = this.onePagePath ? '(lazy) ' : ''; + logger.info(`Website generation ${lazyWebsiteGenerationString}started at ${ + startTime.toLocaleTimeString()}`); return new Promise((resolve, reject) => { this.readSiteConfig(baseUrl) .then(() => this.collectAddressablePages()) @@ -530,16 +558,22 @@ class Site { .then(() => this.collectPlugins()) .then(() => this.collectPluginSpecialTags()) .then(() => this.buildAssets()) - .then(() => this.buildSourceFiles()) + .then(() => (this.onePagePath ? this.lazyBuildSourceFiles() : this.buildSourceFiles())) .then(() => this.copyMarkBindAsset()) .then(() => this.copyFontAwesomeAsset()) .then(() => this.copyOcticonsAsset()) .then(() => this.copyLayouts()) - .then(() => this.updateSiteData()) + .then(() => this.updateSiteData(this.onePagePath || undefined)) .then(() => { const endTime = new Date(); const totalBuildTime = (endTime - startTime) / 1000; - logger.info(`Website generation complete! Total build time: ${totalBuildTime}s`); + logger.info(`Website generation ${lazyWebsiteGenerationString}complete! Total build time: ${ + totalBuildTime}s`); + + if (!this.onePagePath && totalBuildTime > LAZY_LOADING_BUILD_TIME_RECOMMENDATION_LIMIT) { + logger.info('Your site took quite a while to build...' + + 'Have you considered using markbind serve -o when writing content to speed things up?'); + } }) .then(resolve) .catch((error) => { @@ -565,6 +599,44 @@ class Site { }); } + /** + * Adds all pages except the current page being viewed to toRebuild, flagging them for lazy building later. + */ + lazyBuildAllPagesNotViewed() { + this.pages.forEach((page) => { + const normalizedUrl = FsUtil.removeExtension(page.sourcePath); + if (normalizedUrl !== this.currentPageViewed) { + this.toRebuild.add(normalizedUrl); + } + }); + + return Promise.resolve(); + } + + /** + * Only build landing page of the site, building more as the author goes to different links. + */ + lazyBuildSourceFiles() { + return new Promise((resolve, reject) => { + logger.info('Generating landing page...'); + this.generateLandingPage() + .then(() => { + const lazyLoadingSpinnerHtmlFilePath = path.join(__dirname, LAZY_LOADING_SITE_FILE_NAME); + const outputSpinnerHtmlFilePath = path.join(this.outputPath, LAZY_LOADING_SITE_FILE_NAME); + + return fs.copyAsync(lazyLoadingSpinnerHtmlFilePath, outputSpinnerHtmlFilePath); + }) + .then(() => fs.removeAsync(this.tempPath)) + .then(() => this.lazyBuildAllPagesNotViewed()) + .then(() => logger.info('Landing page built, other pages will be built as you navigate to them!')) + .then(resolve) + .catch((error) => { + // if error, remove the site and temp folders + Site.rejectHandler(reject, error, [this.tempPath, this.outputPath]); + }); + }); + } + _rebuildAffectedSourceFiles(filePaths) { const filePathArray = Array.isArray(filePaths) ? filePaths : [filePaths]; const uniquePaths = _.uniq(filePathArray); @@ -581,14 +653,73 @@ class Site { }); } + _rebuildPageBeingViewed(normalizedUrls) { + const startTime = new Date(); + const normalizedUrlArray = Array.isArray(normalizedUrls) ? normalizedUrls : [normalizedUrls]; + const uniqueUrls = _.uniq(normalizedUrlArray); + uniqueUrls.forEach(normalizedUrl => logger.info( + `Building ${normalizedUrl} as some of its dependencies were changed since the last visit`)); + MarkBind.resetVariables(); + + /* + Lazy loading only builds the page being viewed, but the user may be quick enough + to trigger multiple page builds before the first one has finished building, + hence we need to take this into account. + */ + const regeneratePagesBeingViewed = uniqueUrls.map(normalizedUrl => + new Promise((resolve, reject) => { + this._setTimestampVariable(); + const pageToRebuild = this.pages.find(page => + FsUtil.removeExtension(page.sourcePath) === normalizedUrl); + + if (!pageToRebuild) { + Site.rejectHandler(reject, + new Error(`Failed to rebuild ${normalizedUrl} during lazy loading`), + [this.tempPath, this.outputPath]); + } + + this.toRebuild.delete(normalizedUrl); + pageToRebuild.userDefinedVariablesMap = this.userDefinedVariablesMap; + pageToRebuild.generate(new Set()) + .then(() => { + pageToRebuild.collectHeadingsAndKeywords(); + + return this.writeSiteData(); + }) + .then(() => { + const endTime = new Date(); + const totalBuildTime = (endTime - startTime) / 1000; + logger.info(`Lazy website regeneration complete! Total build time: ${totalBuildTime}s`); + }) + .then(resolve) + .catch((error) => { + logger.error(error); + reject(new Error(`Failed to rebuild ${normalizedUrl} during lazy loading`)); + }); + }), + ); + + return Promise.all(regeneratePagesBeingViewed) + .then(() => fs.removeAsync(this.tempPath)); + } + _rebuildSourceFiles() { - logger.warn('Rebuilding all source files'); + logger.info('File added or removed, updating list of site\'s pages...'); return new Promise((resolve, reject) => { Promise.resolve('') .then(() => this.updateAddressablePages()) - // ignore the warning on next line as IDE doesn't understand `delay` very well .then(filesToRemove => this.removeAsset(filesToRemove)) - .then(() => this.buildSourceFiles()) + .then(() => { + if (this.onePagePath) { + this.mapAddressablePagesToPages(this.addressablePages || [], this.getFavIconUrl()); + + return this.rebuildPageBeingViewed(this.currentPageViewed) + .then(() => this.lazyBuildAllPagesNotViewed()); + } + + logger.warn('Rebuilding all pages...'); + return this.buildSourceFiles(); + }) .then(resolve) .catch((error) => { // if error, remove the site and temp folders @@ -740,6 +871,33 @@ class Site { .forEach(plugin => this.loadPlugin(plugin, true)); } + getFavIconUrl() { + const { baseUrl, faviconPath } = this.siteConfig; + + if (faviconPath) { + if (!fs.existsSync(path.join(this.rootPath, faviconPath))) { + logger.warn(`${faviconPath} does not exist`); + } + return url.join('/', baseUrl, faviconPath); + } else if (fs.existsSync(path.join(this.rootPath, FAVICON_DEFAULT_PATH))) { + return url.join('/', baseUrl, FAVICON_DEFAULT_PATH); + } + + return undefined; + } + + mapAddressablePagesToPages(addressablePages, faviconUrl) { + this.pages = addressablePages.map(page => this.createPage({ + faviconUrl, + pageSrc: page.src, + title: page.title, + layout: page.layout, + frontmatter: page.frontmatter, + searchable: page.searchable !== 'no', + externalScripts: page.externalScripts, + })); + } + /** * Collects the special tags of the site's plugins, and injects them into the parsers. */ @@ -775,47 +933,14 @@ class Site { generatePages() { // Run MarkBind include and render on each source file. // Render the final rendered page to the output folder. - const { baseUrl, faviconPath } = this.siteConfig; const addressablePages = this.addressablePages || []; const builtFiles = new Set(); const processingFiles = []; - let faviconUrl; - if (faviconPath) { - faviconUrl = url.join('/', baseUrl, faviconPath); - if (!fs.existsSync(path.join(this.rootPath, faviconPath))) { - logger.warn(`${faviconPath} does not exist`); - } - } else if (fs.existsSync(path.join(this.rootPath, FAVICON_DEFAULT_PATH))) { - faviconUrl = url.join('/', baseUrl, FAVICON_DEFAULT_PATH); - } + const faviconUrl = this.getFavIconUrl(); this._setTimestampVariable(); - if (this.onePagePath) { - const page = addressablePages.find(p => p.src === this.onePagePath); - if (!page) { - return Promise.reject(new Error(`${this.onePagePath} is not specified in the site configuration.`)); - } - this.pages.push(this.createPage({ - faviconUrl, - pageSrc: page.src, - title: page.title, - layout: page.layout, - frontmatter: page.frontmatter, - searchable: page.searchable !== 'no', - externalScripts: page.externalScripts, - })); - } else { - this.pages = addressablePages.map(page => this.createPage({ - faviconUrl, - pageSrc: page.src, - title: page.title, - layout: page.layout, - frontmatter: page.frontmatter, - searchable: page.searchable !== 'no', - externalScripts: page.externalScripts, - })); - } + this.mapAddressablePagesToPages(addressablePages, faviconUrl); const progressBar = new ProgressBar(`[:bar] :current / ${this.pages.length} pages built`, { total: this.pages.length }); @@ -835,7 +960,27 @@ class Site { }); } + /** + * Renders only the starting page for lazy loading to the output folder. + */ + generateLandingPage() { + const addressablePages = this.addressablePages || []; + const faviconUrl = this.getFavIconUrl(); + + this._setTimestampVariable(); + this.mapAddressablePagesToPages(addressablePages, faviconUrl); + + const landingPage = this.pages.find(page => page.src === this.onePagePath); + if (!landingPage) { + return Promise.reject(new Error(`${this.onePagePath} is not specified in the site configuration.`)); + } + + return landingPage.generate(new Set()); + } + regenerateAffectedPages(filePaths) { + const startTime = new Date(); + const builtFiles = new Set(); const processingFiles = []; const shouldRebuildAllPages = this.collectUserDefinedVariablesMapIfNeeded(filePaths) || this.forceReload; @@ -844,13 +989,25 @@ class Site { } this._setTimestampVariable(); this.pages.forEach((page) => { - if (shouldRebuildAllPages || filePaths.some((filePath) => { + const doFilePathsHaveSourceFiles = filePaths.some((filePath) => { const isIncludedFile = page.includedFiles.has(filePath); const isPluginSourceFile = page.pluginSourceFiles.has(filePath); return isIncludedFile || isPluginSourceFile; - })) { - // eslint-disable-next-line no-param-reassign + }); + + if (shouldRebuildAllPages || doFilePathsHaveSourceFiles) { + if (this.onePagePath) { + const normalizedSource = FsUtil.removeExtension(page.sourcePath); + const isPageBeingViewed = normalizedSource === this.currentPageViewed; + + if (!isPageBeingViewed) { + this.toRebuild.add(normalizedSource); + return; + } + } + + // eslint-disable-next-line no-param-reassign page.userDefinedVariablesMap = this.userDefinedVariablesMap; processingFiles.push(page.generate(builtFiles) .catch((err) => { @@ -864,8 +1021,22 @@ class Site { return new Promise((resolve, reject) => { Promise.all(processingFiles) - .then(() => this.updateSiteData(shouldRebuildAllPages ? undefined : filePaths)) + .then(() => { + // For lazy loading, we defer updating site data pages not being viewed, + // even if all pages should be rebuilt, until they are navigated to. + const shouldUpdateAllSiteData = shouldRebuildAllPages && !this.onePagePath; + return this.updateSiteData(shouldUpdateAllSiteData ? undefined : filePaths); + }) .then(() => logger.info('Pages rebuilt')) + .then(() => { + const endTime = new Date(); + const totalBuildTime = (endTime - startTime) / 1000; + logger.info(`Website regeneration complete! Total build time: ${totalBuildTime}s`); + if (!this.onePagePath && totalBuildTime > LAZY_LOADING_REBUILD_TIME_RECOMMENDATION_LIMIT) { + logger.info('Your pages took quite a while to rebuild...' + + 'Have you considered using markbind serve -o when writing content to speed things up?'); + } + }) .then(resolve) .catch(reject); }); @@ -880,8 +1051,9 @@ class Site { */ updateSiteData(filePaths) { const generateForAllPages = filePaths === undefined; + const filePathsToUpdateData = Array.isArray(filePaths) ? filePaths : [filePaths]; this.pages.forEach((page) => { - if (generateForAllPages || filePaths.some(filePath => page.includedFiles.has(filePath))) { + if (generateForAllPages || filePathsToUpdateData.some(filePath => page.includedFiles.has(filePath))) { page.collectHeadingsAndKeywords(); } }); @@ -1071,6 +1243,9 @@ class Site { */ Site.prototype.buildAsset = delay(Site.prototype._buildMultipleAssets, 1000); +Site.prototype.rebuildPageBeingViewed + = delay(Site.prototype._rebuildPageBeingViewed, 1000); + /** * Rebuild pages that are affected by changes in filePaths * @param filePaths a single path or an array of paths corresponding to the files that have changed diff --git a/src/constants.js b/src/constants.js index 35d7c0a41e..f89bf66f9f 100644 --- a/src/constants.js +++ b/src/constants.js @@ -56,6 +56,9 @@ module.exports = { SITE_CONFIG_NAME: 'site.json', SITE_DATA_NAME: 'siteData.json', LAYOUT_SITE_FOLDER_NAME: 'layouts', + LAZY_LOADING_SITE_FILE_NAME: 'LazyLiveReloadLoadingSite.html', + LAZY_LOADING_BUILD_TIME_RECOMMENDATION_LIMIT: 30000, + LAZY_LOADING_REBUILD_TIME_RECOMMENDATION_LIMIT: 5000, USER_VARIABLES_PATH: '_markbind/variables.md', WIKI_SITE_NAV_PATH: '_Sidebar.md', WIKI_FOOTER_PATH: '_Footer.md',