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

perf: Use named Parser import, to allow bundlers to create direct function references #535

Merged
merged 2 commits into from
Dec 1, 2023

Conversation

absidue
Copy link
Collaborator

@absidue absidue commented Nov 2, 2023

Currently YouTube.js uses a default export to export the Parser functions and the imports that default export, instead of the namespace export/import. Why is that a problem? Because namespace imports are special, the object they give you is special and known as a "module namespace object" (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import#module_namespace_object), which gets treated specially by bundlers, but because we are exporting said object with default we are telling the bundler we want it to be treated as a normal object instead. The result is larger bundles and potentially slower code as you are calling functions on an object, instead of calling the function directly.

These changes have a very minimal impact on the bundles provided by YouTube.js because of an esbuild limitation (it doesn't handle re-exported namespaces well, see: evanw/esbuild#1420) but for anyone using deno, ES modules on node or the web export, will benefit from it, FreeTube for example saves 4337 bytes. This will also help anyone importing the Parser from YouTube.js and using it in their own code, as they'll get the direct function referencing benefits too.

YouTube.js bundles size changes:

File Decrease
browser.js -66 bytes
browser.js.map -50 bytes
browser.min.js -41 bytes
browser.min.js.map -85 bytes
node.cjs -66 bytes
node.cjs.map -52 bytes

So what exactly happens in FreeTube that it shaves off 4337 bytes. The screenshots below were taken with terser-webpack-plugin, patched to set terser's deprecated beautify option to true, the size measurements were taken without that modification. You may want to click on the screenshots to open them in a new tab, so that you can see them bigger.

As we can see on this screenshot, instead of parseResponse being referenced/called directly, it is called on an object PD.
before
If we look at what PD is, it's just a variable assignment so a bit boring, but e is more interesting.
before-variable
Looks like e is an object containing named references referencing the actual parser functions. That's not what we want, but is what is caused by the default export and the use of it, we told the bundler that we don't care abou the module namespace object's special status, instead we want to use it as a normal object, so the bundler complies.
before-barrel

So how does the situation look afterwards? Well that object disappeared from the output and the parseResponse function is now directly referenced/called, in this case _E.
after

While that might not seem like a big change, the parser function are used in a lot of places in YouTube.js (just look at how many files I had to modify for this change), so that smalll change adds up quickly.

@LuanRT LuanRT merged commit 95ed602 into LuanRT:main Dec 1, 2023
4 checks passed
@absidue absidue deleted the parser-named-imports branch December 1, 2023 07:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants