pug-site-core 1.0.1
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/index.js +4 -0
- package/lib/devServer.js +232 -0
- package/lib/generate.js +674 -0
- package/lib/pugRuntime.js +1 -0
- package/lib/translate.js +98 -0
- package/lib/utils.js +374 -0
- package/lib/watchFile.js +32 -0
- package/package.json +34 -0
package/lib/generate.js
ADDED
|
@@ -0,0 +1,674 @@
|
|
|
1
|
+
import fse from "fs-extra";
|
|
2
|
+
import pug from "pug";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import {
|
|
5
|
+
getPagesPugFilePathArr,
|
|
6
|
+
getCompilePugFilter,
|
|
7
|
+
pathIsSame,
|
|
8
|
+
sleep,
|
|
9
|
+
pagesPathFilter,
|
|
10
|
+
pathSymbol,
|
|
11
|
+
obfuscateJavaScript
|
|
12
|
+
} from "./utils.js";
|
|
13
|
+
import _ from "lodash";
|
|
14
|
+
import { config } from "./config.js";
|
|
15
|
+
import async from "async";
|
|
16
|
+
import UglifyJS from "uglify-js";
|
|
17
|
+
|
|
18
|
+
const __dirname = path.resolve();
|
|
19
|
+
const pugRootPath = path.join(__dirname, "/template/pages");
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 将pages目录下的pug模板编译为JS函数
|
|
23
|
+
* @param {string} pugPath - 指定编译的pug文件路径(相对于/template/pages)
|
|
24
|
+
* @throws {Error} 当路径不存在或编译失败时抛出错误
|
|
25
|
+
* @returns {Promise<void>}
|
|
26
|
+
*/
|
|
27
|
+
export async function compilePagesPugToFn(pugPath) {
|
|
28
|
+
try {
|
|
29
|
+
// 获取所有需要编译的pug文件路径
|
|
30
|
+
const pagesPugFilePathArr = await getPagesPugFilePathArr();
|
|
31
|
+
const fnRootPath = path.join(__dirname, "/pagesPugFn");
|
|
32
|
+
|
|
33
|
+
// 读取pug运行时代码作为基础代码
|
|
34
|
+
const lastPugFnStr = await fse.readFile("./pugRuntime.js", "utf8");
|
|
35
|
+
|
|
36
|
+
// 验证指定路径是否存在
|
|
37
|
+
if (pugPath && !fse.pathExistsSync(path.join(pugRootPath, pugPath))) {
|
|
38
|
+
throw new Error("路径不存在! 注意路径前面会自动拼接/template/pages");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let compiledCode = lastPugFnStr;
|
|
42
|
+
|
|
43
|
+
// 使用async库并发编译pug文件
|
|
44
|
+
await async.eachLimit(
|
|
45
|
+
// 过滤出需要编译的文件
|
|
46
|
+
pagesPugFilePathArr.filter(
|
|
47
|
+
(fileName) => !pugPath || pathIsSame(pugPath, fileName)
|
|
48
|
+
),
|
|
49
|
+
10, // 限制并发数为10
|
|
50
|
+
async (fileName) => {
|
|
51
|
+
const filePath = path.join(pugRootPath, fileName);
|
|
52
|
+
const funName = fileName.split(pathSymbol).join("_").slice(0, -4);
|
|
53
|
+
|
|
54
|
+
// 读取并编译pug文件
|
|
55
|
+
const pugValue = await fse.readFile(filePath, "utf8");
|
|
56
|
+
const fnStr = pug.compileClient(pugValue, {
|
|
57
|
+
filename: filePath,
|
|
58
|
+
basedir: path.join(__dirname, "/template"),
|
|
59
|
+
compileDebug: true,
|
|
60
|
+
name: funName,
|
|
61
|
+
filters: getCompilePugFilter()
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// 提取函数定义部分
|
|
65
|
+
const functionStart = fnStr.indexOf(`function ${funName}(locals)`);
|
|
66
|
+
const functionEnd = fnStr.lastIndexOf("}") + 1;
|
|
67
|
+
|
|
68
|
+
if (functionStart === -1) {
|
|
69
|
+
throw new Error(`无法在编译结果中找到函数 ${funName}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 只提取函数定义部分并转换为ES模块格式
|
|
73
|
+
const functionBody = fnStr.slice(functionStart, functionEnd);
|
|
74
|
+
const exportFn = functionBody.replace(
|
|
75
|
+
`function ${funName}(locals)`,
|
|
76
|
+
`export function ${funName}(locals)`
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
compiledCode += exportFn;
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
// 压缩代码
|
|
84
|
+
const result = UglifyJS.minify(compiledCode);
|
|
85
|
+
if (result.error) {
|
|
86
|
+
throw new Error(`代码压缩失败: ${result.error}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 写入最终文件
|
|
90
|
+
const outputPath = path.join(fnRootPath, "index.js");
|
|
91
|
+
await fse.ensureFile(outputPath);
|
|
92
|
+
await fse.writeFile(outputPath, result.code);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error("编译PUG模板失败:", error);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 向getData.js中注入数据获取函数
|
|
101
|
+
* 为每个pug模板自动生成对应的数据获取函数
|
|
102
|
+
* @returns {Promise<void>}
|
|
103
|
+
*/
|
|
104
|
+
export async function generateGetDataFn() {
|
|
105
|
+
try {
|
|
106
|
+
const getDataFile = await fse.readFile("./getData.js", "utf8");
|
|
107
|
+
const pagesPugFilePathArr = await getPagesPugFilePathArr(true);
|
|
108
|
+
|
|
109
|
+
// 注入公共数据获取函数
|
|
110
|
+
if (!getDataFile.includes("get_common_data")) {
|
|
111
|
+
const commonDataFn = `export async function get_common_data(language) {
|
|
112
|
+
return {}
|
|
113
|
+
}\n`;
|
|
114
|
+
await fse.appendFile("./getData.js", commonDataFn);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 为每个页面注入数据获取函数
|
|
118
|
+
await async.each(pagesPugFilePathArr, async (fileName) => {
|
|
119
|
+
const funName =
|
|
120
|
+
"get_" + fileName.split(pathSymbol).join("_").slice(0, -4) + "_data";
|
|
121
|
+
|
|
122
|
+
if (!getDataFile.includes(funName)) {
|
|
123
|
+
const template = config.getDataFnTemplate
|
|
124
|
+
.toString()
|
|
125
|
+
.replace("template", funName);
|
|
126
|
+
const dataFn = `\nexport async ${template}`;
|
|
127
|
+
await fse.appendFile("./getData.js", dataFn);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error("生成数据函数失败:", error);
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 调用getData中的函数获取模版数据并写入JSON文件
|
|
138
|
+
* @param {string[]} args - 命令行参数,用于过滤模板和语言
|
|
139
|
+
*/
|
|
140
|
+
export async function fetchDataToJsonFile(args) {
|
|
141
|
+
const JsonRootPath = path.join(__dirname, "/jsonData");
|
|
142
|
+
|
|
143
|
+
// 解析过滤参数
|
|
144
|
+
let filterFun = [];
|
|
145
|
+
let filterLang = [];
|
|
146
|
+
args.forEach((item) => {
|
|
147
|
+
const [key, value] = item.split("=");
|
|
148
|
+
if (value) {
|
|
149
|
+
if (key === "f") {
|
|
150
|
+
filterFun = value.split(",");
|
|
151
|
+
}
|
|
152
|
+
if (key === "c") {
|
|
153
|
+
filterLang = value.split(",");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// 如果没有过滤条件,清空输出目录
|
|
159
|
+
if (!filterFun.length && !filterLang.length) {
|
|
160
|
+
await fse.remove(JsonRootPath);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const getData = await import("./getData.js");
|
|
164
|
+
let arrPagesPugFilePathArr = await getPagesPugFilePathArr();
|
|
165
|
+
let pagesPugFilePathArr = await getPagesPugFilePathArr(true);
|
|
166
|
+
let filterFinishArr = arrPagesPugFilePathArr.filter(
|
|
167
|
+
(item) => !pagesPugFilePathArr.includes(item)
|
|
168
|
+
);
|
|
169
|
+
const { languageList, fileMapTable, fetchDataLangLimit } = config;
|
|
170
|
+
let starTime = Date.now();
|
|
171
|
+
|
|
172
|
+
await async.eachLimit(languageList, fetchDataLangLimit, async (language) => {
|
|
173
|
+
// 语言过滤
|
|
174
|
+
if (filterLang.length && !filterLang.includes(language)) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 清空指定语言的数据目录
|
|
179
|
+
if (filterLang.includes(language) && !filterFun.length) {
|
|
180
|
+
await fse.remove(path.join(JsonRootPath, language));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 处理公共数据
|
|
184
|
+
const commonFuncName = "get_common_data";
|
|
185
|
+
if (!filterFun.length || filterFun.includes(commonFuncName)) {
|
|
186
|
+
const commonData = await getData[commonFuncName](language);
|
|
187
|
+
console.log(language, commonFuncName, "开始写入json文件");
|
|
188
|
+
await fse.outputJSON(
|
|
189
|
+
path.join(JsonRootPath, language, "_common.json"),
|
|
190
|
+
commonData
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// 处理文件映射表数据
|
|
195
|
+
if (fileMapTable?.length) {
|
|
196
|
+
await async.each(fileMapTable, async (obj) => {
|
|
197
|
+
if (
|
|
198
|
+
obj.getDataFn &&
|
|
199
|
+
!obj.pugPath &&
|
|
200
|
+
obj.outPutPath &&
|
|
201
|
+
obj.outPutPath.endsWith(".json")
|
|
202
|
+
) {
|
|
203
|
+
if (
|
|
204
|
+
obj.languageList &&
|
|
205
|
+
obj.languageList.length > 0 &&
|
|
206
|
+
!obj.languageList.includes(language)
|
|
207
|
+
) {
|
|
208
|
+
return Promise.resolve();
|
|
209
|
+
}
|
|
210
|
+
let dataFn = getData[obj.getDataFn];
|
|
211
|
+
if (!dataFn || typeof dataFn !== "function") {
|
|
212
|
+
return Promise.reject(dataFn + "获取数据函数不存在!");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (filterFun.length && !filterFun.includes(funName)) {
|
|
216
|
+
return Promise.resolve();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
let data = await dataFn(language);
|
|
220
|
+
if (!data) {
|
|
221
|
+
return Promise.reject(dataFn + "获取的数据为null!");
|
|
222
|
+
}
|
|
223
|
+
console.log(language, obj.getDataFn, "开始写入json文件");
|
|
224
|
+
let outPutPath = obj.outPutPath.split("/").join(pathSymbol);
|
|
225
|
+
let jsonFilePath;
|
|
226
|
+
if (Array.isArray(data)) {
|
|
227
|
+
let name = outPutPath.split(pathSymbol).pop().replace(/\..*$/, "");
|
|
228
|
+
const regex = /^\[.+\]$/;
|
|
229
|
+
if (regex.test(name)) {
|
|
230
|
+
let property = name.slice(1, -1);
|
|
231
|
+
for (let index = 0; index < data.length; index++) {
|
|
232
|
+
const dataItem = data[index];
|
|
233
|
+
let fileName = dataItem[property];
|
|
234
|
+
if (
|
|
235
|
+
fileName === null ||
|
|
236
|
+
fileName === undefined ||
|
|
237
|
+
fileName === ""
|
|
238
|
+
) {
|
|
239
|
+
return Promise.reject(
|
|
240
|
+
dataFn +
|
|
241
|
+
"获取的数据中期望以" +
|
|
242
|
+
property +
|
|
243
|
+
`命名但是${index}下标中对象属性不存在`
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
jsonFilePath = path.join(
|
|
247
|
+
JsonRootPath,
|
|
248
|
+
language,
|
|
249
|
+
outPutPath.replace(name, fileName)
|
|
250
|
+
);
|
|
251
|
+
await fse.remove(jsonFilePath);
|
|
252
|
+
await fse.outputJson(jsonFilePath, dataItem);
|
|
253
|
+
}
|
|
254
|
+
} else {
|
|
255
|
+
jsonFilePath = path.join(JsonRootPath, language, outPutPath);
|
|
256
|
+
await fse.remove(jsonFilePath);
|
|
257
|
+
await fse.outputJson(jsonFilePath, data);
|
|
258
|
+
}
|
|
259
|
+
} else if (typeof data === "object") {
|
|
260
|
+
jsonFilePath = path.join(JsonRootPath, language, outPutPath);
|
|
261
|
+
await fse.remove(jsonFilePath);
|
|
262
|
+
await fse.outputJson(jsonFilePath, data);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
await async.each(pagesPugFilePathArr, async (fileName) => {
|
|
269
|
+
let funName =
|
|
270
|
+
"get_" + fileName.split(pathSymbol).join("_").slice(0, -4) + "_data";
|
|
271
|
+
|
|
272
|
+
let jsonFilePath = fileName.slice(0, -4).split(pathSymbol);
|
|
273
|
+
if (!getData[funName] || typeof getData[funName] !== "function") {
|
|
274
|
+
console.log(funName, "获取数据函数不存在!");
|
|
275
|
+
return Promise.reject(funName + "获取数据函数不存在!");
|
|
276
|
+
}
|
|
277
|
+
if (filterFun.length && !filterFun.includes(funName)) {
|
|
278
|
+
return Promise.resolve();
|
|
279
|
+
}
|
|
280
|
+
let data = await getData[funName](language);
|
|
281
|
+
if (Array.isArray(data) && data.length > 0) {
|
|
282
|
+
console.log(language, funName, "开始写入json文件");
|
|
283
|
+
await async.eachOfLimit(data, 1000, async (item, index) => {
|
|
284
|
+
if (typeof item !== "object" || Array.isArray(item)) {
|
|
285
|
+
let type = Array.isArray(item) ? "array" : typeof item;
|
|
286
|
+
return Promise.reject(
|
|
287
|
+
funName + "返回的数据不为对象数组得到类型" + type + "[]"
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
let lastJsonFilePath;
|
|
291
|
+
if (item.page_name && item.page_name.length > 0) {
|
|
292
|
+
lastJsonFilePath = path.join(
|
|
293
|
+
JsonRootPath,
|
|
294
|
+
language,
|
|
295
|
+
...jsonFilePath.slice(0, -1),
|
|
296
|
+
item.page_name
|
|
297
|
+
);
|
|
298
|
+
} else {
|
|
299
|
+
lastJsonFilePath =
|
|
300
|
+
path.join(JsonRootPath, language, ...jsonFilePath) +
|
|
301
|
+
"_" +
|
|
302
|
+
++index +
|
|
303
|
+
".json";
|
|
304
|
+
}
|
|
305
|
+
let templateArr = filterFinishArr.filter(
|
|
306
|
+
(item) => pagesPathFilter(item) === fileName
|
|
307
|
+
);
|
|
308
|
+
if (fse.pathExistsSync(path.join(pugRootPath, fileName))) {
|
|
309
|
+
templateArr.unshift(fileName);
|
|
310
|
+
}
|
|
311
|
+
item._template = templateArr;
|
|
312
|
+
await fse.remove(lastJsonFilePath);
|
|
313
|
+
await fse.outputJson(lastJsonFilePath, item);
|
|
314
|
+
});
|
|
315
|
+
} else if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
316
|
+
console.log(language, funName, "开始写入json文件");
|
|
317
|
+
if (data.page_name && data.page_name.length > 0) {
|
|
318
|
+
jsonFilePath = path.join(
|
|
319
|
+
JsonRootPath,
|
|
320
|
+
language,
|
|
321
|
+
...jsonFilePath.slice(0, -1),
|
|
322
|
+
data.page_name
|
|
323
|
+
);
|
|
324
|
+
} else {
|
|
325
|
+
jsonFilePath =
|
|
326
|
+
path.join(JsonRootPath, language, ...jsonFilePath) + ".json";
|
|
327
|
+
}
|
|
328
|
+
let templateArr = filterFinishArr.filter(
|
|
329
|
+
(item) => pagesPathFilter(item) === fileName
|
|
330
|
+
);
|
|
331
|
+
if (fse.pathExistsSync(path.join(pugRootPath, fileName))) {
|
|
332
|
+
templateArr.unshift(fileName);
|
|
333
|
+
}
|
|
334
|
+
data._template = templateArr;
|
|
335
|
+
await fse.remove(jsonFilePath);
|
|
336
|
+
await fse.outputJson(jsonFilePath, data);
|
|
337
|
+
} else {
|
|
338
|
+
console.log(language, funName, "期望返回数组、对象类型返回:", data);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
console.log("写入完成花费:", (Date.now() - starTime) / 1000, "s");
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export async function buildFn() {
|
|
346
|
+
if (!fse.pathExistsSync(path.join(__dirname, "jsonData"))) {
|
|
347
|
+
return Promise.reject(
|
|
348
|
+
path.join(__dirname, "jsonData"),
|
|
349
|
+
"目录不存在请先执行npm run getData生成数据!"
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
console.log("开始打包...");
|
|
353
|
+
let starTime = Date.now();
|
|
354
|
+
let outputPath = path.join(__dirname, config.fnOutput);
|
|
355
|
+
await fse.remove(outputPath);
|
|
356
|
+
await sleep(0);
|
|
357
|
+
await compilePagesPugToFn();
|
|
358
|
+
await fse.copy(
|
|
359
|
+
path.join(__dirname, "pagesPugFn/index.js"),
|
|
360
|
+
path.join(outputPath, "page/pages.js")
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
if (!fse.pathExistsSync(path.join(__dirname, "router.js"))) {
|
|
364
|
+
return Promise.reject("router.js文件不存在!");
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
await fse.copy(
|
|
368
|
+
path.join(__dirname, "router.js"),
|
|
369
|
+
path.join(outputPath, "page/router.js")
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
await fse.copy(path.join(__dirname, "public"), path.join(outputPath, "page"));
|
|
373
|
+
|
|
374
|
+
let totalCommonData = {};
|
|
375
|
+
totalCommonData.langCommon = config.commonData;
|
|
376
|
+
await async.each(config.languageList, async (lang) => {
|
|
377
|
+
let commonData = await fse.readJSON(
|
|
378
|
+
path.join(__dirname, "jsonData", lang, "_common.json")
|
|
379
|
+
);
|
|
380
|
+
totalCommonData[lang] = commonData;
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
await fse.copy(
|
|
384
|
+
path.join(__dirname, "jsonData"),
|
|
385
|
+
path.join(outputPath, "data"),
|
|
386
|
+
{
|
|
387
|
+
filter: (src, dest) => {
|
|
388
|
+
// 排除_common.json 文件
|
|
389
|
+
return !src.endsWith("_common.json");
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
await fse.copy(
|
|
395
|
+
path.join(__dirname, "/template/static"),
|
|
396
|
+
path.join(outputPath, "page/static"),
|
|
397
|
+
{
|
|
398
|
+
filter: (src, dest) => {
|
|
399
|
+
//根目录必须要返回true
|
|
400
|
+
if (src.endsWith("static")) {
|
|
401
|
+
return true;
|
|
402
|
+
}
|
|
403
|
+
if (config.buildStaticDirArr && config.buildStaticDirArr.length > 0) {
|
|
404
|
+
return !!config.buildStaticDirArr.find((item) => {
|
|
405
|
+
return src.startsWith(
|
|
406
|
+
path.join(__dirname, "/template/static", item)
|
|
407
|
+
);
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
return true;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
await fse.writeJSON(
|
|
416
|
+
path.join(outputPath, "page", "common") + ".json",
|
|
417
|
+
totalCommonData
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
if (config.obfuscateJavaScript) {
|
|
421
|
+
console.log("开始混淆js文件...");
|
|
422
|
+
const startTime = Date.now();
|
|
423
|
+
await obfuscateJavaScript(path.join(outputPath, "page", "static"));
|
|
424
|
+
const costTime = (Date.now() - startTime) / 1000;
|
|
425
|
+
console.log("混淆js文件耗时:", costTime, "s");
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
console.log("打包完成花费:", (Date.now() - starTime) / 1000, "s");
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
//html文件打包 不维护了
|
|
432
|
+
export async function buildStatic() {
|
|
433
|
+
let jsonDataPath = path.join(__dirname, "jsonData");
|
|
434
|
+
|
|
435
|
+
if (!fse.pathExistsSync(jsonDataPath)) {
|
|
436
|
+
return Promise.reject(
|
|
437
|
+
jsonDataPath + "目录不存在请先执行npm run getData生成数据!"
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
console.log("开始打包...");
|
|
441
|
+
let starTime = Date.now();
|
|
442
|
+
let distOutputPath = path.join(__dirname, config.staticOutput);
|
|
443
|
+
await fse.remove(distOutputPath);
|
|
444
|
+
await sleep(0);
|
|
445
|
+
await fse.copy(path.join(__dirname, "public"), distOutputPath);
|
|
446
|
+
|
|
447
|
+
await fse.copy(
|
|
448
|
+
path.join(__dirname, "/template/static"),
|
|
449
|
+
path.join(distOutputPath, "static"),
|
|
450
|
+
{
|
|
451
|
+
filter: (src, dest) => {
|
|
452
|
+
//根目录必须要返回true
|
|
453
|
+
if (src.endsWith("static")) {
|
|
454
|
+
return true;
|
|
455
|
+
}
|
|
456
|
+
if (config.buildStaticDirArr && config.buildStaticDirArr.length > 0) {
|
|
457
|
+
return !!config.buildStaticDirArr.find((item) => {
|
|
458
|
+
return src.startsWith(
|
|
459
|
+
path.join(__dirname, "/template/static", item)
|
|
460
|
+
);
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
await compilePagesPugToFn();
|
|
469
|
+
let PagesPugToFn = await import("./pagesPugFn/index.js");
|
|
470
|
+
const getData = await import("./getData.js");
|
|
471
|
+
const fileMapTable = config.fileMapTable;
|
|
472
|
+
await async.each(config.languageList, async (lang) => {
|
|
473
|
+
let langDataPath = path.join(jsonDataPath, lang);
|
|
474
|
+
if (!fse.pathExistsSync(langDataPath)) {
|
|
475
|
+
console.log(
|
|
476
|
+
`注意配置了${lang}语言但${langDataPath}中没有生成${lang}语言的数据!`
|
|
477
|
+
);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
let commonData = await fse.readJSON(
|
|
481
|
+
path.join(__dirname, "jsonData", lang, "_common.json")
|
|
482
|
+
);
|
|
483
|
+
commonData = _.merge(commonData, config.commonData);
|
|
484
|
+
|
|
485
|
+
if (fileMapTable && Array.isArray(fileMapTable)) {
|
|
486
|
+
await async.each(fileMapTable, async (obj) => {
|
|
487
|
+
if (
|
|
488
|
+
obj.pugPath &&
|
|
489
|
+
obj.getDataFn &&
|
|
490
|
+
obj.outPutPath &&
|
|
491
|
+
obj.outPutPath.endsWith(".html")
|
|
492
|
+
) {
|
|
493
|
+
if (
|
|
494
|
+
obj.languageList &&
|
|
495
|
+
obj.languageList.length > 0 &&
|
|
496
|
+
!obj.languageList.includes(lang)
|
|
497
|
+
) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
let langPrefix =
|
|
501
|
+
obj.languageList && obj.languageList.length > 0 ? lang : "";
|
|
502
|
+
let pugPathPreArr = [""];
|
|
503
|
+
if (obj.deviceList && obj.deviceList.length > 0) {
|
|
504
|
+
pugPathPreArr = obj.deviceList;
|
|
505
|
+
}
|
|
506
|
+
await async.each(pugPathPreArr, async (devicePrefix) => {
|
|
507
|
+
let pugPath = path.join(
|
|
508
|
+
pugRootPath,
|
|
509
|
+
langPrefix,
|
|
510
|
+
devicePrefix,
|
|
511
|
+
obj.pugPath.split("/").join(pathSymbol)
|
|
512
|
+
);
|
|
513
|
+
if (!fse.pathExistsSync(pugPath)) {
|
|
514
|
+
return Promise.reject(pugPath + "模版路径不存在!");
|
|
515
|
+
}
|
|
516
|
+
let dataFn = getData[obj.getDataFn];
|
|
517
|
+
if (!dataFn || typeof dataFn !== "function") {
|
|
518
|
+
return Promise.reject(dataFn + "获取数据函数不存在!");
|
|
519
|
+
}
|
|
520
|
+
let data = await dataFn(lang);
|
|
521
|
+
if (!data) {
|
|
522
|
+
return Promise.reject(dataFn + "获取的数据为null!");
|
|
523
|
+
}
|
|
524
|
+
let outPutPath = obj.outPutPath.split("/").join(pathSymbol);
|
|
525
|
+
let htmlPath;
|
|
526
|
+
let html;
|
|
527
|
+
if (Array.isArray(data)) {
|
|
528
|
+
let name = outPutPath
|
|
529
|
+
.split(pathSymbol)
|
|
530
|
+
.pop()
|
|
531
|
+
.replace(/\..*$/, "");
|
|
532
|
+
const regex = /^\[.+\]$/;
|
|
533
|
+
if (regex.test(name)) {
|
|
534
|
+
let property = name.slice(1, -1);
|
|
535
|
+
for (let index = 0; index < data.length; index++) {
|
|
536
|
+
const dataItem = data[index];
|
|
537
|
+
let fileName = dataItem[property];
|
|
538
|
+
if (
|
|
539
|
+
fileName === null ||
|
|
540
|
+
fileName === undefined ||
|
|
541
|
+
fileName === ""
|
|
542
|
+
) {
|
|
543
|
+
return Promise.reject(
|
|
544
|
+
dataFn +
|
|
545
|
+
"获取的数据中期望以" +
|
|
546
|
+
property +
|
|
547
|
+
`命名但是${index}下标中对象${property}属性为:${fileName}`
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
htmlPath = path.join(
|
|
551
|
+
distOutputPath,
|
|
552
|
+
lang,
|
|
553
|
+
devicePrefix,
|
|
554
|
+
outPutPath.replace(name, fileName)
|
|
555
|
+
);
|
|
556
|
+
html = pug.compileFile(pugPath, {
|
|
557
|
+
basedir: path.join(__dirname, "/template"),
|
|
558
|
+
compileDebug: true,
|
|
559
|
+
filters: getCompilePugFilter()
|
|
560
|
+
})({
|
|
561
|
+
data: dataItem,
|
|
562
|
+
_pagePath: obj.pugPath,
|
|
563
|
+
common: commonData
|
|
564
|
+
});
|
|
565
|
+
fse.ensureFileSync(htmlPath);
|
|
566
|
+
await fse.writeFile(htmlPath, html);
|
|
567
|
+
}
|
|
568
|
+
} else {
|
|
569
|
+
htmlPath = path.join(
|
|
570
|
+
__dirname,
|
|
571
|
+
"template",
|
|
572
|
+
lang,
|
|
573
|
+
devicePrefix,
|
|
574
|
+
outPutPath
|
|
575
|
+
);
|
|
576
|
+
html = pug.compileFile(pugPath, {
|
|
577
|
+
basedir: path.join(__dirname, "/template"),
|
|
578
|
+
compileDebug: true,
|
|
579
|
+
filters: getCompilePugFilter()
|
|
580
|
+
})({
|
|
581
|
+
data,
|
|
582
|
+
_pagePath: obj.pugPath,
|
|
583
|
+
common: commonData
|
|
584
|
+
});
|
|
585
|
+
fse.ensureFileSync(htmlPath);
|
|
586
|
+
await fse.writeFile(htmlPath, html);
|
|
587
|
+
}
|
|
588
|
+
} else if (typeof data === "object") {
|
|
589
|
+
htmlPath = path.join(
|
|
590
|
+
distOutputPath,
|
|
591
|
+
lang,
|
|
592
|
+
devicePrefix,
|
|
593
|
+
outPutPath
|
|
594
|
+
);
|
|
595
|
+
html = pug.compileFile(pugPath, {
|
|
596
|
+
basedir: path.join(__dirname, "/template"),
|
|
597
|
+
compileDebug: true,
|
|
598
|
+
filters: getCompilePugFilter()
|
|
599
|
+
})({
|
|
600
|
+
data,
|
|
601
|
+
_pagePath: obj.pugPath,
|
|
602
|
+
common: commonData
|
|
603
|
+
});
|
|
604
|
+
fse.ensureFileSync(htmlPath);
|
|
605
|
+
await fse.writeFile(htmlPath, html);
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
let pagesAllJsonFileName = (
|
|
613
|
+
await fse.readdir(path.join(langDataPath), {
|
|
614
|
+
recursive: true
|
|
615
|
+
})
|
|
616
|
+
).filter((fileName) => fileName.endsWith(".json"));
|
|
617
|
+
await async.eachLimit(pagesAllJsonFileName, 64, async (jsonFileName) => {
|
|
618
|
+
let data = await fse.readJSON(path.join(langDataPath, jsonFileName));
|
|
619
|
+
let pugTemplateArr = data._template;
|
|
620
|
+
if (!pugTemplateArr) {
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
let flag = false;
|
|
624
|
+
|
|
625
|
+
let curLangPugTem = data._template.find((item) => {
|
|
626
|
+
let lang2 = item.split(pathSymbol)[0];
|
|
627
|
+
if (config.languageList.includes(lang2) && lang === lang2) {
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
if (curLangPugTem) {
|
|
632
|
+
flag = true;
|
|
633
|
+
pugTemplateArr = [curLangPugTem];
|
|
634
|
+
} else {
|
|
635
|
+
//没有特殊模版的语言排除其他语言的特殊模版
|
|
636
|
+
pugTemplateArr = data._template.filter((item) => {
|
|
637
|
+
let lang2 = item.split(pathSymbol)[0];
|
|
638
|
+
if (config.languageList.includes(lang2)) {
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
return true;
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
await async.each(pugTemplateArr, (pugTemplate, callback) => {
|
|
646
|
+
let funName = pugTemplate.split(pathSymbol).join("_").slice(0, -4);
|
|
647
|
+
if (flag) {
|
|
648
|
+
pugTemplate = pugTemplate.split(pathSymbol).slice(1).join(pathSymbol);
|
|
649
|
+
}
|
|
650
|
+
let html = PagesPugToFn[funName]({
|
|
651
|
+
data,
|
|
652
|
+
_pagePath: pugTemplate,
|
|
653
|
+
common: commonData
|
|
654
|
+
});
|
|
655
|
+
if (data.page_name) {
|
|
656
|
+
pugTemplate =
|
|
657
|
+
pugTemplate.split(pathSymbol).slice(0, -1).join(pathSymbol) +
|
|
658
|
+
pathSymbol +
|
|
659
|
+
data.page_name;
|
|
660
|
+
}
|
|
661
|
+
let htmlPath = path.join(
|
|
662
|
+
distOutputPath,
|
|
663
|
+
lang,
|
|
664
|
+
pugTemplate.replace(/\..*$/, ".html")
|
|
665
|
+
);
|
|
666
|
+
fse.ensureFileSync(htmlPath);
|
|
667
|
+
const writeStream = fse.createWriteStream(htmlPath);
|
|
668
|
+
writeStream.write(html);
|
|
669
|
+
writeStream.end(callback);
|
|
670
|
+
});
|
|
671
|
+
});
|
|
672
|
+
});
|
|
673
|
+
console.log("打包完成花费:", (Date.now() - starTime) / 1000, "s");
|
|
674
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var pug_has_own_property=Object.prototype.hasOwnProperty;function pug_merge(a,b){if(arguments.length===1){var attrs=a[0];for(var i=1;i<a.length;i++){attrs=pug_merge(attrs,a[i])}return attrs}for(var key in b){if(key==="class"){var valA=a[key]||[];a[key]=(Array.isArray(valA)?valA:[valA]).concat(b[key]||[])}else if(key==="style"){var valA=pug_style(a[key]);valA=valA&&valA[valA.length-1]!==";"?valA+";":valA;var valB=pug_style(b[key]);valB=valB&&valB[valB.length-1]!==";"?valB+";":valB;a[key]=valA+valB}else{a[key]=b[key]}}return a}function pug_classes_array(val,escaping){var classString="",className,padding="",escapeEnabled=Array.isArray(escaping);for(var i=0;i<val.length;i++){className=pug_classes(val[i]);if(!className)continue;escapeEnabled&&escaping[i]&&(className=pug_escape(className));classString=classString+padding+className;padding=" "}return classString}function pug_classes_object(val){var classString="",padding="";for(var key in val){if(key&&val[key]&&pug_has_own_property.call(val,key)){classString=classString+padding+key;padding=" "}}return classString}function pug_classes(val,escaping){if(Array.isArray(val)){return pug_classes_array(val,escaping)}else if(val&&typeof val==="object"){return pug_classes_object(val)}else{return val||""}}function pug_style(val){if(!val)return"";if(typeof val==="object"){var out="";for(var style in val){if(pug_has_own_property.call(val,style)){out=out+style+":"+val[style]+";"}}return out}else{return val+""}}function pug_attr(key,val,escaped,terse){if(val===false||val==null||(!val&&(key==="class"||key==="style"))){return""}if(val===true){return" "+(terse?key:key+'="'+key+'"')}var type=typeof val;if((type==="object"||type==="function")&&typeof val.toJSON==="function"){val=val.toJSON()}if(typeof val!=="string"){val=JSON.stringify(val);if(!escaped&&val.indexOf('"')!==-1){return" "+key+"='"+val.replace(/'/g,"'")+"'"}}if(escaped)val=pug_escape(val);return" "+key+'="'+val+'"'}function pug_attrs(obj,terse){var attrs="";for(var key in obj){if(pug_has_own_property.call(obj,key)){var val=obj[key];if("class"===key){val=pug_classes(val);attrs=pug_attr(key,val,false,terse)+attrs;continue}if("style"===key){val=pug_style(val)}attrs+=pug_attr(key,val,false,terse)}}return attrs}var pug_match_html=/["&<>]/;function pug_escape(_html){var html=""+_html;var regexResult=pug_match_html.exec(html);if(!regexResult)return _html;var result="";var i,lastIndex,escape;for(i=regexResult.index,lastIndex=0;i<html.length;i++){switch(html.charCodeAt(i)){case 34:escape=""";break;case 38:escape="&";break;case 60:escape="<";break;case 62:escape=">";break;default:continue}if(lastIndex!==i)result+=html.substring(lastIndex,i);lastIndex=i+1;result+=escape}if(lastIndex!==i)return result+html.substring(lastIndex,i);else return result}function pug_rethrow(err,filename,lineno,str){if(!(err instanceof Error))throw err;if((typeof window!="undefined"||!filename)&&!str){err.message+=" on line "+lineno;throw err;}var context,lines,start,end;try{str=str||require("fs").readFileSync(filename,{encoding:"utf8"});context=3;lines=str.split("\n");start=Math.max(lineno-context,0);end=Math.min(lines.length,lineno+context)}catch(ex){err.message+=" - could not read from "+filename+" ("+ex.message+")";pug_rethrow(err,null,lineno);return}context=lines.slice(start,end).map(function(line,i){var curr=i+start+1;return(curr==lineno?" > ":" ")+curr+"| "+line}).join("\n");err.path=filename;try{err.message=(filename||"Pug")+":"+lineno+"\n"+context+"\n\n"+err.message}catch(e){}throw err;}
|