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

Implement "on demand entries" #1111

Merged
merged 35 commits into from
Feb 26, 2017
Merged

Implement "on demand entries" #1111

merged 35 commits into from
Feb 26, 2017

Conversation

arunoda
Copy link
Contributor

@arunoda arunoda commented Feb 13, 2017

Related #608

This is a dev only optimization

This is new concept to reduce the dev-rebuild time dramatically if you have a lot of pages in your app.

With this, we don't add pages to webpack when building the dev server. But when we are accessing the page, we'll build the page and add it webpack.

With this, we were able to cut down "15 secs" dev re-build time to "1-2" secs.

In order to use this productively, we have to disable prefetching pages when we are in development.

TODO:

  • Remove older pages from webpack
    • Get the currently active page from the client side.
  • Add some integration tests

@rauchg
Copy link
Member

rauchg commented Feb 13, 2017

Why optional?

@arunoda
Copy link
Contributor Author

arunoda commented Feb 13, 2017

No special reason. Since this is not the way how webpack works normally, some users may don't like this.

So, we should implement this as opt-in or opt-out.

@timneutkens
Copy link
Member

This fixes #608 right?

@arunoda
Copy link
Contributor Author

arunoda commented Feb 14, 2017

@timneutkens Yes. It's has the core. Let's make both related.


