Skip to content
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

Initial page load too slow #1013

Closed
sedubois opened this issue Feb 6, 2017 · 44 comments
Closed

Initial page load too slow #1013

sedubois opened this issue Feb 6, 2017 · 44 comments

Comments

@sedubois
Copy link
Contributor

sedubois commented Feb 6, 2017

There's something quite inefficient going on e.g in the with-apollo example, the initial page load is way too slow:

screen shot 2017-02-06 at 14 09 30

PageSpeed Insights confirms (score of 75/100), sometimes saying the server responded in 2.5 seconds, sometimes in 1.1 seconds.

@sedubois
Copy link
Contributor Author

sedubois commented Feb 6, 2017

cc @ads1018

@sedubois
Copy link
Contributor Author

sedubois commented Feb 6, 2017

As for Nextgram, PSI gives 100/100, but I still get a 5 seconds load time when trying myself:

screen shot 2017-02-06 at 14 22 12

BTW why doesn't Nextgram have the same chunks commons.js, main.js, etc?

@alikhani
Copy link

alikhani commented Feb 6, 2017

Their could be ways to improve the perf using apollo, if you have multiple queries going at the same time, e.g. using batching-interface and deduplication.
Don't know if it would do anything in this example but in more complex projects maybe..

@sedubois
Copy link
Contributor Author

sedubois commented Feb 6, 2017

@alikhani There's a single query in this example, so it doesn't explain the current issue.

@sedubois
Copy link
Contributor Author

sedubois commented Feb 6, 2017

@marktani suggested to check Pingdom, similar results (tested from NYC):

screen shot 2017-02-06 at 14 49 54

screen shot 2017-02-06 at 14 51 38

screen shot 2017-02-06 at 16 18 41

@marktani
Copy link

marktani commented Feb 6, 2017

Interesting interaction: after you loaded the page and reload it, Chrome DevTools show between 2 and 4 seconds needed to "Request ServiceWorker".

@sedubois
Copy link
Contributor Author

sedubois commented Feb 6, 2017

@arunoda would you have an idea about @marktani's observation regarding service workers?

@timneutkens
Copy link
Member

@marktani @sedubois #957 and #1004 might be related

@arunoda
Copy link
Contributor

arunoda commented Feb 6, 2017

@sedubois This might be related to now.sh's container start time or something related.
I've also seen that.

But for the 2nd page reload (after deleting the cache) it works pretty well

@sedubois
Copy link
Contributor Author

sedubois commented Feb 6, 2017

@arunoda even after several page loads, the 1.7 seconds wait time was still present. So it's not just container boot time.

@sedubois
Copy link
Contributor Author

sedubois commented Feb 6, 2017

The screenshots above were made when Now containers were already booted.

@sedubois
Copy link
Contributor Author

sedubois commented Feb 6, 2017

I added Next-news (which was just updated to latest Next.js by @rauchg) to the list of Pingdom screenshots above. But also 2.9 seconds waiting time.

@sedubois
Copy link
Contributor Author

sedubois commented Feb 6, 2017

This would be something with the whole now.sh infrastructure? Because now all response times are twice smaller (pingdom test from NYC: 982 ms for with-apollo, 1.39 sec for nextgram, 1.22 sec for next-news).

