From 70c4942fada1d7c14037eba3ecf1e5b12b262e89 Mon Sep 17 00:00:00 2001 From: Zixuan Chen Date: Sat, 16 Nov 2024 19:18:29 +0800 Subject: [PATCH] chore: add wasm-base64 build target --- .changeset/tame-queens-smile.md | 5 ++ crates/loro-wasm/.gitignore | 3 +- crates/loro-wasm/deno.lock | 1 + crates/loro-wasm/package.json | 14 +-- crates/loro-wasm/rollup.base64.config.mjs | 33 +++++++ crates/loro-wasm/rollup.config.mjs | 3 +- .../loro-wasm/scripts/.vscode/settings.json | 3 + crates/loro-wasm/scripts/post-rollup.ts | 87 +++++++++++++++---- examples/loro-quill/src/App.vue | 6 +- examples/loro-quill/src/binding.ts | 18 ++-- pnpm-lock.yaml | 18 ++++ 11 files changed, 156 insertions(+), 35 deletions(-) create mode 100644 .changeset/tame-queens-smile.md create mode 100644 crates/loro-wasm/rollup.base64.config.mjs create mode 100644 crates/loro-wasm/scripts/.vscode/settings.json diff --git a/.changeset/tame-queens-smile.md b/.changeset/tame-queens-smile.md new file mode 100644 index 00000000..27aabe74 --- /dev/null +++ b/.changeset/tame-queens-smile.md @@ -0,0 +1,5 @@ +--- +"loro-crdt": patch +--- + +Add base64 build target diff --git a/crates/loro-wasm/.gitignore b/crates/loro-wasm/.gitignore index 748c83eb..9fa05e38 100644 --- a/crates/loro-wasm/.gitignore +++ b/crates/loro-wasm/.gitignore @@ -3,4 +3,5 @@ npm/ nodejs/ bundler/ web/ -docs/ \ No newline at end of file +docs/ +base64/ diff --git a/crates/loro-wasm/deno.lock b/crates/loro-wasm/deno.lock index a572ca8f..0f0beaf4 100644 --- a/crates/loro-wasm/deno.lock +++ b/crates/loro-wasm/deno.lock @@ -213,6 +213,7 @@ "npm:@rollup/plugin-alias@^5.1.1", "npm:@rollup/plugin-node-resolve@^15.0.1", "npm:@rollup/plugin-typescript@^12.1.1", + "npm:@rollup/plugin-wasm@^6.2.2", "npm:@typescript-eslint/parser@^6.2.0", "npm:@vitest/ui@^1.0.4", "npm:esbuild@~0.18.20", diff --git a/crates/loro-wasm/package.json b/crates/loro-wasm/package.json index fb6c58f9..ebb715f5 100644 --- a/crates/loro-wasm/package.json +++ b/crates/loro-wasm/package.json @@ -21,6 +21,7 @@ "./bundler", "./nodejs", "./web", + "./base64", "CHANGELOG.md", "README.md", "LICENSE", @@ -38,21 +39,22 @@ "@rollup/plugin-alias": "^5.1.1", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-typescript": "^12.1.1", - "rollup": "^3.20.1", - "tslib": "^2.8.0", - "typescript": "^5.6.3", - "vite-plugin-top-level-await": "^1.2.2", - "vite-plugin-wasm": "^3.1.0", + "@rollup/plugin-wasm": "^6.2.2", "@typescript-eslint/parser": "^6.2.0", "@vitest/ui": "^1.0.4", "esbuild": "^0.18.20", "eslint": "^8.46.0", - "loro-crdt-old": "npm:loro-crdt@=0.16.0", "loro-crdt-alpha-4": "npm:loro-crdt@=1.0.0-alpha.4", + "loro-crdt-old": "npm:loro-crdt@=0.16.0", "prettier": "^3.0.0", + "rollup": "^3.20.1", "rollup-plugin-dts": "^5.3.0", "rollup-plugin-esbuild": "^5.0.0", + "tslib": "^2.8.0", + "typescript": "^5.6.3", "vite": "^4.2.1", + "vite-plugin-top-level-await": "^1.2.2", + "vite-plugin-wasm": "^3.1.0", "vitest": "^1.4.0" } } diff --git a/crates/loro-wasm/rollup.base64.config.mjs b/crates/loro-wasm/rollup.base64.config.mjs new file mode 100644 index 00000000..a7ee1e40 --- /dev/null +++ b/crates/loro-wasm/rollup.base64.config.mjs @@ -0,0 +1,33 @@ +import typescript from '@rollup/plugin-typescript'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import { wasm } from '@rollup/plugin-wasm'; + +const base64Config = { + input: { + 'index': 'bundler/index.js', + }, + output: { + dir: 'base64', + format: 'es', + sourcemap: false, + entryFileNames: '[name].js', + }, + plugins: [ + typescript({ + tsconfig: 'tsconfig.json', + compilerOptions: { + target: 'ES2020', + declaration: true, + outDir: 'base64', + }, + exclude: ['tests/**/*', 'vite.config.*'] + }), + nodeResolve(), + wasm({ + maxFileSize: 1024 * 1024 * 10, + sync: ["*", "loro_wasm_bg.wasm", "bundler/loro_wasm_bg.wasm"] + }), + ] +}; + +export default [base64Config]; diff --git a/crates/loro-wasm/rollup.config.mjs b/crates/loro-wasm/rollup.config.mjs index 74acff32..a41e5847 100644 --- a/crates/loro-wasm/rollup.config.mjs +++ b/crates/loro-wasm/rollup.config.mjs @@ -1,5 +1,6 @@ import typescript from '@rollup/plugin-typescript'; import { nodeResolve } from '@rollup/plugin-node-resolve'; + const createConfig = (format, tsTarget, outputDir) => ({ input: { 'index': 'index.ts', @@ -18,7 +19,7 @@ const createConfig = (format, tsTarget, outputDir) => ({ declaration: true, outDir: outputDir, }, - exclude: ['tests/**/*'] + exclude: ['tests/**/*', 'vite.config.*'] }), nodeResolve() ], diff --git a/crates/loro-wasm/scripts/.vscode/settings.json b/crates/loro-wasm/scripts/.vscode/settings.json new file mode 100644 index 00000000..f7f606b3 --- /dev/null +++ b/crates/loro-wasm/scripts/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "deno.enable": true +} diff --git a/crates/loro-wasm/scripts/post-rollup.ts b/crates/loro-wasm/scripts/post-rollup.ts index 5fbd8663..6691965b 100644 --- a/crates/loro-wasm/scripts/post-rollup.ts +++ b/crates/loro-wasm/scripts/post-rollup.ts @@ -1,4 +1,4 @@ -import { walk } from "https://deno.land/std/fs/mod.ts"; +import { walk } from "https://deno.land/std@0.224.0/fs/mod.ts"; const DIRS_TO_SCAN = ["./nodejs", "./bundler", "./web"]; const FILES_TO_PROCESS = ["index.js", "index.d.ts"]; @@ -8,20 +8,21 @@ async function replaceInFile(filePath: string) { let content = await Deno.readTextFile(filePath); // Replace various import/require patterns for 'loro-wasm' - const isWebIndexJs = filePath.includes("web") && filePath.endsWith("index.js"); + const isWebIndexJs = filePath.includes("web") && + filePath.endsWith("index.js"); const target = isWebIndexJs ? "./loro_wasm.js" : "./loro_wasm"; content = content.replace( /from ["']loro-wasm["']/g, - `from "${target}"` + `from "${target}"`, ); content = content.replace( /require\(["']loro-wasm["']\)/g, - `require("${target}")` + `require("${target}")`, ); content = content.replace( /import\(["']loro-wasm["']\)/g, - `import("${target}")` + `import("${target}")`, ); if (isWebIndexJs) { @@ -35,23 +36,79 @@ async function replaceInFile(filePath: string) { } } -async function main() { - for (const dir of DIRS_TO_SCAN) { - try { - for await (const entry of walk(dir, { +async function transform(dir: string) { + try { + for await ( + const entry of walk(dir, { includeDirs: false, match: [/index\.(js|d\.ts)$/], - })) { - if (FILES_TO_PROCESS.includes(entry.name)) { - await replaceInFile(entry.path); - } + }) + ) { + if (FILES_TO_PROCESS.includes(entry.name)) { + await replaceInFile(entry.path); } - } catch (error) { - console.error(`Error scanning directory ${dir}:`, error); } + } catch (error) { + console.error(`Error scanning directory ${dir}:`, error); } } +async function rollupBase64() { + const command = new Deno.Command("rollup", { + args: ["--config", "./rollup.base64.config.mjs"], + }); + + try { + const { code, stdout, stderr } = await command.output(); + if (code === 0) { + console.log("✓ Rollup base64 build completed successfully"); + } else { + console.error("Error running rollup base64 build:"); + console.error(new TextDecoder().decode(stdout)); + console.error(new TextDecoder().decode(stderr)); + } + } catch (error) { + console.error("Failed to execute rollup command:", error); + } + + const toReplaceFrom = `{ + const wkmod = await import('./loro_wasm_bg-b2849b85.js'); + const instance = new WebAssembly.Instance(wkmod.default, { + "./loro_wasm_bg.js": imports, + }); + __wbg_set_wasm(instance.exports); +}`; + const toReplaceTarget = ` +import loro_wasm_bg_js from './loro_wasm_bg-b2849b85.js'; +const instance = new WebAssembly.Instance(loro_wasm_bg_js(), { + "./loro_wasm_bg.js": imports, +}); +__wbg_set_wasm(instance.exports); + `; + const base64IndexPath = "./base64/index.js"; + const content = await Deno.readTextFile(base64IndexPath); + if (!content.includes(toReplaceFrom)) { + throw new Error( + `Could not find string to replace in ${base64IndexPath}`, + ); + } + await Deno.writeTextFile( + base64IndexPath, + content.replace(toReplaceFrom, toReplaceTarget), + ); + + await Deno.copyFile("./bundler/loro_wasm.d.ts", "./base64/loro_wasm.d.ts"); +} + +async function main() { + for (const dir of DIRS_TO_SCAN) { + await transform(dir); + } + + await rollupBase64(); + transform("./base64"); +} + if (import.meta.main) { main(); } diff --git a/examples/loro-quill/src/App.vue b/examples/loro-quill/src/App.vue index 16090ccf..880fc7db 100644 --- a/examples/loro-quill/src/App.vue +++ b/examples/loro-quill/src/App.vue @@ -5,21 +5,21 @@ import "quill/dist/quill.bubble.css"; import "quill/dist/quill.snow.css"; import { QuillBinding } from "./binding"; - import { Loro } from "loro-crdt"; + import { LoroDoc } from "loro-crdt/base64"; const editor1 = ref(null); const editor2 = ref(null); const editor3 = ref(null); const editor4 = ref(null); const binds: QuillBinding[] = []; - const texts: Loro[] = []; + const texts: LoroDoc[] = []; const editors = [editor1, editor2, editor3, editor4]; const editorVersions = reactive(["", "", "", ""]); const online = reactive([true, true, true, true]); onMounted(() => { let index = 0; for (const editor of editors) { - const text = new Loro(); + const text = new LoroDoc(); text.setPeerId(BigInt(index)); texts.push(text); const quill = new Quill(editor.value!, { diff --git a/examples/loro-quill/src/binding.ts b/examples/loro-quill/src/binding.ts index fe446ce9..ffc1af72 100644 --- a/examples/loro-quill/src/binding.ts +++ b/examples/loro-quill/src/binding.ts @@ -2,7 +2,7 @@ * The skeleton of this binding is learned from https://github.com/yjs/y-quill */ -import { Delta, Loro, LoroText } from "loro-crdt"; +import { Delta, LoroDoc, LoroText } from "loro-crdt/base64"; import Quill, { DeltaOperation, DeltaStatic, Sources } from "quill"; // @ts-ignore import isEqual from "is-equal"; @@ -12,18 +12,18 @@ const Delta = Quill.import("delta"); // setDebug("*"); const EXPAND_CONFIG: { [key in string]: "before" | "after" | "both" | "none" } = - { - bold: "after", - italic: "after", - underline: "after", - link: "none", - header: "none", - }; +{ + bold: "after", + italic: "after", + underline: "after", + link: "none", + header: "none", +}; export class QuillBinding { private richtext: LoroText; constructor( - public doc: Loro, + public doc: LoroDoc, public quill: Quill, ) { doc.configTextStyle({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fb08f130..91c92f9f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: '@rollup/plugin-typescript': specifier: ^12.1.1 version: 12.1.1(rollup@3.29.4)(tslib@2.8.0)(typescript@5.6.3) + '@rollup/plugin-wasm': + specifier: ^6.2.2 + version: 6.2.2(rollup@3.29.4) '@typescript-eslint/parser': specifier: ^6.2.0 version: 6.21.0(eslint@8.57.0)(typescript@5.6.3) @@ -564,6 +567,15 @@ packages: rollup: optional: true + '@rollup/plugin-wasm@6.2.2': + resolution: {integrity: sha512-gpC4R1G9Ni92ZIRTexqbhX7U+9estZrbhP+9SRb0DW9xpB9g7j34r+J2hqrcW/lRI7dJaU84MxZM0Rt82tqYPQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/pluginutils@5.1.0': resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} engines: {node: '>=14.0.0'} @@ -2964,6 +2976,12 @@ snapshots: optionalDependencies: rollup: 4.17.2 + '@rollup/plugin-wasm@6.2.2(rollup@3.29.4)': + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@3.29.4) + optionalDependencies: + rollup: 3.29.4 + '@rollup/pluginutils@5.1.0(rollup@3.29.4)': dependencies: '@types/estree': 1.0.5