vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.84k stars 26.96k forks source link

Should next.js be deferred (common.js, main.js) #1436

Closed khrome83 closed 7 years ago

khrome83 commented 7 years ago

Should next.js defer parsing of JS for the common.js and main.js bundles?

Not familiar with the architecture or how to do this, but it came up as a performance issue.

"382.6KiB of JavaScript is parsed during initial page load. Defer parsing JavaScript to reduce blocking of page rendering."

All but 1.5kb was from common.js and main.js code.

sergiodxa commented 7 years ago

🤔 AFAIK If you defer the parsing of common.js and main.js and try to parse (and execute) the code for your view you are going to have an error because your view code depends on common.js and main.js code to work

khrome83 commented 7 years ago

First page load is server rendered. So do need common.js and main.js to run until, after the site downloads? I am just curious.

arunoda commented 7 years ago

@khrome83 You are correct. We can't async those scripts since they need to be load in sequence. But we can defer them.

wagerfield commented 7 years ago

@arunoda the most bulletproof solution to deferring scripts that I've come across is this:

https://varvy.com/pagespeed/defer-loading-javascript.html

As the article explains, adding the the defer or async attributes to script tags doesn't actually allow the page to fully load. You can see the results of different approaches in the various demos he's put together.

Hope this helps :)

arunoda commented 7 years ago

@wagerfield thanks.

defer is all what we need. Since we are not supporting IE9 that's work for us great.

khrome83 commented 7 years ago

Thank you @arunoda for getting this in.

wagerfield commented 7 years ago

@arunoda did you read the article? Adding the defer attribute doesn't actually solve the problem.

This isn't an archaic method for supporting IE9—this is a behaviour that the latest version of Chrome and other modern browsers experience.

If you take a look at the various examples he put together, you will see that adding the defer attribute doesn't prevent a loaded script from blocking the critical rendering path. If a deferred script starts executing as soon as it loads, it will stop the page from fully loading.

https://varvy.com/pagespeed/defer/defer-example-defer.html

In Chrome you will see the loading spinner on the tab where the favicon normally is persist for 2-3 seconds while the deferred script setTimeout is waiting to return—and is thus blocks the critical rendering path.

1

Furthermore if you open Chrome dev tools and go to the Network tab, you will also see that the page doesn't Load for ~2-3secs.

2

If you then take a look at the 'solved' example you will see that a) the browser tab loading spinner doesn't stall and b) that the Load event fires in the dev tools Network tab after ~3-400ms.

https://varvy.com/pagespeed/defer/defer-example-solved.html

3

arunoda commented 7 years ago

@wagerfield yep. I didn't read the article well. What's available here is correct.

I don't like it's use of window.onload but I'll try to use 'DOMContentLoaded'. I'll re-work my PR.

arunoda commented 7 years ago

@wagerfield Actually, I had to use setTimeout(fn, 0) hack to make it work with DOMContentLoaded.

I think, it's not started rendering yet at that point. Here's the code:


<html>
<head>
<script type="text/javascript">

// Add a script element as a child of the body
 function downloadJSAtOnload() {
   setTimeout(function() {
     var element = document.createElement("script");
     element.src = "/defer-example-solved_files/defer.js";
     document.body.appendChild(element);
   }, 0)
 }

 // Check for browser support of event handling capability
 document.addEventListener("DOMContentLoaded", downloadJSAtOnload, false);
</script>
</head>
<body>

<h1>I wait 2 seconds then ...</h1>
<p id="inner"></p>

</body>
</html>
ptomasroos commented 7 years ago

In what way would it be better to use setTimeout, 0 with DomContentLoaded than relying onLoad @arunoda ?

What is there not to like about onLoad? Its been proven since 1999 or something.

arunoda commented 7 years ago

onload is working properly and it runs after all the resources in the page completed. That's good for external scripts.

But this for our main JS bundle. We need to load as soon as possible without rendering the bundle.

I face an issue currenly because I nees to load two scripts in sequence. But I can't download them in parallel. I am thinking ways to do it now

ptomasroos commented 7 years ago

I think react server uses LABjs. Load and block for them to get correctly sequenced. You might take a look at that. It's from yahoo.

arunoda commented 7 years ago

Thanks @ptomasroos Yeah! Labjs is kind a interesting and something I was looking for. But the thing is, we need to test a bit more and it'll take time.

So, I'm going with the defer attribute for now.