Most of the code in the bundle is library code so make use of Cache-Control and ETag headers for caching library code. At hashnode our bundle.js is served from cloudinary which adds Cache-Control:public, max-age=2500611 . 2500611 seconds = 694 hours So hashnode js bundle is cached for 694 hours, but on each deployment our bundle name( and thus url) is changed and changed URL of the resource force the user to download the new response. Thus we are able to leverage http caching and also able to deploy quickly.
You can also use service workers for caching library code which doesn't change that quickly.
Try to render first page on server and make your js bundle script asynchronous (as javascript is parser blocking).
If you are using webpack checkout this awesome question in webpack ama.