And earlier today my own app (https://relate.now.sh) had sometimes a 25 sec server waiting time, and now it's down to 783 ms.

Maybe this issue should be opened on Now's side.

@timneutkens
Copy link
Member

cc @jamo

@rauchg
Copy link
Member

rauchg commented Feb 6, 2017

We're now tracking this on #now

@rauchg rauchg closed this as completed Feb 6, 2017
@sedubois
Copy link
Contributor Author

sedubois commented Feb 6, 2017

Great 👍 where do you mean on #now, @rauchg could you link?

@rauchg
Copy link
Member

rauchg commented Feb 6, 2017

@sedubois we'll keep you posted on zeit.chat 🎉

@jhwheeler
Copy link

I'm having a similar issue where the container boot time is incredibly slow. After it's booted, even a hard refresh takes 10x less time than previously. Does this have to do with which plan you're on?

@cyrus-za
Copy link

cyrus-za commented Jul 25, 2017

My issue might not be directly related, but I am also experiencing long load times. Not only when hosting on now, but also in local environemnt.

My app was based off the with-apollo example and each new page/route takes very long the first time, but its instant after first load (until the cache gets cleared by the server).

I'm still pretty new to both apollo and next and the whole concept of SSR.

I've modified the with-data.js and init-apollo.js files so not sure if it's actually got to do with my own file state, but it's definitely a big issue to load 3-5 seconds for each route.

with-data.js

import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import { reducer as FormReducer } from 'redux-form'
import React, { Component } from 'react'
import { ApolloProvider, getDataFromTree, withApollo } from 'react-apollo'
import thunk from 'redux-thunk';
import initApollo from './init-apollo'
import { getToken } from "./auth";

function combineReduxFormWithApollo(apolloClient) {
    const middleware = [thunk, apolloClient.middleware()];
    return createStore(
        combineReducers({
            form: FormReducer,
            apollo: apolloClient.reducer(),
        }),
        {},
        compose(
            applyMiddleware(...middleware),
            // If you are using the devToolsExtension, you can add it here also
            (process.browser && (typeof window.__REDUX_DEVTOOLS_EXTENSION__ !== 'undefined') ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f),
        )
    )
}

const withData = ComposedComponent => {
    return class extends Component {
        static propTypes = {
            // serverState: PropTypes.object.isRequired
        }

        static async getInitialProps(context) {
            let serverState = {}

            // Setup a server-side one-time-use apollo client for initial props and
            // rendering (on server)
            let apollo = initApollo({}, {
                getToken: () => getToken(context)
            })

            // Evaluate the composed component's getInitialProps()
            let composedInitialProps = {}
            if (ComposedComponent.getInitialProps) {
                composedInitialProps = await ComposedComponent.getInitialProps(context, apollo)
            }

            // Run all graphql queries in the component tree
            // and extract the resulting data
            if (!process.browser) {
                if (context.res && context.res.finished) {
                    // When redirecting, the response is finished.
                    // No point in continuing to render
                    return;
                }

                // Provide the `url` prop data in case a graphql query uses it
                const url = {query: context.query, pathname: context.pathname}

                const store = combineReduxFormWithApollo(apollo);

                // Run all graphql queries
                const app = (
                    <ApolloProvider client={apollo} store={store}>
                        <ComposedComponent url={url} {...composedInitialProps} />
                    </ApolloProvider>
                )
                await getDataFromTree(app)

                // Extract query data from the Apollo's store
                const state = apollo.getInitialState()

                serverState = {
                    apollo: { // Make sure to only include Apollo's data state
                        data: state.data
                    }
                }
            }
            return {
                serverState,
                ...composedInitialProps
            }
        }

        constructor(props) {
            super(props)
            // Note: Apollo should never be used on the server side beyond the initial
            // render within `getInitialProps()` above (since the entire prop tree
            // will be initialized there), meaning the below will only ever be
            // executed on the client.

            this.apollo = initApollo(this.props.serverState, {
                getToken
            })

            this.store = combineReduxFormWithApollo(this.apollo);
        }

        render() {
            return (
                <ApolloProvider client={this.apollo} store={this.store}>
                    <ComposedComponent {...this.props} />
                </ApolloProvider>
            )
        }
    }
}

export default (component) => {
    return compose(
        withData,
        withApollo,
    )(component)
}

init-apollo.js

import { ApolloClient, createNetworkInterface } from 'react-apollo'
import fetch from 'isomorphic-fetch'
import { GRAPHQL_ENDPOINT } from "./config";

let apolloClient = null

// Polyfill fetch() on the server (used by apollo-client)
if (!process.browser) {
    global.fetch = fetch
}

function create(initialState, {getToken}) {

    const networkInterface = createNetworkInterface({
        uri: GRAPHQL_ENDPOINT
    });

    networkInterface.use([{
        applyMiddleware(req, next) {
            if (!req.options.headers) {
                req.options.headers = req.headers || {};  // Create the header object if needed.
            }
            const token = getToken();
            req.options.headers.authorization = token ? `Bearer ${token}` : null;
            next();
        }
    }]);

    return new ApolloClient({
        initialState,
        dataIdFromObject: o => o.id,
        ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
        networkInterface
    })
}

export default function initApollo(initialState, options) {
    // Make sure to create a new client for every server-side request so that data
    // isn't shared between connections (which would be bad)
    if (!process.browser) {
        return create(initialState, options)
    }

    // Reuse client on the client-side
    if (!apolloClient) {
        apolloClient = create(initialState, options)
    }

    return apolloClient
}

@vilvadot
Copy link

@cyrus-za any news on this? also experiencing the same issues

@adamsoffer
Copy link
Contributor

adamsoffer commented Aug 29, 2017

Are you running in dev or production mode? In dev mode Next only compiles the page you are viewing so it will appear slower when navigating between routes. Production mode should be fine.

@cyrus-za
Copy link

@ads1018 running in production, but using server.js as I had to add next-routes.

I do call next({dev: undefined}) though instead of dev:true so that should do it right?

@adamsoffer
Copy link
Contributor

Try something like this inside server.js:

const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })

@cyrus-za
Copy link

cyrus-za commented Sep 2, 2017

@ads1018 that is exactly what I have currently.

@rovansteen
Copy link
Contributor

@cyprus-za did you manage to resolve this? I’m running in to a similar issue with performance with next and Apollo.

@cyrus-za
Copy link

cyrus-za commented Feb 27, 2018 via email

@aaronkchsu
Copy link

I am running into this too! I will try to upgrade and see what happens! Thanks for everyone who commented on this!

@f2net
Copy link

f2net commented May 3, 2018

I have a similar problem on https://www.greenfarmacia.it
You can see that even switching between the simple pages on the top header (Chi siamo, Info acquisti, Contatti), after some clicks it becomes very slow. Then, also a simple Redux change (in a category page, switching from thumbnails to list) becomes very slow.

I am using Next 5.1 in production mode, using withData HOC from the with-apollo example and the withRedux HOC.

@adamsoffer Do you think that using your npm package next-apollo (instead of the example's /lib withData) could solve this performance problem?

Thank you,
Matteo

@adamsoffer
Copy link
Contributor

@f2net Hmm I'm not sure, but it's worth a try.

@mtoso
Copy link

mtoso commented Jul 4, 2018

@f2net did you have any improvement using next-apollo?

@ythecombinator
Copy link

Any news on this? I have reached a quite similar point where it seems to happen when I open the production app for the first time on the day. This first request comes from the SW and it takes more than a minute to load:

screen shot 2018-08-23 at 8 09 02 am

screen shot 2018-08-23 at 8 09 12 am

@timneutkens
Copy link
Member

timneutkens commented Aug 24, 2018

Not really sure what to do with this comment. Did you check your getInitialProps?

I just realized you're hosting on Now, it seems like ofm.belp.fun is set to freeze, with a scale of 0-1 if you now scale ofm.belp.fun 1 the deployment will keep online and not freeze. There's very big improvement in unfreeze times coming, you can read about it here: https://zeit.co/blog/serverless-docker.

Another thing I saw is that it seems like your start command crashes, causing a reload loop until backoff occurs. The reason for this seems to be that you're trying to remove some files on start, deployments are immutable so any filesystem operations should be done in the build step. As the filesystem is read-only when start occurs.

@ythecombinator
Copy link

Thanks for the quick reply, @timneutkens! I had considered what you mentioned but it turns out that it happens more than once a day, in general. I mean, everytime a user opens the app for the first time on the day–so, actually, it happens once a day per user and that's what made me discard the possibility of my issue being related to now.sh itself. Doesn't make sense for you?

@timneutkens
Copy link
Member

Well your app can be frozen based on a lot of metrics, but the problem here is that unfreezing could crash because of the "start" in package.json, it's not just booting up the app, it's trying clean up some babel things.

@andrerpena
Copy link

Unbelievable. I have a simple project with 1 query deployed with next-apollo and WebPageTest is reporting 3.5s to first miningful paint. I will investigate and update this thread

@avilaj
Copy link

avilaj commented May 31, 2019

Unbelievable. I have a simple project with 1 query deployed with next-apollo and WebPageTest is reporting 3.5s to first miningful paint. I will investigate and update this thread

Have you had any improvement on the matter?
I'm having some harsh times with apollo and next.

@stevez86
Copy link

Also having issues. I think it has to do with how google measures speed or an incorrect timing event. I have a site where everything is cached (including html) and I consistently get the page load event under 500ms, after hydrate event fires at 1.2s (on pagespeed mobile) but my first content paint is 5s! I also use apollo but not sure how that could affect performance adversely (there are no requests made client side). Any leads on how to solve this would be appreciated.

@olso
Copy link

olso commented May 14, 2020

Same with relay

@unluberkay
Copy link

any news?

@millievn
Copy link

any solutions now?

@melvin2016
Copy link

Mine too

@dangerisgo2021
Copy link

have the same issue since all js need to be loaded react, Apollo client and redux before my first content full paint is calculated at + 3 seconds but my page loads < 1 seconds as far as I can tell. is there a way that my ssr render will count as my first contentful paint before they all load. individually the examples have a highscore in lighthouse but from what I can find with typescript, Apollo, React, and Redux they take greater than 3 seconds to fully load and reach fist contentful paint, Time to Interactive and Largest Contentful Paint. I thought SSR would fix all this. My first load JS is flagged as too large particularly my _app file but I don't know how to reduce it as I still wish to use graphql and redux for my application. Next-auth also seem to reduce my score significantly

feels like next and by extension next-auth, react, redux and apollo cant compete with non spa pages or am I full messing everything up. let me know if sharing my repo would help.

@juanfh
Copy link

juanfh commented Aug 28, 2021

@ads1018 running in production, but using server.js as I had to add next-routes.

I do call next({dev: undefined}) though instead of dev:true so that should do it right?

Thats works fine

const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev: undefined })

@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 27, 2022
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