import React, { FC, useRef, useState } from 'react'; import Highlight, { DefaultProps } from 'prism-react-renderer'; import Prism from './prism'; import './prism'; import './prism.css'; import exec from './sandbox'; import ts from 'typescript'; const canStream = 'stream' in File.prototype; type Preset = { fflate: string; uzip: string; pako: string; }; const presets: Record = { 'Basic GZIP compression': { fflate: ` var file = files[0]; fileToU8(file, function(buf) { fflate.gzip(buf, { level: 6, // These are optional, but fflate supports the metadata mtime: file.lastModified, filename: file.name }, function(err, data) { // Hope you're not causing any errors in the demo ;) callback(data); }); });`, uzip: ` var file = files[0]; fileToU8(file, function(buf) { // UZIP doesn't natively support GZIP, but I patched in support for it. // In other words, you're better off using fflate for GZIP. // Also, UZIP runs synchronously on the main thread. It relies on global // state, so you can't even run it in the background without causing bugs. // But just for the sake of a performance comparison, try it out. uzipWorker.gzip(buf, function(err, data) { callback(data); }); });`, pako: ` var file = files[0]; fileToU8(file, function(buf) { // Unlike UZIP, Pako natively supports GZIP, and it doesn't rely on global // state. However, it's still 46kB for this basic functionality as opposed // to fflate's 7kB, not to mention the fact that there's no easy way to use // it asynchronously. I had to add a worker proxy for this to work. pakoWorker.gzip(buf, function(err, data) { callback(data); }); }); ` } } if (canStream) { presets['Streaming GZIP compression'] = { fflate: ` const { AsyncGzip } = fflate; const file = files[0]; const gzipStream = new AsyncGzip({ level: 6 }); // We can stream the file through GZIP to reduce memory usage const fakeResponse = new Response( file.stream().pipeThrough(toNativeStream(gzipStream)) ); fakeResponse.arrayBuffer().then(buf => { callback(new Uint8Array(buf)); });`, uzip: ` // UZIP doesn't support streaming to any extent`, pako: ` // Hundreds of lines of code to make this run on a Worker... const file = files[0]; // In case this wasn't clear already, Pako doesn't actually support this, // you need to create a custom async stream. I suppose you could copy the // code used in this demo. const gzipStream = pakoWorker.createGzip(); const fakeResponse = new Response( file.stream().pipeThrough(toNativeStream(gzipStream)) ); fakeResponse.arrayBuffer().then(buf => { callback(new Uint8Array(buf)); });` }; } const CodeHighlight: FC<{ code: string; onInput: (newCode: string) => void; }> = ({ code, onInput }) => { const tmpParen = useRef(-1); return ( <>
        
{({ tokens, getLineProps, getTokenProps }) => ( tokens.map((line, i) => (
{line.map((token, key) => ( ))}
)) )}
) }; const CodeBox: FC<{files: File[]}> = ({ files }) => { const [{ fflate, uzip, pako }, setCodes] = useState(presets['Streaming GZIP compression']); const onInput = (lib: 'fflate' | 'uzip' | 'pako', code: string) => { const codes: Preset = { fflate, uzip, pako }; codes[lib] = code; setCodes(codes); } return (
fflate: onInput('fflate', t)} />
UZIP (shimmed): onInput('uzip', t)} />
Pako (shimmed): onInput('pako', t)} />
); } export default CodeBox;