image optimization
This commit is contained in:
parent
47ac0b329c
commit
7b04c35c94
7 changed files with 85 additions and 18 deletions
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
33
src/index.ts
33
src/index.ts
|
@ -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..");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -17,7 +17,6 @@ export default class DevPlugin extends Plugin {
|
||||||
|
|
||||||
constructor(sssg: SSSG) {
|
constructor(sssg: SSSG) {
|
||||||
super();
|
super();
|
||||||
if (!process.argv.includes("--dev")) return;
|
|
||||||
|
|
||||||
fs.watch(
|
fs.watch(
|
||||||
sssg.inputFolder,
|
sssg.inputFolder,
|
||||||
|
|
53
src/plugins/image-optimization.ts
Normal file
53
src/plugins/image-optimization.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue