mirror of
https://gitgud.io/BondageProjects/Bondage-College.git
synced 2025-04-25 17:59:34 +00:00
Possibly the gulp minification pipeline is broken; I can't spare the disk space — or the time — to run that at the moment. CI and the changelog generator are fine though. Only remains a few errors in AssetCheck, which look legitimate, but at that point I'm done playing packaging games.
295 lines
7.3 KiB
JavaScript
295 lines
7.3 KiB
JavaScript
import path from "path";
|
|
import log from "fancy-log";
|
|
import c from "ansi-colors";
|
|
import gulp from "gulp";
|
|
import gulpCount from "gulp-count";
|
|
import gulpIf from "gulp-if";
|
|
import gulpSize from "gulp-size";
|
|
import filter from "gulp-filter";
|
|
import imagemin from "gulp-imagemin";
|
|
import jpegtran from "imagemin-jpegtran";
|
|
import cache from "gulp-cache";
|
|
import through from "through2";
|
|
import { rimraf } from "rimraf";
|
|
import { table } from "table";
|
|
import prettyBytes from "pretty-bytes";
|
|
import StreamCounter from "stream-counter";
|
|
|
|
const BASE_DIR = path.resolve(import.meta.dirname, "..", "..");
|
|
const CACHE_DIR = path.resolve(import.meta.dirname, ".imagemin-cache");
|
|
const BATCH_SIZE = 500;
|
|
const SIZE_CONFIG = { showTotal: false };
|
|
|
|
export const assetMinify = gulp.series(logIntro, analyzeBefore, generateBatches, minifyBatches, analyzeAfter, report);
|
|
|
|
export function clean(cb) {
|
|
rimraf(CACHE_DIR, cb);
|
|
}
|
|
|
|
let files = [];
|
|
let batches = [];
|
|
const supportedSizes = {
|
|
before: {
|
|
png: gulpSize(SIZE_CONFIG),
|
|
jpg: gulpSize(SIZE_CONFIG),
|
|
svg: gulpSize(SIZE_CONFIG),
|
|
total: gulpSize(SIZE_CONFIG),
|
|
},
|
|
after: {
|
|
png: gulpSize(SIZE_CONFIG),
|
|
jpg: gulpSize(SIZE_CONFIG),
|
|
svg: gulpSize(SIZE_CONFIG),
|
|
total: gulpSize(SIZE_CONFIG),
|
|
},
|
|
};
|
|
|
|
function logIntro(cb) {
|
|
log(c.cyan("Starting image minification. Please be patient, this can take a long time..."));
|
|
cb();
|
|
}
|
|
|
|
function analyze(beforeOrAfter, sizePlugins, record = false) {
|
|
if (record) {
|
|
files = [];
|
|
}
|
|
return sourceFiles()
|
|
.pipe(gulpIf(record, through.obj((file, env, cb) => {
|
|
files.push(file.path);
|
|
cb(null, file);
|
|
})))
|
|
.pipe(gulpLog(
|
|
"",
|
|
c.cyan(`File counts ${beforeOrAfter} minification`),
|
|
"--------------------------------",
|
|
))
|
|
.pipe(gulpIf(/\.png$/, count("PNG:\t<%= files %> found")))
|
|
.pipe(gulpIf(/\.png$/, sizePlugins.png))
|
|
.pipe(gulpIf(/\.jpe?g$/, count("JPG:\t<%= files %> found")))
|
|
.pipe(gulpIf(/\.jpe?g$/, sizePlugins.jpg))
|
|
.pipe(gulpIf(/\.svg$/, count("SVG:\t<%= files %> found")))
|
|
.pipe(gulpIf(/\.svg$/, sizePlugins.svg))
|
|
.pipe(gulpLog("--------------------------------"))
|
|
.pipe(count("Found <%= files %> in total for minification"))
|
|
.pipe(sizePlugins.total)
|
|
.pipe(gulpLog(
|
|
"",
|
|
c.cyan(`File sizes ${beforeOrAfter} minification`),
|
|
"--------------------------------",
|
|
))
|
|
.pipe(gulpLog(
|
|
() => `PNG: \t${c.magenta(sizePlugins.png.prettySize)}`,
|
|
() => `JPG: \t${c.magenta(sizePlugins.jpg.prettySize)}`,
|
|
() => `SVG: \t${c.magenta(sizePlugins.svg.prettySize)}`,
|
|
"--------------------------------",
|
|
() => `Total: \t${c.magenta(sizePlugins.total.prettySize)}`,
|
|
"",
|
|
));
|
|
}
|
|
|
|
function analyzeBefore() {
|
|
return analyze("before", supportedSizes.before, true);
|
|
}
|
|
|
|
function analyzeAfter() {
|
|
return analyze("after", supportedSizes.after);
|
|
}
|
|
|
|
function report(cb) {
|
|
const { before, after } = supportedSizes;
|
|
log("");
|
|
log(c.cyan("Image minification report"));
|
|
log("--------------------------------");
|
|
const tableData = [
|
|
reportHeader(),
|
|
reportRow("PNG", before.png, after.png),
|
|
reportRow("JPG", before.jpg, after.jpg),
|
|
reportRow("SVG", before.svg, after.svg),
|
|
reportRow("Total", before.total, after.total),
|
|
];
|
|
const tableLines = table(tableData).split("\n");
|
|
for (const line of tableLines) {
|
|
log(line);
|
|
}
|
|
cb();
|
|
}
|
|
|
|
function reportHeader() {
|
|
return [
|
|
c.cyan("File Type"),
|
|
c.cyan("Size before"),
|
|
c.cyan("Size after"),
|
|
c.cyan("Difference"),
|
|
c.cyan("Percentage reduction"),
|
|
];
|
|
}
|
|
|
|
function reportRow(fileType, before, after) {
|
|
return [
|
|
fileType,
|
|
before.prettySize,
|
|
after.prettySize,
|
|
colorizeSizeDifference(before.size, after.size),
|
|
colorizeSizePercentage(before.size, after.size),
|
|
];
|
|
}
|
|
|
|
function getRAGColor(before, after) {
|
|
return after < before ? c.green
|
|
: after > before ? c.red
|
|
: c.yellow;
|
|
}
|
|
|
|
function colorizeSizeDifference(before, after) {
|
|
const color = getRAGColor(before, after);
|
|
return color(prettyBytes(after - before, { signed: true }));
|
|
}
|
|
|
|
function colorizeSizePercentage(before, after) {
|
|
const color = getRAGColor(before, after);
|
|
const reduction = before - after;
|
|
const percentage = before !== 0 ? 100 * reduction / before : 0;
|
|
return color(`${percentage.toFixed(2)}%`);
|
|
}
|
|
|
|
function generateBatches(cb) {
|
|
log(`Splitting ${c.magenta(`${files.length}`)} files into batches of size ${c.magenta(`${BATCH_SIZE}`)}...`);
|
|
batches = [];
|
|
for (let i = 0; i < files.length; i += BATCH_SIZE) {
|
|
batches.push(files.slice(i, i + BATCH_SIZE));
|
|
}
|
|
log(`${c.magenta(`${batches.length}`)} batches generated.`);
|
|
cb();
|
|
}
|
|
|
|
function minifyBatches(cb) {
|
|
const tasks = batches.map((batch, i) => {
|
|
function minifyTask() {
|
|
log(`Minifying batch ${c.magenta(`${i + 1}`)} of ${c.magenta(`${batches.length}`)}`);
|
|
return minifyBatch(batch);
|
|
}
|
|
|
|
minifyTask.displayName = `Minify batch ${i + 1} of ${batches.length}`;
|
|
return minifyTask;
|
|
});
|
|
|
|
return gulp.series(...tasks, (seriesDone) => {
|
|
seriesDone();
|
|
})(cb);
|
|
}
|
|
|
|
function minifyBatch(batch) {
|
|
const sizesBefore = fileSizes();
|
|
const sizesAfter = fileSizes();
|
|
return gulp.src(batch, { base: BASE_DIR })
|
|
.pipe(sizesBefore)
|
|
.pipe(cache(
|
|
configureImagemin(),
|
|
{
|
|
name: "imagemin",
|
|
fileCache: new cache.Cache({
|
|
// @ts-expect-error There's something wrong with the typings here…
|
|
// This is actually cache-swap's interface, which has this option.
|
|
tmpDir: CACHE_DIR,
|
|
cacheDirName: "imagemin-cache",
|
|
}),
|
|
},
|
|
))
|
|
.pipe(sizesAfter)
|
|
.pipe(filter((file) => {
|
|
// @ts-expect-error Smuggling size through
|
|
const sizeBefore = sizesBefore.sizes.get(file.path);
|
|
// @ts-expect-error Smuggling size through
|
|
const sizeAfter = sizesAfter.sizes.get(file.path);
|
|
if (sizeAfter > sizeBefore) {
|
|
log(`Omitting file "${c.magenta(file.path)}": size after minification is greater than original size.`);
|
|
}
|
|
return sizeAfter <= sizeBefore;
|
|
}))
|
|
.pipe(gulp.dest(BASE_DIR));
|
|
}
|
|
|
|
function configureImagemin() {
|
|
return imagemin([
|
|
jpegtran(),
|
|
imagemin.optipng({ optimizationLevel: 5 }),
|
|
imagemin.svgo({
|
|
plugins: [
|
|
{
|
|
name: "removeViewBox",
|
|
active: true,
|
|
},
|
|
{
|
|
name: "cleanupIDs",
|
|
active: true,
|
|
},
|
|
],
|
|
}),
|
|
]);
|
|
}
|
|
|
|
function sourceFiles() {
|
|
return gulp.src([
|
|
`${BASE_DIR}/**/*.{jpg,jpeg,png,svg}`,
|
|
`!${BASE_DIR}/**/Assets/Female3DCG/BodyUpper/3DCGPose/**/*`,
|
|
`!${BASE_DIR}/Tools/**/*`,
|
|
], { base: BASE_DIR });
|
|
}
|
|
|
|
function count(message) {
|
|
return gulpCount({ message, logger: log });
|
|
}
|
|
|
|
function gulpLog(...messages) {
|
|
return through.obj(
|
|
(file, enc, cb) => cb(null, file),
|
|
(cb) => {
|
|
for (const message of messages) {
|
|
if (typeof message === "function") {
|
|
log(message());
|
|
} else {
|
|
log(message);
|
|
}
|
|
}
|
|
cb();
|
|
},
|
|
);
|
|
}
|
|
|
|
function fileSizes() {
|
|
const sizes = new Map();
|
|
|
|
return through.obj(
|
|
async function (file, enc, cb) {
|
|
// @ts-expect-error Smuggling size through
|
|
if (!this.sizes) {
|
|
// @ts-expect-error Smuggling size through
|
|
this.sizes = sizes;
|
|
}
|
|
|
|
if (file.isNull()) {
|
|
cb(null, file);
|
|
return;
|
|
}
|
|
|
|
let size = 0;
|
|
|
|
if (file.isStream()) {
|
|
size = await getStreamSize(file);
|
|
} else if (file.isBuffer()) {
|
|
size = file.contents.length;
|
|
}
|
|
|
|
sizes.set(file.path, size);
|
|
|
|
cb(null, file);
|
|
},
|
|
);
|
|
}
|
|
|
|
function getStreamSize(file) {
|
|
return new Promise((resolve, reject) => {
|
|
const stream = file.contents.pipe(new StreamCounter());
|
|
stream.on("finish", () => resolve(stream.bytes))
|
|
.on("error", (error) => reject(error));
|
|
});
|
|
}
|