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

Decrease browser bundle size #681

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Decrease browser bundle size #681

wants to merge 4 commits into from

Conversation

mb21
Copy link

@mb21 mb21 commented Apr 11, 2024

closes #679

This PR does four things:

  1. Optimizing for more modern browsers by removing forceAllTransforms, which was added in Remove core-js and provide transpiled ES Module output #192 by @goto-bus-stop (as part of ESM support), although the PR description seems to imply that forceAllTransforms wasn't intended. (this makes the esm browser bundle go from from 97KB down to 47KB)
  2. Removing the url-parse package in favour of Node/browser-native new Url (saves 16KB)
  3. Removing the js-base64 package in favour of btoa (saves 9.6KB)
  4. Add info to package.json for https://volta.sh, so that you can easily install the old yarn version used in this project (feel free to remove that commit if you think it doesn't belong).

@mb21 mb21 marked this pull request as ready for review April 11, 2024 14:03
@Acconut
Copy link
Member

Acconut commented Apr 17, 2024

Thank you for the investigation and this PR!

Optimizing for more modern browsers by removing forceAllTransforms, which was added in #192 by @goto-bus-stop (as part of ESM support), although the PR description seems to imply that forceAllTransforms wasn't intended. (this makes the esm browser bundle go from from 97KB down to 47KB)

Good point! I am no expert at transpiling and bundling, which seems to be a whole science on its own. Nowadays we can raise our requirements on the ECMAScript support by the user's bundler and browsers. Although this has to happen in a major release to avoid breaking changes in a minor release. That being said, I have recently worked a bit on moving tus-js-client to TypeScript (#683), which was also a good opportunity to raise the compilation target.

3. Removing the js-base64 package in favour of btoa (saves 9.6KB)

This dependency was added to support tus-js-client inside React Native environment, where btoa is not available. See the pull request #132 and especially the commit 0c72e86. Although the React Native JS runtime looks similar to the environment in a browser, React Native apps cannot utilize all Web APIs and btoa is not provided. Hence we need a polyfill for this situation.

That being said, ~10KB for base64 encoding seems a bit too much and there are two possible approaches I can think of

  • try to only import the encoding function in the hopes that tree shaking is able to remove the rest of the js-base64 package: import {encode} from 'js-base64'
  • write our own base64 encoding function instead of relying on packages or environment support. That should be doable in less than 10KB.

Ideally, we would only need a polyfill for React Native, but I am not sure how that would be possible.

2. Removing the url-parse package in favour of Node/browser-native new Url (saves 16KB)

Similar story as before. URL is not available in React Native and thus we needed a polyfill: 53a6ac3.

An advantage of using those packages instead of using environment-specific APIs is that we get more consistent behavior, which is not influenced by subtle different between the implementations.

4. Add info to package.json for https://volta.sh, so that you can easily install the old yarn version used in this project (feel free to remove that commit if you think it doesn't belong).

I don't know about Volta, but such a change should be in a separate PR and not part of this one. That being said, maybe it's worth considering switching back to NPM, which does not have different versions as Yarn appears to have.

@mb21
Copy link
Author

mb21 commented Apr 17, 2024

Ah, I didn't think of React Native. Hm... not sure, but it's possible that using a dynamic import could work:

const encodeBase64 = navigator.product === 'ReactNative'
  ? (await import('js-base64')).encode
  : btoa

At least when bundled with webpack, this should create its own chunk. But not sure about vite/rollup.

But yeah, that seems more like a hack that relies on runtime-detection of react native. Perhaps it would be better to create two separate builds: one for web and one for react native?

@Acconut
Copy link
Member

Acconut commented Apr 17, 2024

I am hesitant with dynamic imports as I fear that they make the entire setup more complex and brittle. A separate build would also be possible, but I would prefer we first explore solutions to reduce the size of the base64 encoder, either by adjusting the import statement or pulling the code into tus-js-client directly.

@mb21
Copy link
Author

mb21 commented Apr 17, 2024

Yeah, you could use this implementation. But polyfilling URL is probably going to be bigger.

@mb21
Copy link
Author

mb21 commented Apr 17, 2024

Ah, I've never done React Native development, but react-native-url-polyfill says:

React Native does include a polyfill for URL, but this polyfill is homemade — in order to keep it light-weight — and was initially created to handle specific use cases.

@mb21
Copy link
Author

mb21 commented May 4, 2024

Either way, I would avoid publishing the bundled files to npm. (See e.g. this StackOverflow question). Not sure how the TypeScript conversion is going, but it's possible that using tsc instead of esbuild will be enough.

@Acconut
Copy link
Member

Acconut commented May 17, 2024

Either way, I would avoid publishing the bundled files to npm.

We currently include a bundled version alongside the original source code and a transpiled version. The latter two are referenced in the package.json, so the bundler can decide whatever variant it prefers using. The bundled version is not used in such cases. It is only included, so that people can download the bundle from NPM or use it via services like jsDelivr. Under such circumstances, I don't think it's harmful to include a bundled version in the package. The StackOverflow question you linked seems to refer to package which only include a bundled version, which is not the case for tus-js-client (and we intend to keep it that way).

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.

Decrease browser bundle size
2 participants