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.
- package/lib/generate.js +190 -48
- 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
|
|
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
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
597
|
+
async function processArrayData(
|
|
598
|
+
pagesPugToFn,
|
|
599
|
+
data,
|
|
600
|
+
obj,
|
|
601
|
+
funName,
|
|
602
|
+
pagePath,
|
|
603
|
+
commonData,
|
|
604
|
+
lang
|
|
605
|
+
) {
|
|
552
606
|
try {
|
|
553
|
-
|
|
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,
|
|
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(
|
|
570
|
-
|
|
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(
|
|
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
|
|
642
|
+
const compressedHtml = await compressHtml(html, htmlPath);
|
|
643
|
+
await fse.outputFile(htmlPath, compressedHtml);
|
|
579
644
|
}
|
|
580
645
|
} catch (error) {
|
|
581
|
-
throw new Error(
|
|
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(
|
|
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
|
|
667
|
+
const compressedHtml = await compressHtml(html, htmlPath);
|
|
668
|
+
await fse.outputFile(htmlPath, compressedHtml);
|
|
593
669
|
} catch (error) {
|
|
594
|
-
throw new Error(
|
|
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(
|
|
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 (
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|
|
760
|
+
await async.eachLimit(pagesAllJsonFileName, 128, async (jsonFileName) => {
|
|
648
761
|
try {
|
|
649
|
-
const data = await fse.readJSON(
|
|
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(
|
|
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
|
|
800
|
+
const compressedHtml = await compressHtml(html, htmlPath);
|
|
801
|
+
await fse.outputFile(htmlPath, compressedHtml);
|
|
680
802
|
} catch (error) {
|
|
681
|
-
throw new Error(
|
|
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(
|
|
872
|
+
await processCustomBuildHtml(
|
|
873
|
+
PagesPugToFn,
|
|
874
|
+
lang,
|
|
875
|
+
getData,
|
|
876
|
+
commonData,
|
|
877
|
+
dealWithEndFunName
|
|
878
|
+
);
|
|
742
879
|
|
|
743
880
|
// 处理页面JSON文件
|
|
744
|
-
await processPageJsonFiles(
|
|
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
|
+
"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"
|