Skip to content

Initial PageSpeed performance vs .js and .css bundles #1968

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Jonarod opened this issue Apr 11, 2017 · 2 comments
Closed

Initial PageSpeed performance vs .js and .css bundles #1968

Jonarod opened this issue Apr 11, 2017 · 2 comments

Comments

@Jonarod
Copy link

Jonarod commented Apr 11, 2017

Concerned by the initial page load, I tried to put my app into testers like PageSpeed Insights. Though I understand I am not the best developer out there and can definitely review things, what surprises me is that my overall score gets mostly drained by

blocking script resources and blocking CSS resources
namely main.5b5f3790.js and main.61ae6290.css (c-r-a bundles generated by webpack)

Google recommends this :

You should avoid and minimize the use of blocking JavaScript, especially external scripts that must be fetched before they can be executed. Scripts that are necessary to render page content can be inlined to avoid extra network requests, however the inlined content needs to be small and must execute quickly to deliver good performance. Scripts that are not critical to initial render should be made asynchronous or deferred until after the first render. Please keep in mind that for this to improve your loading time, you must also optimize CSS delivery.

I understand that some part of the Javascript and Css could stay like this (due to framework nature of building the page based on javascript). However, a big chunk of the javascript does NOT participate to initial page load, rather they could be called separately or execute asynchronously.

In some related issue, I found several alusions to the require.ensure() function provided by webpack. My concern is that I am a newbie here and doesn't seem to oversee how to implement it in practice so that workflow stays equal.

After reading some docs, I found that basically, I should do something like:

require.ensure([], function(require) {
    var bootstrap = require("bootstrap");
    ...
});

Eventually, this pattern will split my Javascript into 2 separate bundles (tested, it works). However, this implies very poor old fashioned experience of javascript (callback hell?) because as I understand, I should but all my components within the callback of require.ensure()...

I love create-react-app as a developer, but I don't think my users will feel the same passion if I can't boost their experience and ask them to wait for AAAAAAAALLLLLLLLL my files to be downloaded.

So after hours searching and fighting my pagespeed score, I surrender myself to you guys:
how do you handle pagespeed issues and particularly blocking resources ? Do you use require.ensure()? In which context? How do you handle big .js and .css bundle?
Some examples would be more than appreciated.

Thanks

@gaearon
Copy link
Contributor

gaearon commented Apr 11, 2017

Google recommends this

This recommendation is only useful for apps that aren’t fully constructed in JS so we don’t follow it. It definitely makes sense if your app is partially server rendered, but this not the case for CRA.

Eventually, this pattern will split my Javascript into 2 separate bundles (tested, it works). However, this implies very poor old fashioned experience of javascript (callback hell?) because as I understand, I should but all my components within the callback of require.ensure()...

No, this is not the case. require.ensure() can be used anywhere (not just at top level) and you definitely don’t need to rewrite your components. For example it could look like this:

let TodoList = null;

class LazyTodoList extends Component {
  constructor(props) {
    super(props);
    this.state = { isReady: TodoList !== null };
  }

  componentDidMount() {
    require.ensure('./TodoList', () => {
      TodoList = require('./TodoList').default;
      if (!this.hasUnmounted) {
        this.setState({ isReady: true });
      }
    });
  }

  componentWillUnmount() {
    this.hasUnmounted = true;
  }

  render() {
    return this.state.isReady ? <TodoList /> : <h1>Loading...</h1>;
  }
}

This will load TodoList (and any components it depends on) lazily. You don’t need to do anything special in TodoList itself: Webpack will put all its dependencies into the separate bundle automatically even though they are written synchronously.

It is a bit awkward to use require.ensure because of its callback API and CommonJS legacy (see how we had to access .default). So in next version of react-scripts we will support the dynamic import() API proposal which offers the same functionality behind a Promise interface. It would look like this:

  componentDidMount() {
    import('./TodoList').then(TodoList => {
      if (!this.hasUnmounted) {
        this.setState({ isReady: true });
      }
    });
  }

This will be supported in [email protected].

Hope this helps!

@gaearon gaearon closed this as completed Apr 11, 2017
@Jonarod
Copy link
Author

Jonarod commented Apr 11, 2017

Oh I see. Thank you very much for your devoted time on this.
Your example is for sure really usefull and self-explanatory.
In the meanwhile, this lecture also helped me: Medium - Page load performance with react (PWA)

@lock lock bot locked and limited conversation to collaborators Jan 22, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants