| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- 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 existingFiles = await checkFiles(dir);
- if(!existingFiles.html && !existingFiles.neovan) return;
- const content = await bundleFiles(existingFiles);
- const html = mergeFiles(content);
- writeHtml(dir, html);
- }
- const checkFiles = async (dir)=>{
- let neovanPath = path.join(dir, "index.neovan");
- let htmlPath = path.join(dir, "index.html");
- let cssPath = path.join(dir, "index.css");
- let jsPath = path.join(dir, "index.js");
- let [neovan, html, css, js] = await Promise.allSettled([
- fs.access(neovanPath, constants.F_OK),
- fs.access(htmlPath, constants.F_OK),
- fs.access(cssPath, constants.F_OK),
- fs.access(jsPath, constants.f_OK)
- ]);
- if(neovan.status === "fulfilled") return {neovan: neovanPath};
- if(html.status !== "fulfilled") return {html: null};
- let files = {html: htmlPath};
- if(css.status === "fulfilled") files.css = cssPath;
- if(js.status === "fulfilled") files.js = jsPath;
- return files;
- }
- const bundleFiles = async (files)=>{
- const entryPoints = [];
- if(files.neovan) files = await splitNeovan(files.neovan);
- if(files.css) entryPoints.push(files.css);
- if(files.js) entryPoints.push(files.js);
- const esbuildProm = esbuild.build({
- entryPoints: entryPoints,
- bundle: true,
- minify: true,
- write: false,
- outdir: "/"
- });
- const htmlProm = fs.readFile(files.html, "utf-8");
- const data = await Promise.all([esbuildProm, htmlProm]);
- const contents = {
- html: await htmlMinifier.minify(data[1], {
- collapseBooleanAttributes: true,
- collapseInlineTagWhitespace: true,
- collapseWhitespace: true,
- decodeEntities: true,
- html5: true,
- includeAutoGeneratedTags: false,
- noNewlinesBeforeTagClose: true,
- removeComments: true,
- useShortDoctype: true
- }),
- js: "",
- css: ""
- };
- if(files.css && files.js){
- contents.css = `<style>${data[0].outputFiles[0].text}</style>`;
- contents.js = `<script>${data[0].outputFiles[1].text}</script>`;
- }else if(files.css){
- contents.css = `<style>${data[0].outputFiles[0].text}</style>`;
- }else if(files.js){
- contents.js = `<script>${data[0].outputFiles[0].text}</script>`;
- }
- if(files.neovan) fs.rm(path.dirname(files.html), {recursive: true});
- return contents;
- }
- const mergeFiles = (contents)=>{
- const cssIndex = contents.html.indexOf("</head>");
- let html = `${contents.html.slice(0, cssIndex)}${contents.css}${contents.html.slice(cssIndex)}`;
- const jsIndex = html.indexOf("</body>");
- return `${html.slice(0, jsIndex)}${contents.js}${html.slice(jsIndex)}`;
- }
- const writeHtml = async (dir, html)=>{
- const writeDir = `${dir.replace("/routes", "/.build")}`;
- await fs.mkdir(writeDir, {recursive: true});
- fs.writeFile(`${writeDir}/index.html`, html);
- }
- const splitNeovan = async (file)=>{
- let data = await fs.readFile(file, "utf-8");
- let parentPath = path.dirname(file);
- let html = data.slice(data.indexOf("<contents>") + 10, data.indexOf("</contents>"));
- let css = data.slice(data.indexOf("<style>") + 7, data.indexOf("</style>"));
- let js = data.slice(data.indexOf("<script>") + 8, data.indexOf("</script>"));
- let htmlFile = path.join(parentPath, "/tmp/index.html");
- let cssFile = path.join(parentPath, "/tmp/index.css");
- let jsFile = path.join(parentPath, "/tmp/index.js");
- await fs.mkdir(path.join(parentPath, "tmp/"));
- let result = await Promise.all([
- fs.writeFile(htmlFile, html),
- css === "" ? null : fs.writeFile(cssFile, css),
- js === "" ? null : fs.writeFile(jsFile, js)
- ]);
- return {
- html: htmlFile,
- css: css !== "" ? cssFile : undefined,
- js: js !== "" ? jsFile : undefined,
- neovan: true
- };
- }
|