parseDir.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import fs from "node:fs/promises";
  2. import {constants} from "node:fs";
  3. import path from "path";
  4. import htmlMinifier from "html-minifier-terser";
  5. import esbuild from "esbuild";
  6. export default async (dir)=>{
  7. const existingFiles = await checkFiles(dir);
  8. if(!existingFiles.html && !existingFiles.neovan) return;
  9. const content = await bundleFiles(existingFiles);
  10. const html = mergeFiles(content);
  11. writeHtml(dir, html);
  12. }
  13. const checkFiles = async (dir)=>{
  14. let neovanPath = path.join(dir, "index.neovan");
  15. let htmlPath = path.join(dir, "index.html");
  16. let cssPath = path.join(dir, "index.css");
  17. let jsPath = path.join(dir, "index.js");
  18. let [neovan, html, css, js] = await Promise.allSettled([
  19. fs.access(neovanPath, constants.F_OK),
  20. fs.access(htmlPath, constants.F_OK),
  21. fs.access(cssPath, constants.F_OK),
  22. fs.access(jsPath, constants.f_OK)
  23. ]);
  24. if(neovan.status === "fulfilled") return {neovan: neovanPath};
  25. if(html.status !== "fulfilled") return {html: null};
  26. let files = {html: htmlPath};
  27. if(css.status === "fulfilled") files.css = cssPath;
  28. if(js.status === "fulfilled") files.js = jsPath;
  29. return files;
  30. }
  31. const bundleFiles = async (files)=>{
  32. const entryPoints = [];
  33. if(files.neovan) files = await splitNeovan(files.neovan);
  34. if(files.css) entryPoints.push(files.css);
  35. if(files.js) entryPoints.push(files.js);
  36. const esbuildProm = esbuild.build({
  37. entryPoints: entryPoints,
  38. bundle: true,
  39. minify: true,
  40. write: false,
  41. outdir: "/"
  42. });
  43. const htmlProm = fs.readFile(files.html, "utf-8");
  44. const data = await Promise.all([esbuildProm, htmlProm]);
  45. const contents = {
  46. html: await htmlMinifier.minify(data[1], {
  47. collapseBooleanAttributes: true,
  48. collapseInlineTagWhitespace: true,
  49. collapseWhitespace: true,
  50. decodeEntities: true,
  51. html5: true,
  52. includeAutoGeneratedTags: false,
  53. noNewlinesBeforeTagClose: true,
  54. removeComments: true,
  55. useShortDoctype: true
  56. }),
  57. js: "",
  58. css: ""
  59. };
  60. if(files.css && files.js){
  61. contents.css = `<style>${data[0].outputFiles[0].text}</style>`;
  62. contents.js = `<script>${data[0].outputFiles[1].text}</script>`;
  63. }else if(files.css){
  64. contents.css = `<style>${data[0].outputFiles[0].text}</style>`;
  65. }else if(files.js){
  66. contents.js = `<script>${data[0].outputFiles[0].text}</script>`;
  67. }
  68. return contents;
  69. }
  70. const mergeFiles = (contents)=>{
  71. const cssIndex = contents.html.indexOf("</head>");
  72. let html = `${contents.html.slice(0, cssIndex)}${contents.css}${contents.html.slice(cssIndex)}`;
  73. const jsIndex = html.indexOf("</body>");
  74. return `${html.slice(0, jsIndex)}${contents.js}${html.slice(jsIndex)}`;
  75. }
  76. const writeHtml = async (dir, html)=>{
  77. const writeDir = `${dir.replace("/routes", "/.build")}`;
  78. await fs.mkdir(writeDir, {recursive: true});
  79. fs.writeFile(`${writeDir}/index.html`, html);
  80. }
  81. const splitNeovan = async (file)=>{
  82. let data = await fs.readFile(file, "utf-8");
  83. let parentPath = path.dirname(file);
  84. let html = data.slice(data.indexOf("<contents>") + 10, data.indexOf("</contents>"));
  85. let css = data.slice(data.indexOf("<style>") + 7, data.indexOf("</style>"));
  86. let js = data.slice(data.indexOf("<script>") + 8, data.indexOf("</script>"));
  87. let htmlFile = path.join(parentPath, "/tmp/index.html");
  88. let cssFile = path.join(parentPath, "/tmp/index.css");
  89. let jsFile = path.join(parentPath, "/tmp/index.js");
  90. await fs.mkdir(path.join(parentPath, "tmp/"));
  91. let result = await Promise.all([
  92. fs.writeFile(htmlFile, html),
  93. css === "" ? null : fs.writeFile(cssFile, css),
  94. js === "" ? null : fs.writeFile(jsFile, js)
  95. ]);
  96. return {
  97. html: htmlFile,
  98. css: css !== "" ? cssFile : undefined,
  99. js: js !== "" ? jsFile : undefined
  100. };
  101. }