gatsby
Version:
Blazing fast modern site generator for React
186 lines (182 loc) • 7.39 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.calcDirtyHtmlFiles = calcDirtyHtmlFiles;
exports.markHtmlDirtyIfResultOfUsedStaticQueryChanged = markHtmlDirtyIfResultOfUsedStaticQueryChanged;
exports.removePageFiles = void 0;
var _fsExtra = _interopRequireDefault(require("fs-extra"));
var _path = _interopRequireDefault(require("path"));
var _os = require("os");
var _reporter = _interopRequireDefault(require("gatsby-cli/lib/reporter"));
var _gatsbyCoreUtils = require("gatsby-core-utils");
var _pageData = require("../utils/page-data");
var _redux = require("../redux");
var _pageMode = require("../utils/page-mode");
const checkFolderIsEmpty = path => _fsExtra.default.existsSync(path) && !_fsExtra.default.readdirSync(path).length;
const checkAndRemoveEmptyDir = (publicDir, pagePath) => {
const pageHtmlDirectory = _path.default.dirname((0, _gatsbyCoreUtils.generateHtmlPath)(publicDir, pagePath));
const pageDataDirectory = _path.default.join(publicDir, `page-data`, (0, _gatsbyCoreUtils.fixedPagePath)(pagePath));
// if page's folder is empty also remove matching page-data folder
if (checkFolderIsEmpty(pageHtmlDirectory)) {
_fsExtra.default.removeSync(pageHtmlDirectory);
}
if (checkFolderIsEmpty(pageDataDirectory)) {
_fsExtra.default.removeSync(pageDataDirectory);
}
};
const sortedPageKeysByNestedLevel = pageKeys => pageKeys.sort((a, b) => {
const currentPagePathValue = a.split(`/`).length;
const previousPagePathValue = b.split(`/`).length;
return previousPagePathValue - currentPagePathValue;
});
const removePageFiles = async (publicDir, pageKeys) => {
const removePages = pageKeys.map(pagePath => {
const removePromise = (0, _gatsbyCoreUtils.remove)({
publicDir
}, pagePath);
removePromise.then(() => {
_redux.store.dispatch({
type: `HTML_REMOVED`,
payload: pagePath
});
});
return removePromise;
});
const removePageDataList = pageKeys.map(pagePath => (0, _pageData.removePageData)(publicDir, pagePath));
return Promise.all([...removePages, ...removePageDataList]).then(() => {
// Sort removed pageKeys by nested directories and remove if empty.
sortedPageKeysByNestedLevel(pageKeys).forEach(pagePath => {
checkAndRemoveEmptyDir(publicDir, pagePath);
});
});
};
exports.removePageFiles = removePageFiles;
const FSisCaseInsensitive = process.env.TEST_FORCE_CASE_FS ? process.env.TEST_FORCE_CASE_FS === `INSENSITIVE` : (0, _os.platform)() === `win32` || (0, _os.platform)() === `darwin`;
function normalizePagePath(path) {
if (path === `/`) {
return `/`;
}
if (FSisCaseInsensitive) {
// e.g. /TEST/ and /test/ would produce "same" artifacts on case insensitive
// file systems
path = path.toLowerCase();
}
return path.endsWith(`/`) ? path.slice(0, -1) : path;
}
const pageGenerationActionPriority = {
// higher the number, higher the priority
regenerate: 2,
reuse: 1,
delete: 0
};
function calcDirtyHtmlFiles(state) {
const toRegenerate = new Set();
const toDelete = new Set();
const toCleanupFromTrackedState = new Set();
const normalizedPagePathToAction = new Map();
/**
* multiple page paths can result in same html and page-data filenames
* so we need to keep that in mind when generating list of pages
* to regenerate and more importantly - to delete (so we don't delete html and page-data file
* when path changes slightly but it would still result in same html and page-data filenames
* for example adding/removing trailing slash between builds or even mid build with plugins
* like `gatsby-plugin-remove-trailing-slashes`). Additionally similar consideration need to
* be accounted for cases where page paths casing on case-insensitive file systems.
*/
function markActionForPage(path, action) {
const normalizedPagePath = normalizePagePath(path);
const previousAction = normalizedPagePathToAction.get(normalizedPagePath);
let overwritePreviousAction = false;
if (previousAction) {
const previousActionPriority = pageGenerationActionPriority[previousAction.action];
const currentActionPriority = pageGenerationActionPriority[action];
if (currentActionPriority > previousActionPriority) {
overwritePreviousAction = true;
toCleanupFromTrackedState.add(previousAction.actualPath);
if (previousAction.action === `delete`) {
// "reuse" or "regenerate" will take over, so we should
// remove path from list of paths to delete
toDelete.delete(previousAction.actualPath);
}
}
}
if (!previousAction || overwritePreviousAction) {
normalizedPagePathToAction.set(normalizedPagePath, {
actualPath: path,
action
});
if (action === `delete`) {
toDelete.add(path);
} else if (action === `regenerate`) {
toRegenerate.add(path);
}
}
}
if (state.html.unsafeBuiltinWasUsedInSSR) {
_reporter.default.warn(`Previous build used unsafe builtin method. We need to rebuild all pages`);
}
state.html.trackedHtmlFiles.forEach(function (htmlFile, path) {
const page = state.pages.get(path);
if (htmlFile.isDeleted || !page) {
// FIXME: checking pages state here because pages are not persisted
// and because of that `isDeleted` might not be set ...
markActionForPage(path, `delete`);
} else {
if ((0, _pageMode.getPageMode)(page, state) === `SSG`) {
if (htmlFile.dirty || state.html.unsafeBuiltinWasUsedInSSR) {
markActionForPage(path, `regenerate`);
} else {
markActionForPage(path, `reuse`);
}
}
}
});
return {
toRegenerate: Array.from(toRegenerate),
toDelete: Array.from(toDelete),
toCleanupFromTrackedState
};
}
function markHtmlDirtyIfResultOfUsedStaticQueryChanged() {
const state = _redux.store.getState();
const dirtyStaticQueryResults = new Set();
state.html.trackedStaticQueryResults.forEach(function (staticQueryResultState, staticQueryHash) {
if (staticQueryResultState.dirty) {
dirtyStaticQueryResults.add(staticQueryHash);
}
});
// we have dirty static query hashes - now we need to find templates that use them
const dirtyTemplates = new Set();
state.staticQueriesByTemplate.forEach(function (staticQueryHashes, componentPath) {
for (const dirtyStaticQueryHash of dirtyStaticQueryResults) {
if (staticQueryHashes.includes(dirtyStaticQueryHash)) {
dirtyTemplates.add(componentPath);
break; // we already know this template need to rebuild, no need to check rest of queries
}
}
});
// mark html as dirty
const dirtyPages = new Set();
const dirtySlices = new Set();
for (const dirtyTemplate of dirtyTemplates) {
const component = state.components.get(dirtyTemplate);
if (component) {
for (const page of component.pages) {
if (component.isSlice) {
dirtySlices.add(page);
} else {
dirtyPages.add(page);
}
}
}
}
_redux.store.dispatch({
type: `HTML_MARK_DIRTY_BECAUSE_STATIC_QUERY_RESULT_CHANGED`,
payload: {
pages: dirtyPages,
slices: dirtySlices,
staticQueryHashes: dirtyStaticQueryResults
}
});
}
//# sourceMappingURL=build-utils.js.map
;