diff --git a/build/build.ts b/build/build.ts index b3dc1f7..1ae3f65 100644 --- a/build/build.ts +++ b/build/build.ts @@ -2,6 +2,7 @@ import path from "node:path"; import fs from "node:fs"; import { createHash } from "node:crypto"; import { promisify } from "node:util"; +import { exec } from "node:child_process"; import * as esbuild from "esbuild"; import { optimize } from "svgo"; import * as xmlParser from "../lib/xml-parser.ts"; @@ -20,12 +21,9 @@ const fsAsync = { mkdir: promisify(fs.mkdir), }; -const MODE = process.env["NODE_ENV"] || "production"; +const execAsync = promisify(exec); -const BUILD_METADATA = new Date() - .toISOString() - .split(".")[0] - .replace(/[^0-9]/g, ""); +const MODE = process.env["NODE_ENV"] || "production"; const INPUT_DIR = process.cwd(); const OUTPUT_DIR = path.join(INPUT_DIR, "dist"); @@ -140,17 +138,38 @@ function generateSymbol(id: string, svgStr: string): string { return `${symbolBody}`; } +async function getBuildMetadata(): Promise { + const date = new Date().toISOString().slice(2, 10).replaceAll("-", ""); + + const [commit, diff, newFiles] = await Promise.all([ + execAsync("git rev-parse HEAD"), + execAsync("git diff HEAD"), + execAsync("git ls-files --others --exclude-standard"), + ]).then((res) => res.map((r) => r.stdout.trim())); + + if (!diff && !newFiles) return date + commit.slice(0, 4); + + const hash = createHash("md5"); + hash.update(commit).update(diff).update(newFiles); + for (const file of newFiles.split("\n").filter((f) => f)) + hash.update(await fsAsync.readFile(file)); + return date + hash.digest("hex").slice(0, 4); +} + async function init(): Promise { - const [packageJsonFile, npmShrinkwrapFile] = await Promise.all([ - fsAsync.readFile(path.join(INPUT_DIR, "package.json")), - fsAsync.readFile(path.join(INPUT_DIR, "npm-shrinkwrap.json")), - ]); + const [buildMetadata, packageJsonFile, npmShrinkwrapFile] = await Promise.all( + [ + getBuildMetadata(), + fsAsync.readFile(path.join(INPUT_DIR, "package.json")), + fsAsync.readFile(path.join(INPUT_DIR, "npm-shrinkwrap.json")), + ], + ); const packageJson = JSON.parse(packageJsonFile.toString()); delete packageJson["devDependencies"]; delete packageJson["private"]; delete packageJson["scripts"]; - packageJson["version"] = `${packageJson["version"]}+${BUILD_METADATA}`; + packageJson["version"] = `${packageJson["version"]}+${buildMetadata}`; const npmShrinkwrap = JSON.parse(npmShrinkwrapFile.toString()); npmShrinkwrap["version"] = packageJson["version"];