mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-27 22:28:11 +08:00
Split up Wasm binaries so Cloudflare deployments stay below 25 MB per file
This commit is contained in:
+54
-2
@@ -1,6 +1,6 @@
|
||||
import { execSync } from "child_process";
|
||||
import { createHash } from "crypto";
|
||||
import { copyFileSync, cpSync, existsSync, readdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
||||
import { copyFileSync, cpSync, existsSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "fs";
|
||||
import path from "path";
|
||||
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
||||
import { defineConfig } from "vite";
|
||||
@@ -11,7 +11,17 @@ const projectRootDir = path.resolve(__dirname);
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ mode }) => {
|
||||
return {
|
||||
plugins: [svelteGlobalStyles(), webkitUserSelectPrefix(), svelte(), staticAssets(), mode !== "native" && thirdPartyLicenses(), mode !== "native" && serviceWorker()],
|
||||
plugins: [
|
||||
svelteGlobalStyles(),
|
||||
webkitUserSelectPrefix(),
|
||||
svelte(),
|
||||
staticAssets(),
|
||||
mode !== "native" && thirdPartyLicenses(),
|
||||
mode !== "native" && wasmSplitting(),
|
||||
mode !== "native" && serviceWorker(),
|
||||
],
|
||||
// Default for builds that exclude the `wasmSplitting` plugin, which overrides this when active
|
||||
define: { __WASM_PART_COUNT__: "1" },
|
||||
resolve: {
|
||||
alias: [{ find: /\/..\/branding\/(.*\.svg)/, replacement: path.resolve(projectRootDir, "../branding", "$1?raw") }],
|
||||
},
|
||||
@@ -136,6 +146,48 @@ function thirdPartyLicenses(): PluginOption {
|
||||
};
|
||||
}
|
||||
|
||||
// Splits the Wasm binary into parts small enough for Cloudflare Pages' 25 MiB single-file limit, rejoined at runtime by `initWasm()` in `src/utility-functions/wasm-loader.ts`.
|
||||
// Only active when the `SPLIT_WASM` environment variable is set, which CI does for deployments; local builds keep the single file.
|
||||
function wasmSplitting(): PluginOption {
|
||||
const PART_SIZE = 24 * 1024 * 1024;
|
||||
|
||||
let partCount = 1;
|
||||
|
||||
return {
|
||||
name: "wasm-splitting",
|
||||
config(_, { command }) {
|
||||
// Measure the Wasm binary (already built by `cargo run build web` before Vite runs) to decide how many parts are needed
|
||||
if (command === "build" && process.env.SPLIT_WASM) {
|
||||
const wasmPath = path.resolve(projectRootDir, "wrapper/pkg/graphite_wasm_wrapper_bg.wasm");
|
||||
if (!existsSync(wasmPath)) throw new Error(`SPLIT_WASM is set but the Wasm binary is missing at ${wasmPath}`);
|
||||
partCount = Math.ceil(statSync(wasmPath).size / PART_SIZE);
|
||||
}
|
||||
|
||||
// Bake the part count into the bundle so `initWasm()` knows how many parts to fetch and rejoin
|
||||
return { define: { __WASM_PART_COUNT__: String(partCount) } };
|
||||
},
|
||||
// Synchronous so it completes before the `serviceWorker` plugin's `writeBundle` collects the precache manifest
|
||||
writeBundle(options) {
|
||||
if (partCount <= 1) return;
|
||||
|
||||
const assetsDir = path.join(options.dir || "dist", "assets");
|
||||
const wasmFileName = readdirSync(assetsDir).find((name) => name.startsWith("graphite_wasm_wrapper_bg-") && name.endsWith(".wasm"));
|
||||
if (!wasmFileName) throw new Error("Could not find the emitted Wasm asset to split");
|
||||
const wasmPath = path.join(assetsDir, wasmFileName);
|
||||
|
||||
const contents = readFileSync(wasmPath);
|
||||
if (Math.ceil(contents.length / PART_SIZE) !== partCount) throw new Error("Wasm binary size changed during the build, invalidating the baked-in part count");
|
||||
|
||||
// Replace the single Wasm file with its parts so only they get deployed and precached
|
||||
for (let index = 0; index < partCount; index += 1) {
|
||||
const partName = wasmFileName.replace(/\.wasm$/, `-part${index}.wasm`);
|
||||
writeFileSync(path.join(assetsDir, partName), contents.subarray(index * PART_SIZE, (index + 1) * PART_SIZE));
|
||||
}
|
||||
rmSync(wasmPath);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function serviceWorker(): PluginOption {
|
||||
// Files that should never be precached
|
||||
const EXCLUDED_FILES = new Set(["service-worker.js"]);
|
||||
|
||||
Reference in New Issue
Block a user