function ping () {
const url = `/on-demand-entries-ping?page=${Router.pathname}`
fetch(url)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's to watch active entries and dispose inactive pages.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is it implemented ? on-demand-entry-handler.js#middleware is doing nothing ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check now. I was implementing that :)

compilation.addEntry(context, dep, name, (err) => {
if (err) return reject(err)
resolve()
})
Copy link
Contributor

@nkzawa nkzawa Feb 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should not use private plugins.
Webpack v2 supports dynamic entries by setting a function to the entry option. So what we'd like to do is to change returned entries according to page requests. I think we can do that with an optional entry function on server/build/webpack.js.

Copy link
Contributor Author

@arunoda arunoda Feb 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a private function. It's documented by webpack.

Anyway, I'll try to use dynamic functions in the refactoring stage.
For now, this seems like the best option for now as we do more stuff related to entry management.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant about plugins 'webpack/lib/DynamicEntryPlugin'. I'd like to fix that in this PR if possible or I will do it later.

@arunoda arunoda changed the title [WIP] Implement "on demand entries" Implement "on demand entries" Feb 14, 2017
@arunoda
Copy link
Contributor Author

arunoda commented Feb 15, 2017

EDIT: Actually, this issue was there from the beginning. See: #1165

After 8a495aa HMR is not working correctly.

@arunoda arunoda changed the title Implement "on demand entries" [WIP] Implement "on demand entries" Feb 15, 2017
@arunoda arunoda modified the milestones: 2.0, 2.1 Feb 25, 2017
@arunoda
Copy link
Contributor Author

arunoda commented Feb 25, 2017

@timneutkens This is in 2.0.
We are taking this early next week.

@timneutkens
Copy link
Member

timneutkens commented Feb 25, 2017

@arunoda great, I want it in 😄 ❤️ , @rauchg said after 2.0 in #next on slack yesterday, that's why I added the milestone 👍

@leo
Copy link
Contributor

leo commented Feb 25, 2017

@arunoda ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️

I hope you know that you're literally saving me and the ZEIT team a lot of valuable lifetime.

@arunoda
Copy link
Contributor Author

arunoda commented Feb 26, 2017

timneutkens I think we can't wait that long :)

@arunoda
Copy link
Contributor Author

arunoda commented Feb 26, 2017

Guys this is ready. Could you run this few tests before we merge in?

dev,
maxInactiveAge = 1000 * 25
}) {
const server = await getServer()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we are starting a websocket server to accept pings.
The best idea is to hook into our existing app.
But with our API, we don't have access to the server object. So, we can't do that without changing the API.

Since this is dev only, it's fine to start a new server. Which is lightweight of course.

Why?

Earlier we did by sending a HTTP request from the client for every 5 secs. But those requests could be blocked at any time by the chrome for sending too much of requests.

And that could block HMR updates as well.
So, that's why we moved to WS.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But those requests could be blocked at any time by the chrome for sending too much of requests.

Elaborate please?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chrome(and other browsers) has 6 concurrent connection limit for hosts. We won't send 6 connections but sometimes chrome set some of these requests into the stalled state.
May be it things we are sending too many requests.

Then it'll block the request which webpack asks for HMR changes time to time.
I couldn't find a better way other than using a Websocket connection.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Chrome sets it at 8 nowadays. Even then, we would only take up one socket ? Also, I believe webpack uses WS?

Copy link
Contributor Author

@arunoda arunoda Feb 26, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even then, we would only take up one socket ?

With HTTP2 yes it is. But it's not there always.

I believe webpack uses WS?

No it's not. It uses server sent events(HMR middleware) + 2 HTTP requests.

@@ -224,6 +224,10 @@ export default class Router extends EventEmitter {
}

async prefetch (url) {
// We don't add support for prefetch in the development mode.
// If we do that, our on-demand-entries optimization won't performs better
if (process.env.NODE_ENV === 'development') return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some other places test with process.env.NODE_ENV !== 'production' instead.

Developers might have forgotten to define process.env.NODE_ENV but still expect to have a development behaviour in that case.

I think it would be nice if all the code tested whether it's in a production mode or not, in a coherent way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we could use the dev provided when setting up the app (server side). Not sure if we pass it through to the client side though, will allow for consistent behaviour not based on NODE_ENV.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sedubois we set NODE_ENV always. See: https://github.com/zeit/next.js/pull/1111/files#diff-0f2f34c098f5954f99483c9bd61e439dR94

We didn't use 'production' check here because, we need to allow prefetching in JEST.
So, this is safe.

@sedubois
Copy link
Contributor

sedubois commented Feb 26, 2017

It's mentioned that this should be opt-in/-out configurable, but I don't see any user documentation added in this PR.

@arunoda
Copy link
Contributor Author

arunoda commented Feb 26, 2017

@sedubois currently we make this as default and there'll be no opt-out.
We'll go with the beta like that.
Then if we need to make it opt-out, let's do it.

@rauchg proposed that and the idea is to remove options as possible as we can. (Without harming the dev/prod experience).

@rauchg rauchg merged commit d3b1ead into vercel:master Feb 26, 2017
@arunoda arunoda deleted the ondemand-entries branch February 26, 2017 19:56
@jschumme
Copy link

I'm wondering if that change causes a permanent recompiling of my application in development. It actually stops after 16 recompilations.

 Ready on http://localhost:3000
Client pings, but there's no entry for page: /
> Building page: /
 DONE  Compiled successfully in 5545ms22:20:00

 WAIT  Compiling...22:20:00

 DONE  Compiled successfully in 259ms22:20:01

 WAIT  Compiling...22:20:01

 DONE  Compiled successfully in 258ms22:20:01

 WAIT  Compiling...22:20:01

 DONE  Compiled successfully in 190ms22:20:02

 WAIT  Compiling...22:20:02

 DONE  Compiled successfully in 270ms22:20:03

@rauchg
Copy link
Member

rauchg commented Feb 27, 2017

@DarKAdmiral a fix is coming. Beta 34 is on your way.


function ping () {
const url = `/on-demand-entries-ping?page=${Router.pathname}`
fetch(url)
Copy link

@Rajat421 Rajat421 Mar 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(node:18740) DeprecationWarning: loaderUtils.parseQuery() received a non-string value which can be problematic, see webpack/loader-utils#56
parseQuery() will be replaced with getOptions() in the next major version of loader-utils.

i am recieving this warning can you tell me how to resolve this, this warning came when i've updated my 'next' version

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you create an issue for this?

@mojo5000
Copy link

So there is no 'opt-out' flag avail at this time?

@arunoda
Copy link
Contributor Author

arunoda commented Apr 29, 2017

@mojo5000 nope. Currently there's no such flag.

@lock lock bot locked as resolved and limited conversation to collaborators May 12, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants