Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Progress logs for templated pages #1859

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import fs from 'fs';
import path from 'path';
/**
* Recursively finds template pages in a given directory and saves their paths to a set.
* @param {string} directoryPath
* @returns {Promise<Set<string>>} Set containing paths to template pages
*/
export const findTemplatePagesPaths = async (directoryPath) => {
const templatePagePaths = new Set();
const files = await fs.promises.readdir(directoryPath);

for (const file of files) {
const filePath = path.join(directoryPath, file);
const fileStat = await fs.promises.stat(filePath);

if (fileStat.isDirectory()) {
const nestedTemplatePagePaths = await findTemplatePagesPaths(filePath);
nestedTemplatePagePaths.forEach((absolutePath) => templatePagePaths.add(absolutePath));
} else if (file.match(/^\[(.*?)\]\.md$/)) {
templatePagePaths.add(filePath);
}
}

return templatePagePaths;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { findTemplatePagesPaths } from './findTemplatePagesPaths.js';
import { watchDirectory } from './watcher.js';

/**
* Crawls the pages dir and checks for the total no. of md files.
* Then crawls the built pages in .evidence and checks for the dirs
* Compares and shows percentage complete logs.
* @type {import("vite").Plugin}
*/
export const verboseLogs = {
name: 'evidence:verbose-logs',

buildStart() {
const directoryPath = '.svelte-kit/output/prerendered/pages';
findTemplatePagesPaths('../../pages')
.then((dirs) => {
watchDirectory(directoryPath, dirs);
})
.catch((error) => {
console.error('Error:', error);
});
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import fs from 'fs/promises';

/**
* Checks if a directory exists.
* @param {string} directoryPath
* @returns {Promise<boolean>}
*/
async function directoryExists(directoryPath) {
try {
const stats = await fs.stat(directoryPath);
return stats.isDirectory();
} catch (error) {
// @ts-ignore
if (error.code === 'ENOENT') {
return false;
}
throw error;
}
}

/**
* Waits for the specified directory to be created.
* @param {string} directoryPath
* @param {number} maxAttempts
* @param {number} intervalMs
* @returns {Promise<void>}
*/
export async function waitForDirectoryCreation(directoryPath, maxAttempts = 60, intervalMs = 3000) {
let attempts = 0;
while (attempts < maxAttempts) {
const dirExists = await directoryExists(directoryPath);
if (dirExists) {
// console.log(`\nMonitoring pages build progress.`);
return;
}
// } else {
// console.log('\nDirectory not found, retrying...');
// }
attempts++;
await new Promise((resolve) => setTimeout(resolve, intervalMs));
}

throw new Error(`\nDirectory ${directoryPath} not created within the specified time.`);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import path from 'path';
import chokidar from 'chokidar';
import { waitForDirectoryCreation } from './wait-creation.js';

/**
* Calculates the depth of a directory path
* @param {string} dirPath - The directory path
* @returns {number}
*/
function calculateDepth(dirPath) {
const segments = dirPath.split(path.sep).filter((segment) => segment !== '');
if (segments.length === 0) {
return 0;
}
return segments.length - 1;
}

/**
* Calculate the max depth among an array of directory paths
* @param {string[]} dirPaths
* @returns {number} - The highest depth
*/
function getMaxDepth(dirPaths) {
let maxDepth = -1;

for (const dirPath of dirPaths) {
const depth = calculateDepth(dirPath);
if (depth > maxDepth) {
maxDepth = depth;
}
}

return maxDepth;
}

/**
* Watches a directory and calculates the progress of files being added.
* @param {string} directoryPath - The path to the directory to watch.
* @param {Set<string>} dirs - The set of directories to watch.
*/
export async function watchDirectory(directoryPath, dirs) {
/**
* @type {string | number | NodeJS.Timeout | undefined}
*/
let timeout;
/**
* @type {string | number | NodeJS.Timeout | undefined}
*/

/**
* @type {number}
*/
let totalCount = 0;

/**
* @type {chokidar.FSWatcher | undefined}
*/
let watcher;

let done = false;
await waitForDirectoryCreation(directoryPath);
try {
const pathArrays = Array.from(dirs).map((p) => {
const pathArray = p.split(path.sep);
pathArray.pop(); // removing the template page name
return pathArray.slice(3); // removing target dir top paths
});
const joinedPaths = pathArrays.map((p) => path.sep + path.join(...p));
const depth = getMaxDepth(joinedPaths);
watcher = chokidar.watch(directoryPath, { ignoreInitial: true, depth: depth + 1 });

// To trigger set the done state after 60 seconds of inactivity.
const resetTimeout = () => {
clearTimeout(timeout);
timeout = setTimeout(() => {
watcher && watcher.close();
done = true;
}, 60000);
};

/**
* Sometimes, plugins runs again after the pages have been built.
* If this happens, the watcher may not register any changes, and the "done" state will never be true,
* even after the pages have been built. Hence setting up the timer before the watcher as well.
*/
resetTimeout();
watcher.on('addDir', async () => {
resetTimeout();
totalCount++;
console.clear(); // to clear the terminal and not fill the terminal with too many logs
console.log('\u001b[1m\u001b[34m Building template pages: %d+\u001b[0m', totalCount);
console.log('Please wait...');

if (done && watcher) {
watcher.close();
console.log('closing watcher', done);
return;
}
});
} catch (err) {
console.error('Error:', err);
return;
}
}
3 changes: 2 additions & 1 deletion packages/lib/plugin-connector/src/build-plugins/vite.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { queryDirectoryHmr } from './query-directory-hmr.js';
import { sourceQueryHMR } from './source-query-hmr.js';
import { verboseLogs } from './verbose-logs/index.js';

/** @type {() => import("vite").UserConfig["plugins"]} */
export const evidenceVitePlugin = () => {
return [sourceQueryHMR(), queryDirectoryHmr];
return [sourceQueryHMR(), queryDirectoryHmr, verboseLogs];
};
Loading