Nice, will take a look at the generated stats.json. Another thought would be having the bundle analyzer built-in galaxy or hosted online…
1.085 MB, ~300 kb gzipped. MVP
Nice! is that the total bundle size? what view layer are you using?
I’m working on an example app that uses ReactRouter 3. I found the trick I needed here. See the Why bundle loader, and not import()? section further down that page.
Just so everyone knows, that meteor-node-stubs
npm package lets you import stubs for Node built-in modules on the client, like assert
and path
. Only the modules you actually use get bundled, so don’t be fooled by the total size of node_modules/meteor-node-stubs
. And it goes without saying (though this was kinda tricky) that stub modules can be imported dynamically if they’re not otherwise imported statically.
We don’t use
- FontAwesome or alike pre-compiled iconic font sets
- Bootstrap or other CSS framework/lib
We do use:
- Google fonts, while font in the load process, or failed to be loaded, we’re trying to find best matching font from local visitor’ fonts in descending order
- Compiled iconic fonts with only icons we need, and CSS it needs
- SASS for internal styling with auto-prefixes - Not sure if it helps to save some bytes
- Jade for Blaze templates - Not sure if it helps to save some bytes
Steps we have done:
- After dynamic
import
s was introduced in Meteor 1.5 the fist idea was to swap our existingrequire(...)
in FlowRouter routes rules toimport(...)
, in a way described here. This is the most significant optimization our app ever faced. - Next we found most rarely used files which somehow got imported in the
client/index.js
(bundle), and moved to dependent modules or replaced with alternatives where is possible (saved ~100KB) - Momentjs, Stringjs, Diffjs, Numeraljs those heavy libs was imported to the bundle and weight around ~300KB altogether, we have tried to make those dependencies dynamically imported (and we did), but code complexity at this point with all internal
async
/await
got out of the control so we decided to rollback, and have those libs in the main bundle. - Find a way to optimize Momentjs and Stringjs turn out we have been using only 5 features of Momentjs and 2 of Stringjs, so we compiled Momentjs and Stringjs with only features we need (saved ~180KB)
- Review CSS/SASS rules (saved ~12KB)
- Remove unused/useless meteor packages -
reactive-dict
,autoupdate
,es5-shim
,appcache
,mobile-experience
Final results:
- The
js
file size returned from meteor app (gzipped) - 247KB (Google Chrome DevTools - Network Tab) - The app size according to
bundle-visualizer
- 607KB (Yes, not ~300KB as at the first message, we brought back some NPM packages after tests) - The biggest packages we have now is
Blaze
andjQuery
(both is tied to each other). Curious to see size of the apps with React. Anyone?
WHAT
That is incredible! Awesome work!!
React. My app import code is only 100kb which helps. Relatively simple app.
Final result a little bigger, but gzip compression is doing its thing.
What is unusual - we have tried to utilize dynamic import
s for CSS/SASS files. After quick splitting and binding to the templates bundle size (according to bundle-visualizer
) grew for ~80KB (0_o).
And either SASS was processed to CSS, transferred code over WebSockets wasn’t minified - is there any info about behind the scenes how dynamic import
s acts with different types of files?
Is the size reported by bundle-visualizer minified and gzipped? I’m asking because the size it reports is significantly bigger than what website analyzers like GTmetrix report.
No, not gzipped. Yes, minified. Should be the byte to byte analysis. For more info see hashsum.stats.json
where hashum
is taken from main js file hashsum.js
I’d recommend trying out Fort Awesome, by the same team that made Font Awesome. It provides icon font hosting on a CDN, with the ability to pick and choose which icons you serve, as well as the ability to upload custom SVG icons.
looking at that file, I see this:
"totalMinifiedBytes": 1202640,
"totalMinifiedGzipBytes": 331222,
is that the true gzipped size? if it is it would be really cool for the bundle-visualizer
package to display that
I just created a basic app with the bare flag: meteor create --bare
. Then I only added npm’s react and react-dom package.
meteor create --bare my-app
cd my-app
meteor npm install --save react react-dom
meteor --extra-packages bundle-visualizer --production
Size is 584kB. React-dom is 180kB.
Am I missing something? It seems huge to me.
As I’ve mentioned in my post it’s Blaze/jQuery version of Meteor setup (not React, not sure how is big React itself). Plus we have removed some of the default Meteor packages, like reactive-dict
, autoupdate
, es5-shim
, appcache
, mobile-experience
.
Before dynamic route import: 2.5 MB
After: 1.5 MB
Can probably shave off some more if I do things right.
Total Bundle Size
63.47 MB
Client Bundle Size
2.77 MB
From, before dynamic imports:
Total Bundle Size
62.76 MB
Client Bundle Size
3.7 MB
This is after shaving off about 1MB thanks to dynamic updates and other improvements in 1.6. From early testing of 1.6.1 betas I will make it under 2MB then (react-intl
dependency is the biggest issue right now).
Hey guys i have tried to write down the journey we took to reduce the app size of a meteor project.
Link to blog
Please let me know your views.
note, that you have to add dynamic-import
to the extra packages when running bundle visualization. I found that without there maybe not all dynamic imports reflected correctly.
Besides that, I think @rjdavid mentioned in an earlier post, that their client bundle is about 1MB
@jkuester I cannot replicate what you did here. The one with dynamic-import is just the same as the one without. But yes, I can see a number of lazy loaded components in the graph that should not be in the bundle