Skip to content

Reduce plugin bundle size#24

Merged
cyanzhong merged 2 commits into
mainfrom
copilot/reduce-bundle-size-harper-obsidian
Mar 14, 2026
Merged

Reduce plugin bundle size#24
cyanzhong merged 2 commits into
mainfrom
copilot/reduce-bundle-size-harper-obsidian

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 14, 2026

The MarkEdit proofreading bundle was larger than Harper’s Obsidian plugin despite fewer features. Root cause was double inclusion of Harper’s inlined WASM payload in the final single-file build.

  • Root cause

    • src/lint.ts instantiated LocalLinter with binaryInlined, which embeds the full WASM data URL directly in JS.
    • In this bundling setup, that led to duplicated WASM payload content in the output bundle.
  • Change made

    • Switched Harper initialization to use binary instead of binaryInlined in src/lint.ts.
    • Kept linter behavior and feature surface unchanged; only binary sourcing changed.
  • Impact

    • Removes avoidable binary duplication from the generated bundle.
    • Significantly reduces output size while preserving existing proofreading functionality.
// before
import { LocalLinter, binaryInlined } from 'harper.js';
const linter = new LocalLinter({ binary: binaryInlined });

// after
import { LocalLinter, binary } from 'harper.js';
const linter = new LocalLinter({ binary });
Original prompt

This section details on the original issue you should resolve

<issue_title>Reduce the bundle size</issue_title>
<issue_description>The Harper Obsidian plugin bundle size is 38.5 MB, whereas our current bundle size is 46.9 MB.

We need to understand why, since we have fewer features bundled in.

https://github.com/Automattic/harper/tree/master/packages/obsidian-plugin/src</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.

Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
Copilot AI changed the title [WIP] [ISSUE-123] Reduce the bundle size of Harper Obsidian plugin Reduce plugin bundle size by removing duplicated Harper WASM payload Mar 14, 2026
Copilot AI requested a review from cyanzhong March 14, 2026 12:55
@cyanzhong
Copy link
Copy Markdown
Contributor

@copilot The change really cuts a lot of bundle size, which is good.

However, I would like to understand a bit deeper. Like, why this works and is there any feature we lost due to this change?

What is the recommended approach choosing between binary and binaryInlined?

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 14, 2026

@copilot The change really cuts a lot of bundle size, which is good.

However, I would like to understand a bit deeper. Like, why this works and is there any feature we lost due to t...

Both binary and binaryInlined create the same BinaryModule — they differ only in how the 16.7 MB WASM payload is referenced:

  • binary → points to an external file via new URL("harper_wasm_bg.wasm", import.meta.url).href
  • binaryInlined → embeds the full WASM as a ~23 MB base64 data URL string literal directly in the JS source

At runtime, BinaryModule.create() resolves either URL the same way, fetching and initializing the identical WASM module. No features are lost — the linter behavior is exactly the same.

The duplication happened because our build uses vite-plugin-singlefile, which inlines all external assets into a single JS file. When binaryInlined was imported, the bundle contained:

  1. The 23 MB data URL string from binaryInlinedUrl (imported directly)
  2. A second copy inlined by vite-plugin-singlefile from the external .wasm file

Even though binary wasn't explicitly used, the bundler wasn't fully tree-shaking binaryUrl because its new URL(...) pattern creates a side-effectful asset reference that Vite resolves.

Switching to binary means the bundle only includes the one copy that vite-plugin-singlefile inlines from the external .wasm file, while the unused binaryInlinedUrl (a pure string literal) gets properly tree-shaken away.

Recommended approach: binaryInlined is intended for environments that can't load external files at all and don't have a bundler that handles asset inlining (e.g., a raw single-file Obsidian plugin). Since MarkEdit already uses vite-plugin-singlefile to produce a self-contained bundle, binary is the right choice — it lets the bundler handle the inlining once, avoiding the double copy.

@cyanzhong
Copy link
Copy Markdown
Contributor

@copilot Does binary require network access to load the database?

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 14, 2026

@copilot Does binary require network access to load the database?

No. binary references the .wasm file via new URL("harper_wasm_bg.wasm", import.meta.url), which Vite resolves as an asset at build time. Since the build uses vite-plugin-singlefile, that asset gets inlined into the final single JS file as a data URL — so at runtime, the WASM is already embedded in the bundle with no network fetch needed.

In short, both binary and binaryInlined end up fully self-contained in the output. The difference is only in when inlining happens: binaryInlined pre-embeds it in the source (causing duplication when the bundler also inlines the external copy), while binary lets the bundler handle it once.

@cyanzhong cyanzhong marked this pull request as ready for review March 14, 2026 13:15
@cyanzhong cyanzhong changed the title Reduce plugin bundle size by removing duplicated Harper WASM payload Reduce plugin bundle size Mar 14, 2026
@cyanzhong cyanzhong merged commit 168f310 into main Mar 14, 2026
4 checks passed
@cyanzhong cyanzhong deleted the copilot/reduce-bundle-size-harper-obsidian branch March 14, 2026 13:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reduce the bundle size

2 participants