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

chore: improve tree shaking with pure annotations #1501

Merged
merged 2 commits into from
Jul 4, 2024

Conversation

Gravitonic
Copy link
Contributor

@Gravitonic Gravitonic commented Jun 30, 2024

Not sure if this is desired, but by adding some more /* #__PURE__ */ function annotations, I was able to reduce bundle sizes, particularly for use cases only involving XML, since it enables bundlers to tree-shake out the HTML decoding trie. I've tested the tree-shaking behavior with esbuild and Rollup and put the results into a gist here. I've disabled minification for readability, so the file sizes are a bit larger, but I think the relative reductions should be comparable; in this simple case it's ~78% for Rollup and ~82% for esbuild but of course those figures would vary depending on usage.

@fb55
Copy link
Owner

fb55 commented Jun 30, 2024

Hi @Gravitonic, super interesting findings, thanks for this PR! I was under the impression that sideEffects: false in the package.json has the same effect – would you happen to know why that isn't the case?

@Gravitonic
Copy link
Contributor Author

Honestly I'm not completely sure, but here's what I could figure out from my experiments and from what I could find in bundler documentation.

It seems like sideEffects applies at the file level, rather than at the level of particular exports; the bundler only skips a file's imports if none of its exports are used. For instance from the esbuild documentation:

The sideEffects field in package.json can be used to tell esbuild which files in your package can be removed if all imports from that file end up being unused.

or the Webpack documentation:

[The sideEffects field is] similar to /*#__PURE__*/ but on a module level instead of a statement level. It says ("sideEffects" property): "If no direct export from a module flagged with no-sideEffects is used, the bundler can skip evaluating the module for side effects.".

That seems to makes sense with esbuild's metadata; here's why esbuild reports why it currently bundles decode-data-html.js even if only decodeXML is imported:

  1. The input file imports from entities (resolved to dist/esm/index.js)
  2. dist/esm/index.js imports from ./decode.js (resolved to dist/esm/decode.js)
  3. dist/esm/decode.js imports from ./generated/decode-data-html.js (resolved to dist/esm/generated/decode-data-html.js)
  4. So dist/esm/generated/decode-data-html.js is included in the bundle.

Even though the statement with the HTML decoding data is not used, the file is technically imported, and sideEffects only covers cases where none of a file's exports are used. So to mark the statement as having no side effects, I think that's where the /* #__PURE__ */ annotations come in?

@fb55
Copy link
Owner

fb55 commented Jul 1, 2024

That makes sense, yes. Prettier is currently unhappy (likely the removed trailing comma in the type annotation), but otherwise I'm happy to merge this

@fb55 fb55 enabled auto-merge (squash) July 4, 2024 14:13
@fb55 fb55 merged commit c91238d into fb55:master Jul 4, 2024
8 checks passed
@fb55
Copy link
Owner

fb55 commented Jul 5, 2024

Thanks for this awesome PR @Gravitonic!

@Gravitonic
Copy link
Contributor Author

Ah, sorry I got busy during the week — thanks!

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.

2 participants