App: [$500] ExpensiMark: large bundle size
Problem A simple script that uses ExpensiMark library to parse Markdown into HTML has a bundle size of 336 kB (or 184 kB minified) which is quite big.
Details
The file is large because it contains mappings of all HTML entities (from _.escape) and countries, states, currencies etc. from CONST.jsx.
Solution Investigate if it’s possible to minimize the bundle size.
Steps to reproduce
index.js
import ExpensiMark from "expensify-common/lib/ExpensiMark";
const input = "Hello, *world*!";
const parser = new ExpensiMark();
const output = parser.replace(input);
console.log(JSON.stringify(input));
console.log(JSON.stringify(output));
esbuild index.js --bundle --minify --outfile=out.js
out.js: https://pastebin.swmansion.com/?9798f33833cc33b6#DRgiwxs8ujteamHaGDioSzZVZ83nuWUim3QabJ5PUYed
Issue Owner
Current Issue Owner: @SkalakidUpwork Automation - Do Not Edit
- Upwork Job URL: https://www.upwork.com/jobs/~0155a63860a646579c
- Upwork Job ID: 1740457868647858176
- Last Price Increase: 2024-01-04
- Automatic offers:
- fedirjh | Reviewer | 28090032
- aswin-s | Contributor | 28099676
About this issue
- Original URL
- State: closed
- Created 8 months ago
- Comments: 46 (36 by maintainers)
Found another opportunity to reduce bundle size.
ExpensifyMark.jsandstr.jsuses below methods from underscore.These could be replaced with pure ES6 methods. That shaves off another 20kb, bringing down the minified bundle size to approximately 129kb.
Based on bundle analysis 50% of the bundle is html-entities library. named-references to be exact.
CONST.jsxcontributes just 12kb to the whole bundle. So shouldn’t we focus more on how to optimise the usage ofhtml-entities?However a polyfill of String.prototype.replaceAll is embedded in
Strfile. I guess this was for Node 14 compatibility and no longer needed. Removing this polyfill itself reduces 30kb from entire bundle resulting in a 16% savings.PRs for this issue were reviewed internally
@roryabraham I want to make sure I’m looking at the Correct PR. The one above has not merged to production yet, correct? The payment countdown starts after it’s merged to production and there are no regressions.
@aswin-s The PR above https://github.com/Expensify/expensify-common/pull/632 is not showing merged to prod yet.
once that happens the payment title for this GH will auto-update with the payment date
I agree with @aswin-s’s suggestion regarding the removal of the
String.prototype.replaceAllpolyfill. This change is straightforward and indeed offers a significant reduction in the bundle sizeRemoving the polyfill impacts the backward compatibility and potential technical debt for legacy systems. It might be beneficial to conduct a quick survey or analysis to determine how many such legacy projects are dependent on
expensify-commonand their current Node.js versions.I am generally in favor of removing the polyfill, as it primarily affects projects running on very old versions of Node.js (older than 15), which are likely to be a minority if any
@roryabraham Also not sure why we overlooked the removal of
String.prototype.replaceAll. That amounts to 30KB (16% savings). Seems like that’s more relevant thanunderscoresince it is being shared with other packages.https://bundlephobia.com/package/string.prototype.replaceall@1.0.8
It evolved as the result of fixing many different bugs people found over the years, so my hunch is it would be very high-risk for a low reward to try and update that.
Hi contributors 👋🏼
I’ve left some suggestions for how to improve this, but the approach can be open-ended. If multiple contributors have different ideas too, we could potentially hire more than one (in that case, it would probably be simplest to create separate issues to track the work separately).
Also note that the expensify-common codebase must remain compatible with vanilla (non-typescript) js code so that it can continue to be used in our legacy javascript codebases.
Moving this back to weekly. We are hoping to launch this feature in January, so we should start making moves here too. @Skalakid is going to be focused on inline video, so we should find someone else to tag in on this.
No update from me, but @Skalakid keep me posted if you’re starting to work on this
Maybe the first and easiest steps here are to: