pug-site-core 3.0.3 → 3.0.4

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.
Files changed (2) hide show
  1. package/lib/generate.js +190 -48
  2. package/package.json +3 -2
package/lib/generate.js CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  import _ from "lodash";
16
16
  import async from "async";
17
17
  import UglifyJS from "uglify-js";
18
+ import { minify as htmlMinify } from "html-minifier-terser";
18
19
  import { paths } from "./paths.js";
19
20
  import path from "path";
20
21
 
@@ -309,7 +310,10 @@ export async function fetchDataToJsonFile(args) {
309
310
  await checkData(data, language, obj.getDataFn);
310
311
  let outPutPath = obj.outPutPath.split("/").join(pathSymbol);
311
312
  if (Array.isArray(data)) {
312
- let name = outPutPath.split(pathSymbol).pop().replace(/\.[^.]*$/, "");
313
+ let name = outPutPath
314
+ .split(pathSymbol)
315
+ .pop()
316
+ .replace(/\.[^.]*$/, "");
313
317
  const regex = /^\[.+\]$/;
314
318
  if (regex.test(name)) {
315
319
  let property = name.slice(1, -1);
@@ -497,6 +501,41 @@ export async function buildStatic() {
497
501
  let starTime = Date.now();
498
502
  let distOutputPath = paths.resolveRoot(config.staticOutput);
499
503
 
504
+ // HTML压缩配置
505
+ const htmlMinifyOptions = {
506
+ collapseWhitespace: true,
507
+ removeComments: true,
508
+ removeRedundantAttributes: true,
509
+ removeScriptTypeAttributes: true,
510
+ removeStyleLinkTypeAttributes: true,
511
+ minifyCSS: true,
512
+ minifyJS: true,
513
+ useShortDoctype: true,
514
+ removeEmptyAttributes: true,
515
+ removeOptionalTags: true,
516
+ caseSensitive: false,
517
+ };
518
+
519
+ /**
520
+ * 压缩HTML内容
521
+ * @param {string} html - 原始HTML内容
522
+ * @param {string} filePath - 文件路径(用于错误报告)
523
+ * @returns {string} 压缩后的HTML内容
524
+ */
525
+ async function compressHtml(html, filePath = "") {
526
+ // 检查是否启用HTML压缩
527
+ if (!config.minifyHtml) {
528
+ return html; // 如果禁用压缩,直接返回原始HTML
529
+ }
530
+
531
+ try {
532
+ return await htmlMinify(html, htmlMinifyOptions);
533
+ } catch (error) {
534
+ console.warn(`HTML压缩失败 [${filePath}]:`, error.message);
535
+ return html; // 如果压缩失败,返回原始HTML
536
+ }
537
+ }
538
+
500
539
  /**
501
540
  * 构建HTML文件路径
502
541
  * @param {string} lang - 语言代码
@@ -505,24 +544,29 @@ export async function buildStatic() {
505
544
  * @returns {string} 完整的HTML文件路径
506
545
  */
507
546
  function buildHtmlPath(lang, outputPath, fileName = null) {
508
- let htmlPath
547
+ let htmlPath;
509
548
  try {
510
549
  if (fileName) {
511
- htmlPath = paths.resolveRoot(
512
- distOutputPath,
513
- lang,
514
- outputPath.replace(
515
- outputPath.split("/").pop().replace(/\.[^.]*$/, ""),
516
- fileName.replace(/\.[^.]*$/, "")
517
- )
518
- );
550
+ htmlPath = paths.resolveRoot(
551
+ distOutputPath,
552
+ lang,
553
+ outputPath.replace(
554
+ outputPath
555
+ .split("/")
556
+ .pop()
557
+ .replace(/\.[^.]*$/, ""),
558
+ fileName.replace(/\.[^.]*$/, "")
559
+ )
560
+ );
519
561
  } else {
520
562
  htmlPath = paths.resolveRoot(distOutputPath, lang, outputPath);
521
563
  }
522
564
  console.log(htmlPath);
523
565
  return htmlPath;
524
566
  } catch (error) {
525
- throw new Error(`构建HTML路径失败 [lang: ${lang}, outputPath: ${outputPath}, fileName: ${fileName}]: ${error.message}`);
567
+ throw new Error(
568
+ `构建HTML路径失败 [lang: ${lang}, outputPath: ${outputPath}, fileName: ${fileName}]: ${error.message}`
569
+ );
526
570
  }
527
571
  }
528
572
 
@@ -534,71 +578,111 @@ export async function buildStatic() {
534
578
  if (!pagesPugToFn[funName]) {
535
579
  throw new Error(`模板函数 ${funName} 不存在`);
536
580
  }
537
-
581
+
538
582
  return pagesPugToFn[funName]({
539
583
  data,
540
584
  _pagePath: pagePath,
541
585
  common: commonData,
542
586
  });
543
587
  } catch (error) {
544
- throw new Error(`生成HTML失败 [funName: ${funName}, pagePath: ${pagePath}]: ${error.message}`);
588
+ throw new Error(
589
+ `生成HTML失败 [funName: ${funName}, pagePath: ${pagePath}]: ${error.message}`
590
+ );
545
591
  }
546
592
  }
547
593
 
548
594
  /**
549
595
  * 处理数组数据的HTML输出
550
596
  */
551
- async function processArrayData(pagesPugToFn, data, obj, funName, pagePath, commonData, lang) {
597
+ async function processArrayData(
598
+ pagesPugToFn,
599
+ data,
600
+ obj,
601
+ funName,
602
+ pagePath,
603
+ commonData,
604
+ lang
605
+ ) {
552
606
  try {
553
- const name = obj.outPutHtmlPath.split("/").pop().replace(/\.[^.]*$/, "");
607
+ const name = obj.outPutHtmlPath
608
+ .split("/")
609
+ .pop()
610
+ .replace(/\.[^.]*$/, "");
554
611
  const regex = /^\[.+\]$/;
555
-
612
+
556
613
  if (regex.test(name)) {
557
614
  const property = name.slice(1, -1);
558
-
559
- await async.eachLimit(data, 64, async (dataItem, index) => {
615
+
616
+ await async.eachLimit(data, 128, async (dataItem, index) => {
560
617
  try {
561
618
  const fileName = dataItem[property];
562
619
  if (!fileName) {
563
- throw new Error(
564
- `数据项索引 ${index} 中缺少属性 ${property} 或值为空`
565
- );
620
+ throw new Error(`数据项索引 ${index} 中缺少属性 ${property} 或值为空`);
566
621
  }
567
-
622
+
568
623
  const htmlPath = buildHtmlPath(lang, obj.outPutHtmlPath, fileName);
569
- const html = generateHtml(pagesPugToFn, funName, dataItem, pagePath, commonData);
570
- await fse.outputFile(htmlPath, html);
624
+ const html = generateHtml(
625
+ pagesPugToFn,
626
+ funName,
627
+ dataItem,
628
+ pagePath,
629
+ commonData
630
+ );
631
+ const compressedHtml = await compressHtml(html, htmlPath);
632
+ await fse.outputFile(htmlPath, compressedHtml);
571
633
  } catch (error) {
572
- throw new Error(`处理数组数据项失败 [index: ${index}, property: ${property}]: ${error.message}`);
634
+ throw new Error(
635
+ `处理数组数据项失败 [index: ${index}, property: ${property}]: ${error.message}`
636
+ );
573
637
  }
574
638
  });
575
639
  } else {
576
640
  const htmlPath = buildHtmlPath(lang, obj.outPutHtmlPath);
577
641
  const html = generateHtml(pagesPugToFn, funName, data, pagePath, commonData);
578
- await fse.outputFile(htmlPath, html);
642
+ const compressedHtml = await compressHtml(html, htmlPath);
643
+ await fse.outputFile(htmlPath, compressedHtml);
579
644
  }
580
645
  } catch (error) {
581
- throw new Error(`处理数组数据失败 [lang: ${lang}, getDataFn: ${obj.getDataFn}]: ${error.message}`);
646
+ throw new Error(
647
+ `处理数组数据失败 [lang: ${lang}, getDataFn: ${obj.getDataFn}]: ${error.message}`
648
+ );
582
649
  }
583
650
  }
584
651
 
585
652
  /**
586
653
  * 处理对象数据的HTML输出
587
654
  */
588
- async function processObjectData(pagesPugToFn, data, obj, funName, pagePath, commonData, lang) {
655
+ async function processObjectData(
656
+ pagesPugToFn,
657
+ data,
658
+ obj,
659
+ funName,
660
+ pagePath,
661
+ commonData,
662
+ lang
663
+ ) {
589
664
  try {
590
665
  const htmlPath = buildHtmlPath(lang, obj.outPutHtmlPath);
591
666
  const html = generateHtml(pagesPugToFn, funName, data, pagePath, commonData);
592
- await fse.outputFile(htmlPath, html);
667
+ const compressedHtml = await compressHtml(html, htmlPath);
668
+ await fse.outputFile(htmlPath, compressedHtml);
593
669
  } catch (error) {
594
- throw new Error(`处理对象数据失败 [lang: ${lang}, getDataFn: ${obj.getDataFn}]: ${error.message}`);
670
+ throw new Error(
671
+ `处理对象数据失败 [lang: ${lang}, getDataFn: ${obj.getDataFn}]: ${error.message}`
672
+ );
595
673
  }
596
674
  }
597
675
 
598
676
  /**
599
677
  * 处理自定义HTML构建
600
678
  */
601
- async function processCustomBuildHtml(pagesPugToFn, lang, getData, commonData, dealWithEndFunName) {
679
+ async function processCustomBuildHtml(
680
+ pagesPugToFn,
681
+ lang,
682
+ getData,
683
+ commonData,
684
+ dealWithEndFunName
685
+ ) {
602
686
  if (!config.customBuildHtml?.length) return;
603
687
 
604
688
  await async.eachLimit(config.customBuildHtml, 3, async (obj) => {
@@ -609,12 +693,15 @@ export async function buildStatic() {
609
693
  }
610
694
 
611
695
  // 获取数据
612
- if (!getData[obj.getDataFn] || typeof getData[obj.getDataFn] !== 'function') {
696
+ if (
697
+ !getData[obj.getDataFn] ||
698
+ typeof getData[obj.getDataFn] !== "function"
699
+ ) {
613
700
  throw new Error(`数据获取函数 ${obj.getDataFn} 不存在或不是函数`);
614
701
  }
615
702
 
616
703
  const data = await getData[obj.getDataFn](lang);
617
-
704
+
618
705
  // 处理路径和函数名
619
706
  obj.inputPugPath = obj.inputPugPath.replace(/^\//, "");
620
707
  const funName = obj.inputPugPath.split("/").join("_").slice(0, -4);
@@ -623,14 +710,34 @@ export async function buildStatic() {
623
710
 
624
711
  // 根据数据类型处理
625
712
  if (Array.isArray(data)) {
626
- await processArrayData(pagesPugToFn, data, obj, funName, pagePath, commonData, lang);
713
+ await processArrayData(
714
+ pagesPugToFn,
715
+ data,
716
+ obj,
717
+ funName,
718
+ pagePath,
719
+ commonData,
720
+ lang
721
+ );
627
722
  } else if (typeof data === "object" && data !== null) {
628
- await processObjectData(pagesPugToFn, data, obj, funName, pagePath, commonData, lang);
723
+ await processObjectData(
724
+ pagesPugToFn,
725
+ data,
726
+ obj,
727
+ funName,
728
+ pagePath,
729
+ commonData,
730
+ lang
731
+ );
629
732
  } else {
630
733
  throw new Error(`数据类型不支持: ${typeof data}`);
631
734
  }
632
735
  } catch (error) {
633
- throw new Error(`处理自定义HTML构建失败 [lang: ${lang}, config: ${JSON.stringify(obj)}]: ${error.message}`);
736
+ throw new Error(
737
+ `处理自定义HTML构建失败 [lang: ${lang}, config: ${JSON.stringify(obj)}]: ${
738
+ error.message
739
+ }`
740
+ );
634
741
  }
635
742
  });
636
743
  }
@@ -638,28 +745,42 @@ export async function buildStatic() {
638
745
  /**
639
746
  * 处理页面JSON文件
640
747
  */
641
- async function processPageJsonFiles(pagesPugToFn, lang, langDataPath, commonData, dealWithEndFunName) {
748
+ async function processPageJsonFiles(
749
+ pagesPugToFn,
750
+ lang,
751
+ langDataPath,
752
+ commonData,
753
+ dealWithEndFunName
754
+ ) {
642
755
  try {
643
756
  const pagesAllJsonFileName = (
644
757
  await fse.readdir(langDataPath, { recursive: true })
645
758
  ).filter((fileName) => fileName.endsWith(".json"));
646
759
 
647
- await async.eachLimit(pagesAllJsonFileName, 64, async (jsonFileName) => {
760
+ await async.eachLimit(pagesAllJsonFileName, 128, async (jsonFileName) => {
648
761
  try {
649
- const data = await fse.readJSON(paths.resolveRoot(langDataPath, jsonFileName));
762
+ const data = await fse.readJSON(
763
+ paths.resolveRoot(langDataPath, jsonFileName)
764
+ );
650
765
  const pugTemplate = data._template;
651
-
766
+
652
767
  if (!pugTemplate) {
653
768
  return;
654
769
  }
655
770
 
656
771
  const funName = pugTemplate.split(pathSymbol).join("_").slice(0, -4);
657
-
772
+
658
773
  if (dealWithEndFunName.has(funName)) {
659
774
  return;
660
775
  }
661
776
 
662
- const html = generateHtml(pagesPugToFn, funName, data, pugTemplate, commonData);
777
+ const html = generateHtml(
778
+ pagesPugToFn,
779
+ funName,
780
+ data,
781
+ pugTemplate,
782
+ commonData
783
+ );
663
784
 
664
785
  // 构建输出路径
665
786
  let finalPugTemplate = pugTemplate;
@@ -676,9 +797,12 @@ export async function buildStatic() {
676
797
  finalPugTemplate.replace(/\.[^.]*$/, ".html")
677
798
  );
678
799
  console.log(htmlPath);
679
- await fse.outputFile(htmlPath, html);
800
+ const compressedHtml = await compressHtml(html, htmlPath);
801
+ await fse.outputFile(htmlPath, compressedHtml);
680
802
  } catch (error) {
681
- throw new Error(`处理JSON文件失败 [file: ${jsonFileName}]: ${error.message}`);
803
+ throw new Error(
804
+ `处理JSON文件失败 [file: ${jsonFileName}]: ${error.message}`
805
+ );
682
806
  }
683
807
  });
684
808
  } catch (error) {
@@ -718,12 +842,19 @@ export async function buildStatic() {
718
842
  await compilePagesPugToFn();
719
843
  const PagesPugToFn = await import(paths.pagesPugFn);
720
844
 
845
+ // 显示HTML压缩状态
846
+ if (config.minifyHtml) {
847
+ console.log("HTML压缩功能已启用");
848
+ } else {
849
+ console.log("HTML压缩功能已禁用");
850
+ }
851
+
721
852
  // 处理每种语言
722
853
  await async.eachSeries(config.languageList, async (lang) => {
723
854
  try {
724
855
  console.log("开始处理语言:", lang);
725
856
  const langDataPath = paths.resolveRoot(jsonDataPath, lang);
726
-
857
+
727
858
  // 读取公共数据
728
859
  let commonData;
729
860
  try {
@@ -738,10 +869,22 @@ export async function buildStatic() {
738
869
  const dealWithEndFunName = new Map();
739
870
 
740
871
  // 处理自定义HTML构建
741
- await processCustomBuildHtml(PagesPugToFn, lang, getData, commonData, dealWithEndFunName);
872
+ await processCustomBuildHtml(
873
+ PagesPugToFn,
874
+ lang,
875
+ getData,
876
+ commonData,
877
+ dealWithEndFunName
878
+ );
742
879
 
743
880
  // 处理页面JSON文件
744
- await processPageJsonFiles(PagesPugToFn, lang, langDataPath, commonData, dealWithEndFunName);
881
+ await processPageJsonFiles(
882
+ PagesPugToFn,
883
+ lang,
884
+ langDataPath,
885
+ commonData,
886
+ dealWithEndFunName
887
+ );
745
888
 
746
889
  console.log("处理语言:", lang, "完成");
747
890
  } catch (error) {
@@ -763,7 +906,6 @@ export async function buildStatic() {
763
906
  }
764
907
 
765
908
  console.log("打包完成花费:", (Date.now() - starTime) / 1000, "s");
766
-
767
909
  } catch (error) {
768
910
  console.error("HTML文件打包失败:", error);
769
911
  throw error;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pug-site-core",
3
- "version": "3.0.3",
3
+ "version": "3.0.4",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -30,6 +30,7 @@
30
30
  "express-useragent": "^1.0.15",
31
31
  "fs-extra": "^11.2.0",
32
32
  "glob": "^10.3.10",
33
+ "html-minifier-terser": "^7.2.0",
33
34
  "http-proxy-middleware": "^3.0.5",
34
35
  "imagemin": "^8.0.1",
35
36
  "imagemin-gifsicle": "^7.0.0",
@@ -51,7 +52,7 @@
51
52
  "ws": "^8.18.0"
52
53
  },
53
54
  "license": "ISC",
54
- "description": "修复对带.符号的文件名处理",
55
+ "description": "增加html文件的压缩功能以及修改并发数",
55
56
  "files": [
56
57
  "lib/",
57
58
  "index.js"