ultimate-jekyll-manager 0.0.90 → 0.0.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/build.js CHANGED
@@ -199,6 +199,59 @@ Manager.require = function (path) {
199
199
  };
200
200
  Manager.prototype.require = Manager.require;
201
201
 
202
+ // Memory monitoring utility
203
+ Manager.getMemoryUsage = function () {
204
+ const used = process.memoryUsage();
205
+ return {
206
+ rss: Math.round(used.rss / 1024 / 1024),
207
+ heapTotal: Math.round(used.heapTotal / 1024 / 1024),
208
+ heapUsed: Math.round(used.heapUsed / 1024 / 1024),
209
+ external: Math.round(used.external / 1024 / 1024),
210
+ };
211
+ };
212
+ Manager.prototype.getMemoryUsage = Manager.getMemoryUsage;
213
+
214
+ Manager.logMemory = function (logger, label) {
215
+ const mem = Manager.getMemoryUsage();
216
+ logger.log(`[Memory ${label}] RSS: ${mem.rss}MB | Heap Used: ${mem.heapUsed}MB / ${mem.heapTotal}MB | External: ${mem.external}MB`);
217
+ };
218
+ Manager.prototype.logMemory = Manager.logMemory;
219
+
220
+ // Process array in batches to avoid memory issues
221
+ Manager.processBatches = async function (items, batchSize, processFn, logger) {
222
+ const results = [];
223
+
224
+ for (let i = 0; i < items.length; i += batchSize) {
225
+ const batch = items.slice(i, i + batchSize);
226
+ const batchNum = Math.floor(i / batchSize) + 1;
227
+ const totalBatches = Math.ceil(items.length / batchSize);
228
+
229
+ if (logger) {
230
+ logger.log(`Processing batch ${batchNum}/${totalBatches} (${batch.length} items)...`);
231
+ Manager.logMemory(logger, `Before Batch ${batchNum}`);
232
+ }
233
+
234
+ const batchResults = await Promise.all(batch.map(processFn));
235
+ results.push(...batchResults);
236
+
237
+ if (logger) {
238
+ Manager.logMemory(logger, `After Batch ${batchNum}`);
239
+ }
240
+
241
+ // Force garbage collection if available (requires --expose-gc flag)
242
+ if (global.gc) {
243
+ global.gc();
244
+ if (logger) {
245
+ logger.log(`Forced garbage collection after batch ${batchNum}`);
246
+ Manager.logMemory(logger, `After GC`);
247
+ }
248
+ }
249
+ }
250
+
251
+ return results;
252
+ };
253
+ Manager.prototype.processBatches = Manager.processBatches;
254
+
202
255
  // // Task Tracking System (uses global tracking)
203
256
  // Manager.prototype.taskStart = function (taskName) {
204
257
  // const logger = this.logger('task-tracker');
@@ -9,10 +9,12 @@ const spellchecker = require('spellchecker');
9
9
  const cheerio = require('cheerio');
10
10
  const { HtmlValidate } = require('html-validate');
11
11
  const { XMLParser } = require('fast-xml-parser');
12
- const chromeLauncher = require('chrome-launcher');
13
- const lighthouse = require('lighthouse').default || require('lighthouse');
14
12
  const { execute } = require('node-powertools');
15
13
 
14
+ // Lazy-loaded libraries (only loaded when needed)
15
+ let chromeLauncher = null;
16
+ let lighthouse = null;
17
+
16
18
  // Utils
17
19
  const collectTextNodes = require('./utils/collectTextNodes');
18
20
  const dictionary = require('./utils/dictionary');
@@ -33,35 +35,55 @@ const input = [
33
35
  const output = '';
34
36
  const delay = 250;
35
37
 
38
+ // Batch size for processing files (configurable via env var)
39
+ // Set to 0 or 'false' to disable batching and process all files at once (original behavior)
40
+ const BATCH_SIZE = (() => {
41
+ const envValue = process.env.UJ_AUDIT_BATCH_SIZE;
42
+
43
+ if (!envValue || envValue === 'false' || envValue === '0') {
44
+ return Infinity; // Process all files at once (original behavior)
45
+ }
46
+
47
+ return parseInt(envValue, 10);
48
+ })();
49
+
36
50
  // Task
37
51
  async function audit(complete) {
38
52
  // Log
39
53
  logger.log('Starting...');
54
+ logger.log(`Batch size: ${BATCH_SIZE === Infinity ? 'disabled (processing all files at once)' : `${BATCH_SIZE} files per batch`}`);
55
+ Manager.logMemory(logger, 'Audit Start');
40
56
 
41
57
  // Quit if NOT in build mode and UJ_AUDIT_FORCE is not true
42
- if (!Manager.isBuildMode() && process.env.UJ_AUDIT_FORCE !== 'true') {
43
- logger.log('Skipping audit in development mode');
58
+ // if (!Manager.isBuildMode() && process.env.UJ_AUDIT_FORCE !== 'true') {
59
+ // logger.log('Skipping audit in development mode');
60
+ // return complete();
61
+ // }
62
+
63
+ // For now, only run when forced
64
+ if (process.env.UJ_AUDIT_FORCE !== 'true') {
65
+ logger.log('Skipping audit (UJ_AUDIT_FORCE not set to true)');
44
66
  return complete();
45
67
  }
46
68
 
47
69
  // Perform HTML/XML audit
48
70
  await processAudit();
49
71
 
50
- // Real quick, lets check if were in build mode and IF NOT then we run minifyHtml
51
- if (!Manager.isBuildMode()) {
72
+ // Perform Lighthouse audit if URL is provided
73
+ if (process.env.UJ_AUDIT_LIGHTHOUSE_URL) {
74
+ // This helps us pass Lighthouse audits in development mode
52
75
  const minifyHtml = require('./minifyHtml');
53
76
  await new Promise((resolve) => {
54
77
  minifyHtml(resolve);
55
78
  });
56
- }
57
79
 
58
- // Perform Lighthouse audit if URL is provided
59
- if (process.env.UJ_AUDIT_LIGHTHOUSE_URL) {
80
+ // Run Lighthouse audit
60
81
  await runLighthouseAudit();
61
82
  }
62
83
 
63
84
  // Log
64
85
  logger.log('Finished!');
86
+ Manager.logMemory(logger, 'Audit Complete');
65
87
 
66
88
  // Exit process if UJ_AUDIT_AUTOEXIT is set
67
89
  if (process.env.UJ_AUDIT_AUTOEXIT === 'true') {
@@ -228,6 +250,7 @@ async function validateSpelling(file, content) {
228
250
  }
229
251
 
230
252
  async function processAudit() {
253
+ logger.log('📂 Finding files to audit...');
231
254
  const htmlFiles = glob(input, {
232
255
  nodir: true,
233
256
  ignore: [
@@ -239,9 +262,14 @@ async function processAudit() {
239
262
  ]
240
263
  });
241
264
 
242
- // Run validations in parallel
243
- const results = await Promise.all(
244
- htmlFiles.map(async (file) => {
265
+ logger.log(`📊 Found ${htmlFiles.length} files to audit`);
266
+ Manager.logMemory(logger, 'Before Processing');
267
+
268
+ // Process files in batches to avoid memory issues
269
+ const results = await Manager.processBatches(
270
+ htmlFiles,
271
+ BATCH_SIZE,
272
+ async (file) => {
245
273
  const content = jetpack.read(file);
246
274
 
247
275
  // Run format and spellcheck in parallel
@@ -255,9 +283,12 @@ async function processAudit() {
255
283
  formatValidation,
256
284
  spellingValidation
257
285
  };
258
- })
286
+ },
287
+ logger
259
288
  );
260
289
 
290
+ Manager.logMemory(logger, 'After Processing');
291
+
261
292
  // Log results
262
293
  const summary = {
263
294
  totalFiles: htmlFiles.length,
@@ -334,6 +365,10 @@ function format(messages) {
334
365
  async function runLighthouseAudit() {
335
366
  logger.log('📊 Starting Lighthouse audit...');
336
367
 
368
+ // Lazy load Lighthouse dependencies (only when actually running audit)
369
+ chromeLauncher = require('chrome-launcher');
370
+ lighthouse = require('lighthouse').default || require('lighthouse');
371
+
337
372
  let serverStarted = false;
338
373
  let auditUrl = null;
339
374
 
@@ -145,7 +145,8 @@ function defaults(complete, changedFile) {
145
145
 
146
146
  // Log
147
147
  logger.log('Starting...');
148
-
148
+ Manager.logMemory(logger, 'Start');
149
+
149
150
  // Use changedFile if provided, otherwise use all inputs
150
151
  const filesToProcess = changedFile ? [changedFile] : input;
151
152
  logger.log('input', filesToProcess)
@@ -32,6 +32,7 @@ async function developmentRebuild(complete) {
32
32
 
33
33
  // Log
34
34
  logger.log('Starting...');
35
+ Manager.logMemory(logger, 'Start');
35
36
 
36
37
  // Skip first run
37
38
  if (index === 0 && false) {
@@ -43,6 +43,7 @@ function distribute() {
43
43
 
44
44
  // Log
45
45
  logger.log('Starting...');
46
+ Manager.logMemory(logger, 'Start');
46
47
 
47
48
  // Complete
48
49
  return src(input, {
@@ -50,6 +50,7 @@ async function imagemin(complete) {
50
50
 
51
51
  // Log
52
52
  logger.log('Starting...');
53
+ Manager.logMemory(logger, 'Start');
53
54
 
54
55
  // Track timing
55
56
  const startTime = Date.now();
@@ -66,6 +66,7 @@ async function jekyll(complete) {
66
66
  try {
67
67
  // Log
68
68
  logger.log('Starting...');
69
+ Manager.logMemory(logger, 'Start');
69
70
 
70
71
  // Increment index
71
72
  index++;
@@ -96,6 +97,7 @@ async function jekyll(complete) {
96
97
  Manager.isBuildMode() ? '' : `./node_modules/${package.name}/dist/config/_config_development.yml`,
97
98
  ].join(','),
98
99
  '--incremental',
100
+ Manager.isBuildMode() ? ' --profile' : '',
99
101
  // '--disable-disk-cache',
100
102
  ]
101
103
 
@@ -38,6 +38,7 @@ const compiled = {};
38
38
  function jsonToHtml(complete) {
39
39
  // Log
40
40
  logger.log('Starting...');
41
+ Manager.logMemory(logger, 'Start');
41
42
 
42
43
  // First, copy JSON files to _data directory
43
44
  const jsonCopy = src(input)
@@ -30,7 +30,8 @@ function minifyHtmlTask(complete) {
30
30
  }
31
31
 
32
32
  // Log
33
- logger.log('Starting HTML minification...');
33
+ logger.log('Starting...');
34
+ Manager.logMemory(logger, 'Start');
34
35
 
35
36
  // Configure minify options
36
37
  const options = {
@@ -112,7 +113,7 @@ function minifyHtmlTask(complete) {
112
113
  .pipe(dest(output))
113
114
  .on('finish', () => {
114
115
  // Log
115
- logger.log('Finished HTML minification!');
116
+ logger.log('Finished!');
116
117
 
117
118
  // Complete
118
119
  return complete();
@@ -39,7 +39,8 @@ const directoriesToExpand = [
39
39
  // Preprocessing task
40
40
  async function preprocess(complete) {
41
41
  try {
42
- logger.log('Starting preprocessing...');
42
+ logger.log('Starting...');
43
+ Manager.logMemory(logger, 'Start');
43
44
 
44
45
  // Step 1: Process template variables
45
46
  await processTemplates();
@@ -48,10 +49,10 @@ async function preprocess(complete) {
48
49
  // NOTE: NO POINT BECAUSE NESTED FILES (/pages/auth/signup.html) WOULD STILL BE IN a subfolder (/auth)
49
50
  // await moveDirectoryFilesUp();
50
51
 
51
- logger.log('Preprocessing finished!');
52
+ logger.log('Preprocessing!');
52
53
  return complete();
53
54
  } catch (error) {
54
- logger.error('Error during preprocessing:', error);
55
+ logger.error('Error:', error);
55
56
  return complete();
56
57
  }
57
58
  }
@@ -85,6 +85,7 @@ const ENABLE_PURGECSS = Manager.isBuildMode() || process.env.UJ_PURGECSS === 'tr
85
85
  function sass(complete) {
86
86
  // Log
87
87
  logger.log('Starting...');
88
+ Manager.logMemory(logger, 'Start');
88
89
 
89
90
  // Generate pages scss
90
91
  generatePageScss();
@@ -21,6 +21,7 @@ let externalUrl;
21
21
  module.exports = async function serve(complete) {
22
22
  // Log
23
23
  logger.log('Starting...');
24
+ Manager.logMemory(logger, 'Start');
24
25
 
25
26
  // BrowserSync settings
26
27
  const settings = {
@@ -14,6 +14,7 @@ const rootPathProject = Manager.getRootPath('project');
14
14
  module.exports = async function setup(complete) {
15
15
  // Log
16
16
  logger.log('Starting setup...');
17
+ Manager.logMemory(logger, 'Start');
17
18
 
18
19
  // Run clean and setup
19
20
  await require('../../commands/clean.js')();
@@ -41,7 +41,7 @@ const CACHE_DIR = '.temp/cache/translation';
41
41
  const CACHE_BRANCH = 'cache-uj-translation';
42
42
  const RECHECK_DAYS = 0;
43
43
  // const LOUD = false;
44
- const LOUD = Manager.isServer() || process.env.UJ_LOUD_LOGS === 'true';
44
+ const LOUD = process.env.UJ_LOUD_LOGS === 'true';
45
45
  const CONTROL = 'UJ-TRANSLATION-CONTROL';
46
46
  const RTL_LANGUAGES = ['ar', 'he', 'fa', 'ur', 'ps', 'sd', 'ku', 'yi', 'ji', 'ckb', 'dv', 'arc', 'aii', 'syr'];
47
47
 
@@ -93,6 +93,7 @@ async function translation(complete) {
93
93
 
94
94
  // Log
95
95
  logger.log('Starting...');
96
+ Manager.logMemory(logger, 'Start');
96
97
 
97
98
  // Quit if NOT in build mode and UJ_TRANSLATION_FORCE is not true
98
99
  if (!Manager.isBuildMode() && process.env.UJ_TRANSLATION_FORCE !== 'true') {
@@ -231,6 +232,10 @@ async function processTranslation() {
231
232
  processedFiles: []
232
233
  };
233
234
 
235
+ // Calculate total tasks for progress tracking
236
+ const totalTasks = allFiles.length * languages.length;
237
+ let completedTasks = 0;
238
+
234
239
  for (const filePath of allFiles) {
235
240
  // Get relative path and original HTML
236
241
  const relativePath = filePath.replace(/^_site[\\/]/, '');
@@ -278,8 +283,13 @@ async function processTranslation() {
278
283
  : path.join('_site', lang, relativePath);
279
284
  const logTag = `[${lang}] ${relativePath}`;
280
285
 
286
+ // Increment and calculate progress
287
+ completedTasks++;
288
+ const progress = `${completedTasks}/${totalTasks}`;
289
+ const percentage = ((completedTasks / totalTasks) * 100).toFixed(1);
290
+
281
291
  // Log
282
- logger.log(`🌐 Started: ${logTag}`);
292
+ logger.log(`🌐 Started [${progress} - ${percentage}%]: ${logTag}`);
283
293
 
284
294
  // Skip if the file is not in the meta or if it has no text nodes
285
295
  let translated = null;
@@ -312,7 +322,7 @@ async function processTranslation() {
312
322
  && jetpack.exists(cachePath)
313
323
  ) {
314
324
  translated = jetpack.read(cachePath);
315
- logger.log(`📦 Success: ${logTag} - Using cache`);
325
+ logger.log(`📦 Success [${progress} - ${percentage}%]: ${logTag} - Using cache`);
316
326
  stats.fromCache++;
317
327
  stats.cachedFiles.push(logTag);
318
328
  } else {
@@ -321,7 +331,7 @@ async function processTranslation() {
321
331
 
322
332
  // Log
323
333
  const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(2);
324
- logger.log(`✅ Success: ${logTag} - Translated (Elapsed time: ${elapsedTime}s)`);
334
+ logger.log(`✅ Success [${progress} - ${percentage}%]: ${logTag} - Translated (Elapsed time: ${elapsedTime}s)`);
325
335
 
326
336
  // Set translated result
327
337
  translated = result;
@@ -339,7 +349,7 @@ async function processTranslation() {
339
349
  stats.processedFiles.push(logTag);
340
350
  } catch (e) {
341
351
  const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(2);
342
- logger.error(`❌ Failed: ${logTag} — ${e.message} (Elapsed time: ${elapsedTime}s)`);
352
+ logger.error(`❌ Failed [${progress} - ${percentage}%]: ${logTag} — ${e.message} (Elapsed time: ${elapsedTime}s)`);
343
353
 
344
354
  // Set translated result
345
355
  translated = bodyText;
@@ -266,6 +266,7 @@ function webpack(complete) {
266
266
 
267
267
  // Log
268
268
  logger.log('Starting...');
269
+ Manager.logMemory(logger, 'Start');
269
270
 
270
271
  // Log mode and devtools
271
272
  logger.log(`Mode: ${settings.mode}`);
@@ -38,3 +38,19 @@
38
38
  [debug] [2025-10-21T00:37:54.671Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
39
39
  [debug] [2025-10-21T00:37:54.672Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
40
40
  [debug] [2025-10-21T00:37:54.672Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
41
+ [debug] [2025-10-22T06:48:21.189Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
42
+ [debug] [2025-10-22T06:48:21.189Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
43
+ [debug] [2025-10-22T06:48:21.191Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
44
+ [debug] [2025-10-22T06:48:21.191Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
45
+ [debug] [2025-10-22T06:48:21.191Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
46
+ [debug] [2025-10-22T06:48:21.191Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
47
+ [debug] [2025-10-22T06:48:21.191Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
48
+ [debug] [2025-10-22T06:48:21.191Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
49
+ [debug] [2025-10-22T06:51:09.272Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
50
+ [debug] [2025-10-22T06:51:09.272Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
51
+ [debug] [2025-10-22T06:51:09.274Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
52
+ [debug] [2025-10-22T06:51:09.274Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
53
+ [debug] [2025-10-22T06:51:09.274Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
54
+ [debug] [2025-10-22T06:51:09.274Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
55
+ [debug] [2025-10-22T06:51:09.274Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
56
+ [debug] [2025-10-22T06:51:09.274Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultimate-jekyll-manager",
3
- "version": "0.0.90",
3
+ "version": "0.0.92",
4
4
  "description": "Ultimate Jekyll dependency manager",
5
5
  "main": "dist/index.js",
6
6
  "exports": {