WICG / webpackage

Web packaging format
Other
1.23k stars 116 forks source link

Interest in implementing in a bundler & dev server (subresource loading) #705

Open Jarred-Sumner opened 2 years ago

Jarred-Sumner commented 2 years ago

I’d be interested in potentially implementing support for outputting Web Bundles in a new bundler & transpiler called Bun.

The specific motivation for Bun’s usecase today is to improve page load time in development for large apps while keeping hot module reloading incredibly fast.

Currently, there’s an unfortunate tradeoff for hot module reloading <> bundling. Bundling improves page load time, but means the browser must reload lots of code for small changes. There are various workarounds, but a better solution is if browsers exposed an interface for remapping import paths to byte ranges within a bundled file (like with web bundles!)

From there, the initial request could be bundled and the bundler-specific implementation of hot module reloading would be able to use consistent import paths in transpiled code. Consistent import paths help prevent reloading code unnecessarily. The alternative is implementing a custom module loader on top of either ESM or <script> tags, which adds runtime & build-time performance overhead.

Incase it's helpful, here's a little about the metadata Bun's current bundling format stores.
For apps with ~15 MB of JavaScript dependencies (3,185 modules & 295 npm packages), the metadata loads in ~0.15ms on my laptop ![image](https://user-images.githubusercontent.com/709451/145673293-b416deb4-ff36-476c-8b9d-2d3337645440.png) The file starts with `#!/usr/bin/env bun\n`, followed by a byte offset to the start of the metadata, then the bundled code for each file, and at the end, the metadata. ```proto // This is the top-level type loaded from disk message JavascriptBundleContainer { uint32 bundle_format_version = 1; // These fields are specific to Bun and probably not other bundlers LoadedRouteConfig routes = 3; LoadedFramework framework = 2; JavascriptBundle bundle = 4; // Don't technically need to store this, but it may be helpful as a sanity check uint32 code_length = 5; } struct StringPointer { uint32 offset; uint32 length; } struct JavascriptBundledModule { // package-relative path including file extension StringPointer path; // Source code StringPointer code; // index into JavascriptBundle.packages uint32 package_id; // The ESM export is this id ("$" + number.toString(16)) uint32 id; // This lets us efficiently compare strings ignoring the extension byte path_extname_length; } struct JavascriptBundledPackage { StringPointer name; StringPointer version; uint32 hash; uint32 modules_offset; uint32 modules_length; } struct JavascriptBundle { // These are sorted alphabetically so you can do binary search JavascriptBundledModule[] modules; JavascriptBundledPackage[] packages; byte[] etag; uint32 generated_at; // generated by hashing all ${name}@${version} in sorted order byte[] app_package_json_dependencies_hash; byte[] import_from_name; // This is what StringPointer refers to byte[] manifest_string; } ``` Eventually, this will include exports & imports of each module.

Is the recommended way to try out web bundles in a browser today using the <link> based api & an origin trial with Chromium?

hayatoito commented 2 years ago

Thanks for filing an issue!

How Web Bundles can help hot module reloading seems an interesting topic. We've never thought how a browser-native bundle format, Web Bundles, can help HMR.

We don't have any plan nor ideas as of now, and I am not fully aware how a browser can help to support HMR nicely. If you have any specific requests, that would be welcomed!

Is the recommended way to try out web bundles in a browser today using the based api & an origin trial with Chromium?

You can try the feature locally by enabling the flag. This guide might be helpful:

https://chromium.googlesource.com/chromium/src/+/refs/heads/main/content/browser/web_package/subresource_loading_origin_trial.md#how-to-try-this-feature-locally