|
@@ -5,41 +5,73 @@ import htmlMinifier from "html-minifier-terser";
|
|
|
import esbuild from "esbuild";
|
|
import esbuild from "esbuild";
|
|
|
|
|
|
|
|
export default async (dir)=>{
|
|
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 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);
|
|
|
|
|
+ writeFile(dir, bundle);
|
|
|
|
|
+ fs.rm(path.join(dir, "tmp/"), {recursive: true, force: true});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-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)
|
|
|
|
|
|
|
+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 {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;
|
|
|
|
|
|
|
+ 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 files;
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ html: html,
|
|
|
|
|
+ css: cssFile,
|
|
|
|
|
+ js: jsFile
|
|
|
|
|
+ };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const bundleFiles = async (files)=>{
|
|
|
|
|
- const entryPoints = [];
|
|
|
|
|
- if(files.neovan) files = await splitNeovan(files.neovan);
|
|
|
|
|
|
|
+const parseHtml = async (index)=>{
|
|
|
|
|
+ const parentPath = path.dirname(index);
|
|
|
|
|
+ const basename = path.basename(index, ".html");
|
|
|
|
|
|
|
|
- if(files.css) entryPoints.push(files.css);
|
|
|
|
|
- if(files.js) entryPoints.push(files.js);
|
|
|
|
|
|
|
+ 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({
|
|
const esbuildProm = esbuild.build({
|
|
|
entryPoints: entryPoints,
|
|
entryPoints: entryPoints,
|
|
@@ -48,76 +80,39 @@ const bundleFiles = async (files)=>{
|
|
|
write: false,
|
|
write: false,
|
|
|
outdir: "/"
|
|
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: ""
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ const htmlProm = htmlMinifier.minify(data.html, {
|
|
|
|
|
+ collapseBooleanAttributes: true,
|
|
|
|
|
+ collapseInlineTagWhitespace: true,
|
|
|
|
|
+ collapseWhitespace: true,
|
|
|
|
|
+ decodeEntities: true,
|
|
|
|
|
+ html5: true,
|
|
|
|
|
+ includeAutoGeneratedTags: false,
|
|
|
|
|
+ noNewlinesBeforeTagClose: true,
|
|
|
|
|
+ removeComments: true,
|
|
|
|
|
+ useShortDoctype: true
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- 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>`;
|
|
|
|
|
|
|
+ const [buildData, html] = await Promise.all([esbuildProm, htmlProm]);
|
|
|
|
|
+
|
|
|
|
|
+ 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;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if(files.neovan) fs.rm(path.dirname(files.html), {recursive: true});
|
|
|
|
|
- return contents;
|
|
|
|
|
|
|
+ return mergeFiles(comps);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const mergeFiles = (contents)=>{
|
|
|
|
|
- const cssIndex = contents.html.indexOf("</head>");
|
|
|
|
|
- let html = `${contents.html.slice(0, cssIndex)}${contents.css}${contents.html.slice(cssIndex)}`;
|
|
|
|
|
|
|
+const mergeFiles = (comps)=>{
|
|
|
|
|
+ const cssIndex = comps.html.indexOf("</head>");
|
|
|
|
|
+ const html = `${comps.html.slice(0, cssIndex)}<style>${comps.css}</style>${comps.html.slice(cssIndex)}`;
|
|
|
|
|
|
|
|
const jsIndex = html.indexOf("</body>");
|
|
const jsIndex = html.indexOf("</body>");
|
|
|
- return `${html.slice(0, jsIndex)}${contents.js}${html.slice(jsIndex)}`;
|
|
|
|
|
|
|
+ return `${html.slice(0, jsIndex)}<script>${comps.js}</script>${html.slice(jsIndex)}`;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const writeHtml = async (dir, html)=>{
|
|
|
|
|
- const writeDir = `${dir.replace("/routes", "/.build")}`;
|
|
|
|
|
|
|
+const writeFile = async (dir, bundle)=>{
|
|
|
|
|
+ const writeDir = dir.replace("routes", ".build");
|
|
|
await fs.mkdir(writeDir, {recursive: true});
|
|
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
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ await fs.writeFile(`${writeDir}/index.html`, bundle);
|
|
|
}
|
|
}
|