From 8a9592d5ebf2f3d3ea4d3d6b93e78d27fc47d270 Mon Sep 17 00:00:00 2001 From: Jack <34489450+fenjalien@users.noreply.github.com> Date: Thu, 2 Nov 2023 12:10:38 +0000 Subject: [PATCH] Improve package loading times --- .gitignore | 2 ++ esbuild.config.mjs | 35 +++------------------------ package-lock.json | 15 +++++++++--- package.json | 3 ++- src/compiler.worker.ts | 21 ++++++++++------ src/main.ts | 55 +++++++++++++++++++++++++++++++++++++++--- 6 files changed, 86 insertions(+), 45 deletions(-) diff --git a/.gitignore b/.gitignore index 0558e7b..87dec95 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ data.json # Added by cargo target + +*.wasm \ No newline at end of file diff --git a/esbuild.config.mjs b/esbuild.config.mjs index e379414..756fc4a 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -12,36 +12,6 @@ if you want to view the source, please visit the github repository of this plugi `; const prod = (process.argv[2] === "production"); -import * as fs from 'fs'; -import * as path from 'path'; - - -let wasmPlugin = { - name: 'wasm', - setup(build) { - // let path = require('path') - // let fs = require('fs') - - // Resolve ".wasm" files to a path with a namespace - build.onResolve({ filter: /\.wasm$/ }, args => { - if (args.resolveDir === '') { - return // Ignore unresolvable paths - } - return { - path: path.isAbsolute(args.path) ? args.path : path.join(args.resolveDir, args.path), - namespace: 'wasm-binary', - } - }) - // Virtual modules in the "wasm-binary" namespace contain the - // actual bytes of the WebAssembly file. This uses esbuild's - // built-in "binary" loader instead of manually embedding the - // binary data inside JavaScript code ourselves. - build.onLoad({ filter: /.*/, namespace: 'wasm-binary' }, async (args) => ({ - contents: await fs.promises.readFile(args.path), - loader: 'binary', - })) - }, -} const context = await esbuild.context({ banner: { @@ -70,8 +40,11 @@ const context = await esbuild.context({ sourcemap: prod ? false : "inline", treeShaking: true, outfile: "main.js", + define: { + PLUGIN_VERSION: JSON.stringify(process.env.npm_package_version) + }, plugins: [ - inlineWorkerPlugin({ format: "cjs", target: "es2018", plugins: [wasmPlugin] }) + inlineWorkerPlugin({ format: "cjs", target: "es2018" }) ] }) diff --git a/package-lock.json b/package-lock.json index 84713b1..0afed30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "obsidian-typst-plugin", - "version": "0.5.1", + "version": "0.8alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "obsidian-typst-plugin", - "version": "0.5.1", + "version": "0.8alpha", "license": "Apache-2.0", "dependencies": { + "@capacitor/core": "^5.5.1", "obsidian": "latest", "obsidian-typst": "file:pkg", "svgo": "^3.0.2", @@ -34,6 +35,14 @@ "node": ">=0.10.0" } }, + "node_modules/@capacitor/core": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.5.1.tgz", + "integrity": "sha512-VG6Iv8Q7ZAbvjodxpvjcSe0jfxUwZXnvjbi93ehuJ6eYP8U926qLSXyrT/DToZq+F6v/HyGyVgn3mrE/9jW2Tg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/@codemirror/state": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.2.1.tgz", @@ -2502,7 +2511,7 @@ }, "pkg": { "name": "obsidian-typst", - "version": "0.5.1" + "version": "0.7.1" }, "pkg/pkg": { "extraneous": true diff --git a/package.json b/package.json index cc36dc2..849a67d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-typst-plugin", - "version": "0.7.1", + "version": "0.8alpha", "description": "Renders `typst` code blocks to images with Typst.", "main": "main.js", "scripts": { @@ -25,6 +25,7 @@ "typescript": "^5.1" }, "dependencies": { + "@capacitor/core": "^5.5.1", "obsidian": "latest", "obsidian-typst": "file:pkg", "svgo": "^3.0.2", diff --git a/src/compiler.worker.ts b/src/compiler.worker.ts index a146712..d43527e 100644 --- a/src/compiler.worker.ts +++ b/src/compiler.worker.ts @@ -1,11 +1,11 @@ //@ts-ignore -import wasmBin from '../pkg/obsidian_typst_bg.wasm' -import * as typst from '../pkg' +// import wasmBin from '../pkg/obsidian_typst_bg.wasm' +import typstInit, * as typst from '../pkg' import { CompileImageCommand, CompileSvgCommand } from "src/types"; -typst.initSync(wasmBin); +// typst.initSync(wasmBin); let canUseSharedArrayBuffer = new Boolean(false); @@ -27,11 +27,20 @@ function requestData(path: string): string { throw buffer[0] } -const compiler = new typst.SystemWorld("", requestData) +let compiler: typst.SystemWorld; //= new typst.SystemWorld("", requestData) -onmessage = (ev: MessageEvent) => { +// Receive data from main thread +// `true` means a sharedarraybuffer can be used +// `Array` is a list of fonts to be added to the compiler +// `string` the url to the web assembly binary data +onmessage = (ev: MessageEvent) => { if (ev.data == true) { canUseSharedArrayBuffer = ev.data + } else if (typeof ev.data == "string") { + typstInit(ev.data).then(_ => { + compiler = new typst.SystemWorld("", requestData) + console.log("Typst web assembly loaded!"); + }) } else if (ev.data instanceof Array) { ev.data.forEach(font => compiler.add_font(new Uint8Array(font))) } else if ("format" in ev.data) { @@ -41,8 +50,6 @@ onmessage = (ev: MessageEvent) = } else if (ev.data.format == "svg") { postMessage(compiler.compile_svg(ev.data.source, ev.data.path)) } - - // postMessage(compile(ev.data)) } else { throw ev; } diff --git a/src/main.ts b/src/main.ts index 52b219b..5fbbda1 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,7 @@ -import { App, renderMath, HexString, Platform, Plugin, PluginSettingTab, Setting, loadMathJax, normalizePath } from 'obsidian'; +import { App, renderMath, HexString, Platform, Plugin, PluginSettingTab, Setting, loadMathJax, normalizePath, Notice, requestUrl } from 'obsidian'; +import { CapacitorHttp } from '@capacitor/core'; +declare const PLUGIN_VERSION: string; // @ts-ignore import CompilerWorker from "./compiler.worker.ts" @@ -19,7 +21,8 @@ interface TypstPluginSettings { shared: string, math: string, code: string, - } + }, + plugin_version: string, } const DEFAULT_SETTINGS: TypstPluginSettings = { @@ -34,7 +37,8 @@ const DEFAULT_SETTINGS: TypstPluginSettings = { shared: "#set text(fill: white, size: SIZE)\n#set page(width: WIDTH, height: HEIGHT)", math: "#set page(margin: 0pt)\n#set align(horizon)", code: "#set page(margin: (y: 1em, x: 0pt))" - } + }, + plugin_version: PLUGIN_VERSION } export default class TypstPlugin extends Plugin { @@ -47,11 +51,35 @@ export default class TypstPlugin extends Plugin { prevCanvasHeight: number = 0; textEncoder: TextEncoder fs: any; + wasmPath = ".obsidian/plugins/typst/obsidian_typst_compiler.wasm" async onload() { + console.log("loading Typst Renderer"); + this.textEncoder = new TextEncoder() await this.loadSettings() + this.compilerWorker = (new CompilerWorker() as Worker); + + if (!await this.app.vault.adapter.exists(this.wasmPath) || this.settings.plugin_version != PLUGIN_VERSION) { + new Notice("Typst Renderer: Downloading required web assembly component!", 5000); + try { + await this.fetchWasm() + new Notice("Typst Renderer: Web assembly component downloaded!", 5000) + } catch (error) { + new Notice("Typst Renderer: Failed to fetch component: " + error, 0) + console.error("Typst Renderer: Failed to fetch component: " + error) + } + } + this.compilerWorker.postMessage( + URL.createObjectURL( + new Blob( + [await this.app.vault.adapter.readBinary(this.wasmPath)], + { type: "application/wasm" } + ) + ) + ) + if (!Platform.isMobileApp) { this.compilerWorker.postMessage(true); this.fs = require("fs") @@ -97,6 +125,26 @@ export default class TypstPlugin extends Plugin { console.log("loaded Typst Renderer"); } + async fetchWasm() { + let response + let data + response = requestUrl(`https://api.github.com/repos/fenjalien/obsidian-typst/releases/tags/${PLUGIN_VERSION}`) + data = await response.json + let asset = data.assets.find((a: any) => a.name == "obsidian_typst_compiler.wasm") + if (asset == undefined) { + throw "Could not find the correct file!" + } + + response = requestUrl({url: asset.url, headers: {"Accept": "application/octet-stream"}}) + data = await response.arrayBuffer + await this.app.vault.adapter.writeBinary( + this.wasmPath, + data + ) + + this.settings.plugin_version = PLUGIN_VERSION + await this.saveSettings() + } async compileToTypst(path: string, source: string, size: number, display: boolean): Promise { return await navigator.locks.request("typst renderer compiler", async (lock) => { @@ -282,6 +330,7 @@ export default class TypstPlugin extends Plugin { async saveSettings() { await this.saveData(this.settings); } + } class TypstSettingTab extends PluginSettingTab {