| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- import fs from "node:fs/promises";
- import {constants} from "node:fs";
- import path from "path";
- import htmlMinifier from "html-minifier-terser";
- import esbuild from "esbuild";
- export default async (dir)=>{
- const indexFile = await findIndex(dir);
- if(!indexFile) return;
- let data = {};
- if(path.extname(indexFile) === ".neovan"){
- data = await getNeovanData(indexFile);
- }else{
- data = await parseHtml(indexFile);
- }
- const bundle = await createBundle(data);
- fs.rm(path.join(dir, "tmp/"), {recursive: true, force: true});
- }
- const findIndex = async (dir)=>{
- const neovanPath = path.join(dir, "index.neovan");
- const htmlPath = path.join(dir, "index.html");
- const [neovan, html] = await Promise.allSettled([
- fs.access(path.join(dir, "index.neovan"), constants.F_OK),
- fs.access(path.join(dir, "index.html"), constants.F_OK)
- ]);
- if(neovan.status === "fulfilled") return neovanPath;
- if(html.status === "fulfilled") return htmlPath;
- return null;
- }
- const getNeovanData = async (index)=>{
- const neovan = await fs.readFile(index, "utf-8");
- const parentPath = path.dirname(index);
-
- const html = neovan.slice(neovan.indexOf("<contents>") + 10, neovan.indexOf("</contents>"));
- const css = neovan.slice(neovan.indexOf("<style>") + 7, neovan.indexOf("</style>"));
- const js = neovan.slice(neovan.indexOf("<script>") + 8, neovan.indexOf("</script>"));
- const cssFile = path.join(parentPath, `tmp/${path.basename(index, ".neovan")}.css`);
- const jsFile = path.join(parentPath, `tmp/${path.basename(index, ".neovan")}.js`);
- await fs.mkdir(path.join(parentPath, "tmp/"));
- await Promise.all([
- css === "" ? null : fs.writeFile(cssFile, css),
- js === "" ? null : fs.writeFile(jsFile, js)
- ]);
- return {
- html: html,
- css: cssFile,
- js: jsFile
- };
- }
- const parseHtml = async (index)=>{
- const parentPath = path.dirname(index);
- const basename = path.basename(index, ".html");
- return {
- html: await fs.readFile(index, "utf-8"),
- css: path.join(parentPath, `${basename}.css`),
- js: path.join(parentPath, `${basename}.js`)
- };
- }
- const createBundle = async (data)=>{
- const entryPoints = [];
- if(data.css) entryPoints.push(data.css);
- if(data.js) entryPoints.push(data.js);
- const esbuildProm = esbuild.build({
- entryPoints: entryPoints,
- bundle: true,
- minify: true,
- write: false,
- outdir: "/"
- });
- const htmlProm = htmlMinifier.minify(data.html, {
- collapseBooleanAttributes: true,
- collapseInlineTagWhitespace: true,
- collapseWhitespace: true,
- decodeEntities: true,
- html5: true,
- includeAutoGeneratedTags: false,
- noNewlinesBeforeTagClose: true,
- removeComments: true,
- useShortDoctype: true
- });
- const [buildData, html] = await Promise.all([esbuildProm, htmlProm]);
- //potentially replaceable
- const comps = {html: html};
- for(let i = 0; i < buildData.outputFiles.length; i++){
- const ext = path.extname(buildData.outputFiles[i].path).replace(".", "");
- comps[ext] = buildData.outputFiles[i].text;
- }
- return mergeFiles(comps);
- }
- const mergeFiles = (comps)=>{
- const cssIndex = comps.html.indexOf("</head>");
- const html = `${comps.html.slice(0, cssIndex)}${comps.css}${comps.html.slice(cssIndex)}`;
- const jsIndex = html.indexOf("</body>");
- return `${comps.html.slice(0, jsIndex)}${comps.js}${html.slice(jsIndex)}`;
- }
|