image optimization

This commit is contained in:
Soph :3 2024-08-30 03:51:53 +03:00
parent 47ac0b329c
commit 7b04c35c94
Signed by: sophie
GPG key ID: EDA5D222A0C270F2
7 changed files with 85 additions and 18 deletions

BIN
bun.lockb

Binary file not shown.

View file

@ -4,17 +4,18 @@
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"devDependencies": { "devDependencies": {
"@types/bun": "latest" "@types/bun": "^1.1.8"
}, },
"peerDependencies": { "peerDependencies": {
"typescript": "^5.0.0" "typescript": "^5.0.0"
}, },
"dependencies": { "dependencies": {
"@types/mime-types": "^2.1.4", "@types/mime-types": "^2.1.4",
"esbuild": "^0.23.0", "esbuild": "^0.23.1",
"marked": "^13.0.3", "marked": "^14.1.0",
"mime-types": "^2.1.35", "mime-types": "^2.1.35",
"postcss": "^8.4.41", "postcss": "^8.4.41",
"preact": "^10.23.1" "preact": "^10.23.2",
"sharp": "^0.33.5"
} }
} }

View file

@ -4,11 +4,12 @@ export abstract class Plugin {
renameTo?: string; renameTo?: string;
abstract longLasting: boolean; abstract longLasting: boolean;
abstract build?(): void; abstract build?(): void;
isBinary = false;
abstract rewriteFile( abstract rewriteFile(
file: string, file: string | Buffer,
filePath: string filePath: string
): Promise<string | undefined | null | void>; ): Promise<Buffer | string | undefined | null | void>;
} }
import * as fs from "fs"; import * as fs from "fs";
@ -35,13 +36,14 @@ export default class SSSG {
} }
async build() { async build() {
for(const plugin of this.plugins) { console.time("Building..");
if(plugin.build) { for (const plugin of this.plugins) {
if (plugin.build) {
plugin.build(); plugin.build();
} }
} }
try { try {
fs.rmSync(this.outputFolder, {recursive: true}); fs.rmSync(this.outputFolder, { recursive: true });
} catch {} } catch {}
const sourceFiles = fs.readdirSync(this.inputFolder, { const sourceFiles = fs.readdirSync(this.inputFolder, {
@ -66,7 +68,6 @@ export default class SSSG {
z.rewriteTriggers.includes(type) z.rewriteTriggers.includes(type)
); );
if (availablePlugins.length == 0) { if (availablePlugins.length == 0) {
const oldPath = path.join(file.parentPath, file.name); const oldPath = path.join(file.parentPath, file.name);
fs.cpSync( fs.cpSync(
@ -82,12 +83,20 @@ export default class SSSG {
file.parentPath, file.parentPath,
shortname + shortname +
"." + "." +
(plugin.rewriteTriggers.includes("*") ? type : plugin.renameTo) (plugin.rewriteTriggers.includes("*") || plugin.renameTo == "keep"
? type
: plugin.renameTo)
) )
.replace(this.inputFolder, this.outputFolder); .replace(this.inputFolder, this.outputFolder);
let data = fs.readFileSync(oldPath).toString("utf8"); let data: string | Buffer = fs.readFileSync(oldPath);
if (!plugin.isBinary) {
data = data.toString("utf8");
}
for await (const globalPlugin of globalPlugins) { for await (const globalPlugin of globalPlugins) {
if (!globalPlugin.isBinary && plugin.isBinary) continue;
const rewritten = await globalPlugin.rewriteFile(data, oldPath); const rewritten = await globalPlugin.rewriteFile(data, oldPath);
if (!rewritten) continue; if (!rewritten) continue;
data = rewritten; data = rewritten;
@ -98,8 +107,14 @@ export default class SSSG {
if (!rewrite) continue; if (!rewrite) continue;
fs.mkdirSync(path.dirname(newPath), { recursive: true }); fs.mkdirSync(path.dirname(newPath), { recursive: true });
fs.writeFileSync(newPath, rewrite); fs.writeFileSync(
newPath,
plugin.isBinary
? new Uint8Array(rewrite as Buffer)
: (rewrite as string)
);
} }
} }
console.timeEnd("Building..");
} }
} }

View file

@ -5,7 +5,7 @@ export default class CompileTimeJS extends Plugin {
rewriteTriggers = ["html", "*"] rewriteTriggers = ["html", "*"]
longLasting = false; longLasting = false;
build = undefined; build = undefined;
async rewriteFile(file: string, filePath: string): Promise<string> { async rewriteFile(file: string, filePath: string): Promise<string> {
let input = file; let input = file;
const regex = /{&(.+)&}/gms; const regex = /{&(.+)&}/gms;

View file

@ -3,7 +3,7 @@ import SSSG, { Plugin } from "..";
import * as fs from "fs"; import * as fs from "fs";
import mime from "mime-types"; import mime from "mime-types";
const script = `let reconnectTimeout;function connect(){console.log("[--dev] connecting to dev server");let ws=new WebSocket("ws://localhost:8080");ws.addEventListener("message",message=>{if(message.data=="refresh"){location.reload()}});ws.addEventListener("open",()=>{console.log("[--dev] connected")});ws.addEventListener("close",()=>{console.log("[--dev] socket closed, restarting in 1s");clearTimeout(reconnectTimeout);reconnectTimeout=setTimeout(()=>{connect()},1e3)})}window.addEventListener("load",()=>connect());`; const script = `let reconnectTimeout,waitingForReconnect=!1;function connect(){console.log("[dev] connecting to dev server");var e=new WebSocket("ws://localhost:8080");e.addEventListener("message",e=>{"refresh"==e.data&&location.reload()}),e.addEventListener("open",()=>{console.log("[dev] connected"),waitingForReconnect&&location.reload()}),e.addEventListener("close",()=>{console.log("[dev] socket closed, restarting in 1s"),clearTimeout(reconnectTimeout),reconnectTimeout=setTimeout(()=>{connect(),waitingForReconnect=!0},1e3)})}window.addEventListener("load",()=>connect());`;
export default class DevPlugin extends Plugin { export default class DevPlugin extends Plugin {
build: undefined; build: undefined;
@ -14,10 +14,9 @@ export default class DevPlugin extends Plugin {
longLasting = true; longLasting = true;
server!: Server; server!: Server;
allConnections: ServerWebSocket<number>[] = []; allConnections: ServerWebSocket<number>[] = [];
constructor(sssg: SSSG) { constructor(sssg: SSSG) {
super(); super();
if (!process.argv.includes("--dev")) return;
fs.watch( fs.watch(
sssg.inputFolder, sssg.inputFolder,

View file

@ -0,0 +1,53 @@
import { Plugin } from "..";
import sharp from "sharp";
export default class ImageOptimization extends Plugin {
build: undefined;
name = "image-optimization";
rewriteTriggers = ["png", "gif", "jpg", "jpeg", "webp", "avif"];
renameTo = "keep";
isBinary = true;
longLasting = false;
logging = true;
constructor(logging = true) {
super();
this.logging = logging;
}
async rewriteFile(file: Buffer, filePath: string) {
const nonOptimized = file;
const type = filePath.split(".").at(-1);
let data: Buffer = file;
if (type == "webp") {
data = await sharp(file).webp({ lossless: true }).toBuffer();
}
if (type == "avif") {
data = await sharp(file).avif({ lossless: true }).toBuffer();
}
if (type == "jpg" || type == "jpeg") {
data = await sharp(file).jpeg({ quality: 100 }).toBuffer();
}
if (type == "png") {
data = await sharp(file).png({ quality: 100 }).toBuffer();
}
if (type == "gif") {
// not heavy optimizations, not a fan tbf, but whatever :shrug:
data = await sharp(file, { animated: true })
.gif({ colors: 16 })
.toBuffer();
}
if(nonOptimized.byteLength < data.byteLength) {
if(this.logging) {
console.log("❌ " + filePath + "("+nonOptimized.byteLength+"B) optimized was " + data.byteLength + "B. It has been skipped.");
}
data = nonOptimized;
}
return data;
}
}

View file

@ -1,7 +1,6 @@
import { Plugin } from ".."; import { Plugin } from "..";
export default class Variables extends Plugin { export default class Variables extends Plugin {
name = "variables"; name = "variables";
rewriteTriggers = ["html", "*"]; rewriteTriggers = ["html", "*"];
renameTo = undefined; renameTo = undefined;