2023-04-07 17:54:47 +00:00
|
|
|
const {
|
|
|
|
lstatSync,
|
|
|
|
readdirSync,
|
|
|
|
mkdirSync,
|
|
|
|
copyFileSync,
|
|
|
|
writeFileSync,
|
|
|
|
readFileSync,
|
|
|
|
exists,
|
|
|
|
} = require("fs");
|
|
|
|
const { join, basename, dirname } = require("path");
|
|
|
|
|
|
|
|
const isDirectory = (source) => lstatSync(source).isDirectory();
|
|
|
|
const getDirectories = (source) =>
|
|
|
|
readdirSync(source)
|
|
|
|
.map((name) => join(source, name))
|
|
|
|
.filter(isDirectory);
|
|
|
|
|
|
|
|
function ensureDir(folder) {
|
|
|
|
try {
|
|
|
|
if (!isDirectory(folder)) mkdirSync(folder);
|
|
|
|
} catch (e) {
|
|
|
|
mkdirSync(folder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const fileExists = (filename) =>
|
|
|
|
new Promise((yes, no) => exists(filename, (exi) => yes(exi)));
|
|
|
|
ensureDir("./out");
|
|
|
|
|
|
|
|
const sass = require("sass");
|
|
|
|
|
|
|
|
function findHead(elm) {
|
|
|
|
if (elm.tagName === "head") return elm;
|
|
|
|
for (let i = 0; i < elm.childNodes.length; i++) {
|
|
|
|
let res = findHead(elm.childNodes[i]);
|
|
|
|
if (res) return res;
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
const rollup = require("rollup");
|
|
|
|
const includepaths = require("rollup-plugin-includepaths");
|
|
|
|
const typescript = require("rollup-plugin-typescript2");
|
|
|
|
const resolve = require("rollup-plugin-node-resolve");
|
|
|
|
const minify = require("html-minifier").minify;
|
|
|
|
const gzipSize = require("gzip-size");
|
|
|
|
|
|
|
|
async function file_name(folder, name, exts) {
|
|
|
|
for (let ext of exts) {
|
|
|
|
let basefile = `${folder}/${name}.${ext}`;
|
|
|
|
if (await fileExists(basefile)) return basefile;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function buildPage(folder) {
|
|
|
|
const pagename = basename(folder);
|
|
|
|
const outpath = "./out/" + pagename;
|
|
|
|
|
|
|
|
ensureDir(outpath);
|
|
|
|
|
|
|
|
const basefile = await file_name(folder, pagename, ["tsx", "ts", "js"]);
|
|
|
|
|
|
|
|
let bundle = await rollup.rollup({
|
|
|
|
input: basefile,
|
|
|
|
plugins: [
|
|
|
|
includepaths({
|
|
|
|
paths: ["shared", "node_modules"],
|
|
|
|
}),
|
|
|
|
typescript(),
|
|
|
|
resolve({
|
|
|
|
// not all files you want to resolve are .js files
|
|
|
|
extensions: [".mjs", ".js", ".jsx", ".json"], // Default: [ '.mjs', '.js', '.json', '.node' ]
|
|
|
|
|
|
|
|
// whether to prefer built-in modules (e.g. `fs`, `path`) or
|
|
|
|
// local ones with the same names
|
|
|
|
preferBuiltins: false, // Default: true
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
treeshake: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
let { output } = await bundle.generate({
|
|
|
|
format: "iife",
|
|
|
|
compact: true,
|
|
|
|
});
|
|
|
|
let { code } = output[0];
|
|
|
|
|
|
|
|
let sass_res = sass.renderSync({
|
|
|
|
file: folder + `/${pagename}.scss`,
|
|
|
|
includePaths: ["./node_modules", folder, "./shared", "../node_modules"],
|
|
|
|
outputStyle: "compressed",
|
|
|
|
});
|
|
|
|
|
|
|
|
let css = "<style>\n" + sass_res.css.toString("utf8") + "\n</style>\n";
|
|
|
|
let script = "<script>\n" + code + "\n</script>\n";
|
|
|
|
let html = readFileSync(`${folder}/${pagename}.hbs`).toString("utf8");
|
|
|
|
|
|
|
|
let idx = html.indexOf("</head>");
|
|
|
|
if (idx < 0) throw new Error("No head element found");
|
|
|
|
let idx2 = html.indexOf("</body>");
|
|
|
|
if (idx2 < 0) throw new Error("No body element found");
|
|
|
|
|
|
|
|
if (idx < idx2) {
|
|
|
|
let part1 = html.slice(0, idx);
|
|
|
|
let part2 = html.slice(idx, idx2);
|
|
|
|
let part3 = html.slice(idx2, html.length);
|
|
|
|
html = part1 + css + part2 + script + part3;
|
|
|
|
} else {
|
|
|
|
let part1 = html.slice(0, idx2);
|
|
|
|
let part2 = html.slice(idx2, idx);
|
|
|
|
let part3 = html.slice(idx, html.length);
|
|
|
|
html = part1 + script + part2 + css + part3;
|
|
|
|
}
|
|
|
|
|
|
|
|
let result = minify(html, {
|
|
|
|
removeAttributeQuotes: true,
|
|
|
|
collapseWhitespace: true,
|
|
|
|
html5: true,
|
|
|
|
keepClosingSlash: true,
|
|
|
|
minifyCSS: false,
|
|
|
|
minifyJS: false,
|
|
|
|
removeComments: true,
|
|
|
|
useShortDoctype: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
let gzips = await gzipSize(result);
|
|
|
|
writeFileSync(`${outpath}/${pagename}.html`, result);
|
|
|
|
let stats = {
|
|
|
|
sass: sass_res.stats,
|
|
|
|
js: {
|
|
|
|
chars: code.length,
|
|
|
|
},
|
|
|
|
css: {
|
|
|
|
chars: css.length,
|
|
|
|
},
|
|
|
|
bundle_size: result.length,
|
|
|
|
gzip_size: gzips,
|
|
|
|
};
|
|
|
|
|
|
|
|
writeFileSync(outpath + `/stats.json`, JSON.stringify(stats, null, " "));
|
|
|
|
}
|
|
|
|
|
|
|
|
async function run() {
|
|
|
|
console.log("Start compiling!");
|
|
|
|
let pages = getDirectories("./src");
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async (e) => {
|
|
|
|
try {
|
|
|
|
await buildPage(e);
|
|
|
|
} catch (er) {
|
|
|
|
console.error("Failed compiling", basename(e));
|
|
|
|
console.log(er);
|
|
|
|
process.exitCode = 1;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
);
|
|
|
|
console.log("Finished compiling!");
|
|
|
|
}
|
|
|
|
|
|
|
|
const chokidar = require("chokidar");
|
|
|
|
if (process.argv.join(" ").toLowerCase().indexOf("watch") >= 0)
|
|
|
|
chokidar
|
|
|
|
.watch(
|
|
|
|
["./src", "./node_modules", "./package.json", "./package-lock.json"],
|
|
|
|
{
|
|
|
|
ignoreInitial: true,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
.on("all", () => run());
|
|
|
|
run();
|