SHA1 digest (Vite) - chung-leong/zigar GitHub Wiki
In this example we're going to create an app that calculates SHA-1 digests of files, using a built-in function of Zig's standard library.
First, we'll create the basic skeleton:
npm create vite@latest
Need to install the following packages:
[email protected]
Ok to proceed? (y) y
✔ Project name: … sha1
✔ Select a framework: › React
✔ Select a variant: › JavaScript + SWC
cd hello
npm install
npm install --save-dev rollup-plugin-zigar
mkdir zig
Then we add sha1.zig
:
const std = @import("std");
pub fn sha1(bytes: []const u8) [std.crypto.hash.Sha1.digest_length * 2]u8 {
var digest: [std.crypto.hash.Sha1.digest_length]u8 = undefined;
std.crypto.hash.Sha1.hash(bytes, &digest, .{});
return std.fmt.bytesToHex(digest, .lower);
}
Add Zigar plugin to vite.config.js
:
import react from '@vitejs/plugin-react-swc';
import zigar from 'rollup-plugin-zigar';
import { defineConfig } from 'vite';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [ react(), zigar({ topLevelAwait: false }) ],
})
Made alterations to App.jsx
:
import { useCallback, useState } from 'react';
import { sha1 } from '../zig/sha1.zig';
import './App.css';
function App() {
const [ digest, setDigest ] = useState('-')
const onChange = useCallback(async (evt) => {
const [ file ] = evt.target.files;
if (file) {
const buffer = await file.arrayBuffer();
const { string } = sha1(buffer);
setDigest(string);
} else {
setDigest('-');
}
}, []);
return (
<>
<div className="card">
<input type="file" onChange={onChange} />
<h2>{digest}</h2>
</div>
</>
)
}
export default App
And we're ready to go:
npm run dev
VITE v5.1.6 ready in 329 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h + enter to show help
Run the usual command and preview the result:
npm run build
npm run preview
You should notice that the app runs faster now than in dev mode. rollup-plugin-zigar by default
sets optimize
to ReleaseSmall
when building for production. That removes overhead from Zig's
runtime safety system.
The build log, you'll notice that there is no gzip estimate for the .wasm file:
vite v5.1.6 building for production...
✓ 34 modules transformed.
dist/index.html 0.46 kB │ gzip: 0.29 kB
dist/assets/sha1-RsZosFvf.wasm 7.97 kB
dist/assets/index-DiwrgTda.css 1.39 kB │ gzip: 0.72 kB
dist/assets/index-lTKY5Jez.js 190.91 kB │ gzip: 61.49 kB
✓ built in 7.35s
WebAssembly binaries are actually highly compressible (> 50%). Web servers typically don't recognize this, however, and will not apply compression on them. For this reason, it can be profitable to embed the WASM binary in the JavaScript file.
In vite.config.js
, we make the following change:
export default defineConfig({
plugins: [ react(), zigar({ topLevelAwait: false, embedWASM: true }) ],
})
We get the following when we rebuild:
vite v5.1.6 building for production...
✓ 34 modules transformed.
dist/index.html 0.46 kB │ gzip: 0.29 kB
dist/assets/index-DiwrgTda.css 1.39 kB │ gzip: 0.72 kB
dist/assets/index-DoBMgcnF.js 201.57 kB │ gzip: 66.83 kB
✓ built in 1.50s
A saving of about 3K.
You can find the complete source code for this example here.
This example is still relatively simple. All we're doing is calling a function. It accepts an uncomplicated argument and returns an uncomplicated value. In the next example, the function involved will take more complicated arguments and return something complicated as well.