171 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			171 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
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"],
 | 
						|
      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)
 | 
						|
      }
 | 
						|
   }))
 | 
						|
   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()
 |