Skip to content

chore: improve tree shaking with pure annotations#1501

Merged
fb55 merged 2 commits intofb55:masterfrom
Gravitonic:master
Jul 4, 2024
Merged

chore: improve tree shaking with pure annotations#1501
fb55 merged 2 commits intofb55:masterfrom
Gravitonic:master

Conversation

@Gravitonic
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
@fb55
Copy link
Copy Markdown
Owner

fb55 commented Jul 5, 2024

Thanks for this awesome PR @Gravitonic!

@Gravitonic
Copy link
Copy Markdown
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