Use only the jimp modules the host export needs (#1162)

jimp pulls in every image format and plugin, about 60 packages and
26 MB that only export.ts uses. Build the Jimp class from @jimp/core
with the PNG format and the crop and resize plugins instead. The
generated spritesheet is byte-identical to the one from jimp.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
BastiaanandClaude Opus 5.5 authored and GitHub committed 2026-10-30 20:24:07 +00:00
1 parent 53a4fce934
commit 0f7c8be060
2 files changed
+14 -4

No files matched your search

+5 -1
View File
@@ -38,8 +38,12 @@
"dependencies": {
"@clusterio/lib": "workspace:^",
"@jimp/core": "^1.6.1",
"@jimp/js-png": "^1.6.1",
"@jimp/plugin-crop": "^1.6.1",
"@jimp/plugin-resize": "^1.6.1",
"@jimp/types": "^1.6.1",
"@sinclair/typebox": "catalog:",
"jimp": "^1.6.1",
"pidusage": "^4.1.0",
"rcon-client": "^4.2.5",
"semver": "catalog:",
+9 -3
View File
@@ -1,7 +1,11 @@
// Export of item icons and locale
import fs from "node:fs/promises";
import path from "path";
import { Jimp, JimpMime, type JimpInstance } from "jimp";
import { createJimp } from "@jimp/core";
import png from "@jimp/js-png";
import * as crop from "@jimp/plugin-crop";
import * as resize from "@jimp/plugin-resize";
import type {} from "@jimp/types"; // needed to name jimp types in export.d.ts
import yazl from "yazl";
import * as lib from "@clusterio/lib";
@@ -147,7 +151,9 @@ async function loadFile(
return await modZip.zip.readFile(path.posix.join(modZip.root, filePath));
}
type Image = JimpInstance;
// Only the parts of jimp the export uses
const Jimp = createJimp({ formats: [png], plugins: [crop.methods, resize.methods] });
type Image = InstanceType<typeof Jimp>;
type IconCache = Map<string, Image | null>;
async function loadIcon(
server: FactorioServer,
@@ -618,7 +624,7 @@ async function buildExport(server: FactorioServer, zipCache: ZipCache) {
// Crop sheet to actual used height and write single spritesheet + metadata.
const usedRows = Math.ceil(state.pos / (SHEET_WIDTH / SHEET_ICON_SIZE));
state.sheet.crop({ x: 0, y: 0, w: SHEET_WIDTH, h: Math.max(usedRows * SHEET_ICON_SIZE, 1) });
zip.addBuffer(await state.sheet.getBuffer(JimpMime.png), "export/spritesheet.png");
zip.addBuffer(await state.sheet.getBuffer("image/png"), "export/spritesheet.png");
addJson("export/metadata.json", state.metadata satisfies lib.ExportMetadata);
zip.end();