From 22fbe70a6063bfd209de7a4b6bfc535a4f5e5e53 Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Sun, 19 Oct 2025 11:51:57 +0200 Subject: [PATCH] use browser's builtin compression streams API instead of LZ4 package --- bun.lock | 3 --- package.json | 1 - src/VisualEditor/VisualEditor.tsx | 33 ++++++++++++++++++++++--------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/bun.lock b/bun.lock index 69f065c..7bb152c 100644 --- a/bun.lock +++ b/bun.lock @@ -8,7 +8,6 @@ "@fontsource/roboto": "^5.2.8", "@mui/icons-material": "^7.3.4", "@mui/material": "^7.3.4", - "@nick/lz4": "npm:@jsr/nick__lz4", "react": "^19", "react-dom": "^19", }, @@ -94,8 +93,6 @@ "@mui/utils": ["@mui/utils@7.3.3", "", { "dependencies": { "@babel/runtime": "^7.28.4", "@mui/types": "^7.4.7", "@types/prop-types": "^15.7.15", "clsx": "^2.1.1", "prop-types": "^15.8.1", "react-is": "^19.1.1" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-kwNAUh7bLZ7mRz9JZ+6qfRnnxbE4Zuc+RzXnhSpRSxjTlSTj7b4JxRLXpG+MVtPVtqks5k/XC8No1Vs3x4Z2gg=="], - "@nick/lz4": ["@jsr/nick__lz4@0.3.4", "https://npm.jsr.io/~/11/@jsr/nick__lz4/0.3.4.tgz", {}, "sha512-ZNc+8lCMC8D/cIa9GrSxRcEQC/MyThBOXXlg6rhrvAWSUcKPODwvscsVA+v1UugiBzfJ2dvQIZ/j8484PMadkg=="], - "@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="], "@types/bun": ["@types/bun@1.2.23", "", { "dependencies": { "bun-types": "1.2.23" } }, "sha512-le8ueOY5b6VKYf19xT3McVbXqLqmxzPXHsQT/q9JHgikJ2X22wyTW3g3ohz2ZMnp7dod6aduIiq8A14Xyimm0A=="], diff --git a/package.json b/package.json index 9f1d687..39e33f0 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "@fontsource/roboto": "^5.2.8", "@mui/icons-material": "^7.3.4", "@mui/material": "^7.3.4", - "@nick/lz4": "npm:@jsr/nick__lz4", "react": "^19", "react-dom": "^19" }, diff --git a/src/VisualEditor/VisualEditor.tsx b/src/VisualEditor/VisualEditor.tsx index 4e3b97d..d1a27b8 100644 --- a/src/VisualEditor/VisualEditor.tsx +++ b/src/VisualEditor/VisualEditor.tsx @@ -1,4 +1,3 @@ -import * as lz4 from "@nick/lz4"; import { Dispatch, SetStateAction, useEffect, useMemo, useRef, useState } from "react"; import { Statechart } from "../statecharts/abstract_syntax"; @@ -136,9 +135,15 @@ export function VisualEditor({ast, setAST, rt, errors, setErrors, mode, highligh useEffect(() => { const compressedState = window.location.hash.slice(1); try { - const compressedBuffer = Uint8Array.fromBase64(compressedState); - const recoveredState = JSON.parse(new TextDecoder().decode(lz4.decompress(compressedBuffer))); - setState(recoveredState); + const ds = new DecompressionStream("deflate"); + const writer = ds.writable.getWriter(); + writer.write(Uint8Array.fromBase64(compressedState)); + writer.close(); + + new Response(ds.readable).arrayBuffer().then(decompressedBuffer => { + const recoveredState = JSON.parse(new TextDecoder().decode(decompressedBuffer)); + setState(recoveredState); + }); } catch (e) { console.error("could not recover state:", e); @@ -147,11 +152,21 @@ export function VisualEditor({ast, setAST, rt, errors, setErrors, mode, highligh useEffect(() => { const timeout = setTimeout(() => { - const stateBuffer = new TextEncoder().encode(JSON.stringify(state)); - const compressedStateBuffer = lz4.compress(stateBuffer); - const compressedStateString = compressedStateBuffer.toBase64(); - window.location.hash = "#"+compressedStateString; - }, 200); + const serializedState = JSON.stringify(state); + const stateBuffer = new TextEncoder().encode(serializedState); + + const cs = new CompressionStream("deflate"); + const writer = cs.writable.getWriter(); + writer.write(stateBuffer); + writer.close(); + + // todo: cancel this promise handler when concurrently starting another compression job + new Response(cs.readable).arrayBuffer().then(compressedStateBuffer => { + const compressedStateString = new Uint8Array(compressedStateBuffer).toBase64(); + console.log(compressedStateString.length, serializedState.length); + window.location.hash = "#"+compressedStateString; + }); + }, 100); return () => clearTimeout(timeout); }, [state]);