Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: use Vite, Vitest; use Rust/WebAssembly instead of Asm.js #20

Merged
merged 5 commits into from
Jun 13, 2022

Conversation

pastelmind
Copy link
Collaborator

@pastelmind pastelmind commented Jun 10, 2022

For the full story, see the second comment.

Summary of changes

For users

For developers

  • Building the project now requires rustup to be installed on your computer. rpm install-ing this project will also install wasm-pack.
  • We now use Vite and Vitest instead of Webpack and Jest.

@pastelmind pastelmind added the type: enhancement New feature or request label Jun 10, 2022
@pastelmind pastelmind self-assigned this Jun 10, 2022
Yehyoung Kang added 3 commits June 13, 2022 15:34
Use Vite instead of Webpack as our build tool. Vite is considerably
simpler and requires less configuration than Jest.
We also need Vite to use Vitest, which provides better support for ESM
and WebAssembly than Jest, and does not require a separate build setup.
Vitest integrates seamlessly with Vite, and supports ESM and WebAssembly
much better than Jest.
Reimplement the image decoder, previously implemented in handwritten
Asm.js, into Rust/WebAssembly. Since Asm.js is effectively a "done"
technology and is unsupported by esbuild, moving to WebAssembly is a
sensible choice.

The new implementation is almost as fast as the previous one in Chrome.

At build time, the WebAssembly binary is inlined into the bundle as a
base64-encoded string. This allows downstream users to use regular
bundlers.

Due to how WebAssembly works, however, the library's signature has
changed.
Now, the library exports a `Promise` object named `init`. This promise
is created when the library is imported, and is resolved asynchronously.
Before using symbols exported by the library (including the default
export), users must wait for the promise to resolve.

example:

    import PSD, {init} from '@webtoon/psd'

    async fun() => {
      await init;
      PSD.parse(/* ... */)
    }
Yehyoung Kang added 2 commits June 13, 2022 15:47
Bump the minimum browser versions (used by eslint-plugin-compat) to
reflect WebAssembly support.

Currently, the minimum browser versions include those that support:
TextDecoder, Typed Arrays, WebAssembly
- Bump supported browser versions
- Update bundle size (larger, but still smaller than competitiors)
- Add info on async initialization and `init`
@pastelmind
Copy link
Collaborator Author

pastelmind commented Jun 13, 2022

Motivation

One of our long-term goals has been using WebAssembly to improve image decoding performance. We initially implemented an asm.js decoder to explore possible performance gains. While we did see a reasonable improvement, we cannot continue to use asm.js for the following reasons:

  1. asm.js is deprecated technology. It has stopped evolving, and is superseded by WebAssembly, which is being actively developed. JavaScript engines may eventually stop supporting it altogether.
  2. Several development tools do not support asm.js. In particular, esbuild does not recognize asm.js syntax; it will mangle asm.js code while bundling, deoptimizing it into vanilla JavaScript code. Anyone who uses esbuild cannot benefit from the performance gains of asm.js.
    Since esbuild powers several popular tools, such as Vite, we can expect asm.js to become less and less useful over time.

These problems meant that we must adopt WebAssembly at some point; that is now.

The following is a detailed explanation of this pull request. It's long, so hold tight.

Note: This pull request depends on #19.

Use Vite & Vitest instead of Webpack & Jest

Vite is a modern build tool. It supports TypeScript and native ESM better than Webpack, and does not require as many plugins to work. It's also very fast for development builds.

Vitest is a test framework which integrates well with Vite, and handles native ESM better than Jest.

Migrate to Rust/WebAssembly

We rewrote the asm.js decoder in Rust. This is compiled to WebAssembly using wasm-pack. The WASM binary is bundled into the build artifact (dist/index.js) as a base64-encoded string. This means that users can continue to use whatever build tool they were using w/o fear of breaking the library. The downside is that the bundle is considerably larger (~73 KiB), but this shouldn't be a problem if your server uses HTTP compression.

When the library is imported, the WASM binary is decoded asynchronously, then the rest of the module is initialized. @webtoon/psd now exports a Promise named init, which resolves when the initialization is done. Users must ensure that the promise is resolved before accessing other values exported by @webtoon/psd--this includes the default export, too!

import PSD, {init} from '@webtoon/psd';

PSD.parse(/* ... */); // error, the library has not been initialized yet

(async () => {
  await init; // Wait for the library to initialize itself
              // Note that 'init' is NOT a function!
              // await init() <-- this is invalid
  PSD.parse(/* ... */);
})();

// If you can use top-level await, this becomes considerably simpler
await init;
PSD.parse(/* ... */);

// Since 'init' is added to the task queue when the library is imported,
// it should probably be loaded by the time an event handler fires.
// Thus, this should _probably_ be safe.
elem.addEventListener('someEvent', () => {
  PSD.parse(/* ... */);
})

From now on, developers must install wasm-pack on their system to build @webtoon/psd.

Preliminary testing indicates that the new WASM decoder performs comparably to the old decoder. In the future, we hope to gain further performance improvements.

@pastelmind pastelmind changed the title feat: use Vite, Vitest; use Rust/WebAssembly instead of Asm.js feat!: use Vite, Vitest; use Rust/WebAssembly instead of Asm.js Jun 13, 2022
@pastelmind pastelmind merged commit deabaa2 into main Jun 13, 2022
@pastelmind pastelmind deleted the feat-wasm branch June 13, 2022 07:36
@pastelmind pastelmind mentioned this pull request Jun 20, 2022
pastelmind pushed a commit that referenced this pull request Jul 13, 2023
…locks-for-effects

expose multipbleObjectBasedeffects and ObjectUndocumented
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant