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

Optimize dispatch plain object check #2599

Merged
merged 2 commits into from Nov 16, 2017

Conversation

@timdorr
Member

timdorr commented Sep 5, 2017

Closes #2598

This boosts perf by not exhaustively checking every action of it's object-ness. Dispatch is approximately 56x faster. Across a million runs of simple counter reducer:

master: 4690.358ms
nodash: 82.821ms

I also applied the same thing in combineReducers. I believe the check is sufficient, but I'd love a second set of eyes on it.

We also no longer need to bundle any of lodash, so this saves a good number of bytes too! From the UMD build:

26715 master/redux.js
21518 nodash/redux.js
5761 master/redux.min.js
4813 nodash/redux.min.js

@markerikson

This comment has been minimized.

Show comment
Hide comment
@markerikson

markerikson Sep 5, 2017

Contributor

Looks okay at first glance, although the nuances of JS object detection are something I've never had to deal with. Do we have some tests around this scenario?

Contributor

markerikson commented Sep 5, 2017

Looks okay at first glance, although the nuances of JS object detection are something I've never had to deal with. Do we have some tests around this scenario?

@markerikson

This comment has been minimized.

Show comment
Hide comment
@markerikson

markerikson Sep 5, 2017

Contributor

I saw an email from a review comment come through, but I'm not seeing that comment as I'm looking at the diff. The email said:

This seems to have the same problem with an old-fashioned isArray implementation. It always fails if the action comes from another window.

Anyone more knowledgeable have thoughts on that?

Contributor

markerikson commented Sep 5, 2017

I saw an email from a review comment come through, but I'm not seeing that comment as I'm looking at the diff. The email said:

This seems to have the same problem with an old-fashioned isArray implementation. It always fails if the action comes from another window.

Anyone more knowledgeable have thoughts on that?

@timdorr

This comment has been minimized.

Show comment
Hide comment
@timdorr

timdorr Sep 5, 2017

Member

Another alternative to checking constructor is to toString the object and see if that is [object Object].

Member

timdorr commented Sep 5, 2017

Another alternative to checking constructor is to toString the object and see if that is [object Object].

@milesj

This comment has been minimized.

Show comment
Hide comment
@milesj

milesj Sep 5, 2017

Constructor checks should be enough IMO.

milesj commented Sep 5, 2017

Constructor checks should be enough IMO.

@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton Sep 5, 2017

Contributor

The isPlainObject check is certainly more robust, but if it's not needed, and a simpler check is doable, more power to ya.

Does anyone know the history of using plain object checks over simpler ones?
It looks like it's used to warn of incorrect usage. Could this be moved to a doc note to avoid the check entirely?

Contributor

jdalton commented Sep 5, 2017

The isPlainObject check is certainly more robust, but if it's not needed, and a simpler check is doable, more power to ya.

Does anyone know the history of using plain object checks over simpler ones?
It looks like it's used to warn of incorrect usage. Could this be moved to a doc note to avoid the check entirely?

@timdorr

This comment has been minimized.

Show comment
Hide comment
@timdorr

timdorr Sep 5, 2017

Member

@jdalton It's a good safety net for someone that makes a mistake when setting up something like redux-thunk or another middleware. Happens a fair amount and is more friendly to beginners.

Member

timdorr commented Sep 5, 2017

@jdalton It's a good safety net for someone that makes a mistake when setting up something like redux-thunk or another middleware. Happens a fair amount and is more friendly to beginners.

@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton Sep 5, 2017

Contributor

Happens a fair amount and is more friendly to beginners.

Could it be something that's available in dev builds and removed in production?
Or maybe toggleable with some debug: false redux option?

How are similar debug helpers handled in react?

Contributor

jdalton commented Sep 5, 2017

Happens a fair amount and is more friendly to beginners.

Could it be something that's available in dev builds and removed in production?
Or maybe toggleable with some debug: false redux option?

How are similar debug helpers handled in react?

@timdorr

This comment has been minimized.

Show comment
Hide comment
@timdorr

timdorr Sep 5, 2017

Member

We have some dev-only checks in combineReducers, but not much else. Unfortunately, it's easy to miss a lot of these issues without 100% test coverage, so having "friendlier" errors in production is pretty helpful to our users. Other than this strict check, they are mostly fairly simple and performant enough to warrant leaving it.

AFAIK, React still uses the dev-expression babel plugin and __DEV__ checks in their code.

Member

timdorr commented Sep 5, 2017

We have some dev-only checks in combineReducers, but not much else. Unfortunately, it's easy to miss a lot of these issues without 100% test coverage, so having "friendlier" errors in production is pretty helpful to our users. Other than this strict check, they are mostly fairly simple and performant enough to warrant leaving it.

AFAIK, React still uses the dev-expression babel plugin and __DEV__ checks in their code.

@markerikson

This comment has been minimized.

Show comment
Hide comment
@markerikson

markerikson Sep 5, 2017

Contributor

Couple more questions:

  1. What scenarios are likely to result in someone dispatching objects from Object.create(null), or from another window?
  2. What checks would be necessary to catch those?

Per 1, I know I've seen several addons that do stuff like serializing actions over postMessage, Electron main-vs-render interop, and similar concepts. I'm not sure if any of those would run into trouble with this change.

Contributor

markerikson commented Sep 5, 2017

Couple more questions:

  1. What scenarios are likely to result in someone dispatching objects from Object.create(null), or from another window?
  2. What checks would be necessary to catch those?

Per 1, I know I've seen several addons that do stuff like serializing actions over postMessage, Electron main-vs-render interop, and similar concepts. I'm not sure if any of those would run into trouble with this change.

@timdorr

This comment has been minimized.

Show comment
Hide comment
@timdorr

timdorr Sep 6, 2017

Member

Object.create(null)

Seems unlikely. Most folks use object literals.

from another window

This I have zero clue about. Not saying that it's not possible, just that I've never done it and don't know the implications. Can someone wire up a demo so we can test it out?

BTW, my company does this in our Chrome extension. We have a background page with the Redux store that is replicated to the frontend content scripts. We do phone calls, so we need a single place to maintain our dialer's state. I'll ask the engineer who built that out.

Member

timdorr commented Sep 6, 2017

Object.create(null)

Seems unlikely. Most folks use object literals.

from another window

This I have zero clue about. Not saying that it's not possible, just that I've never done it and don't know the implications. Can someone wire up a demo so we can test it out?

BTW, my company does this in our Chrome extension. We have a background page with the Redux store that is replicated to the frontend content scripts. We do phone calls, so we need a single place to maintain our dialer's state. I'll ask the engineer who built that out.

Show outdated Hide outdated src/combineReducers.js Outdated
@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Sep 6, 2017

Contributor

My two cents:

  1. Cross-iframe and cross-realm things can get weird and cause false negatives. I'm really happy with the effort that went into Lodash implementation.

  2. I don't think benchmarks are very relevant. If you're dispatching more than one or two actions in a second you already have a performance problem because your subscribers are executing much more often. You might want to reconsider using Redux if dispatching is your bottleneck.

Contributor

gaearon commented Sep 6, 2017

My two cents:

  1. Cross-iframe and cross-realm things can get weird and cause false negatives. I'm really happy with the effort that went into Lodash implementation.

  2. I don't think benchmarks are very relevant. If you're dispatching more than one or two actions in a second you already have a performance problem because your subscribers are executing much more often. You might want to reconsider using Redux if dispatching is your bottleneck.

@timdorr timdorr changed the title from Remove lodash. to Optimize dispatch plain object check Sep 6, 2017

@timdorr

This comment has been minimized.

Show comment
Hide comment
@timdorr

timdorr Sep 6, 2017

Member

<Retitling this so it doesn't come across as a dig against lodash>

Member

timdorr commented Sep 6, 2017

<Retitling this so it doesn't come across as a dig against lodash>

@markerikson

This comment has been minimized.

Show comment
Hide comment
@markerikson

markerikson Sep 6, 2017

Contributor

More research questions:

  1. What edge cases do all the individual checks in lodash.isPlainObject actually handle?
  2. Which of those checks are the most expensive?
  3. Which of the edge cases are we actually concerned about in practice?
Contributor

markerikson commented Sep 6, 2017

More research questions:

  1. What edge cases do all the individual checks in lodash.isPlainObject actually handle?
  2. Which of those checks are the most expensive?
  3. Which of the edge cases are we actually concerned about in practice?
@markerikson

This comment has been minimized.

Show comment
Hide comment
@markerikson

markerikson Sep 6, 2017

Contributor

@gaearon , I've anecdotally seen plenty of cases where people are firing off way more than "one or two actions a second". I agree that subscribers are generally the bottleneck, but if we can reasonably say that there's some "plain object" edge cases that we aren't concerned with and improve dispatching perf overall, it's worth at least investigating.

Contributor

markerikson commented Sep 6, 2017

@gaearon , I've anecdotally seen plenty of cases where people are firing off way more than "one or two actions a second". I agree that subscribers are generally the bottleneck, but if we can reasonably say that there's some "plain object" edge cases that we aren't concerned with and improve dispatching perf overall, it's worth at least investigating.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Sep 6, 2017

Contributor

The problem is that we'll likely get false negatives for plain objects rather than false positives. In other words we'll now throw for things that are actually completely okay (and are plain objects).

This is hugely disruptive to people who already rely on current behavior in their apps, sometimes without a good alternative.

I've anecdotally seen plenty of cases where people are firing off way more than "one or two actions a second"

OK. Let's say 60 dispatches per second is the maximum I would consider reasonable. Does this PR make a measurable difference in this case?

Contributor

gaearon commented Sep 6, 2017

The problem is that we'll likely get false negatives for plain objects rather than false positives. In other words we'll now throw for things that are actually completely okay (and are plain objects).

This is hugely disruptive to people who already rely on current behavior in their apps, sometimes without a good alternative.

I've anecdotally seen plenty of cases where people are firing off way more than "one or two actions a second"

OK. Let's say 60 dispatches per second is the maximum I would consider reasonable. Does this PR make a measurable difference in this case?

@rodrigorm

This comment has been minimized.

Show comment
Hide comment
@rodrigorm

rodrigorm Sep 6, 2017

@gaearon I have run a sample with 60 dispatches before and apter applying the patch:

$ node .
master: 0.164ms
nodash: 0.162ms

rodrigorm commented Sep 6, 2017

@gaearon I have run a sample with 60 dispatches before and apter applying the patch:

$ node .
master: 0.164ms
nodash: 0.162ms
@jayhasyee

This comment has been minimized.

Show comment
Hide comment
@jayhasyee

jayhasyee Sep 6, 2017

@timdorr @gaearon I can suggest a lazy assertion.

  1. first we check the action by my previous less strict suggestion
  2. if it does not meet with the first restriction, we can check with isPlainObject or something else

Benefits: we do not punish the regular users, but in edge cases there may be performance overheads

IMHO I think we should leave Lodash, because that's a heavy dependency.
My new suggestion:

if (!action || (action.constructor !== Object && !action.__proto__ && typeof action !== 'object')) {
  throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.');
}

jayhasyee commented Sep 6, 2017

@timdorr @gaearon I can suggest a lazy assertion.

  1. first we check the action by my previous less strict suggestion
  2. if it does not meet with the first restriction, we can check with isPlainObject or something else

Benefits: we do not punish the regular users, but in edge cases there may be performance overheads

IMHO I think we should leave Lodash, because that's a heavy dependency.
My new suggestion:

if (!action || (action.constructor !== Object && !action.__proto__ && typeof action !== 'object')) {
  throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.');
}
@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Sep 6, 2017

Contributor

I like this (idea, not the code snippet which I think doesn't do that). Any downsides?

Contributor

gaearon commented Sep 6, 2017

I like this (idea, not the code snippet which I think doesn't do that). Any downsides?

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Sep 6, 2017

Contributor

Are there objects with constructor === Object but that are not considered plain objects by Lodash?

Contributor

gaearon commented Sep 6, 2017

Are there objects with constructor === Object but that are not considered plain objects by Lodash?

@jayhasyee

This comment has been minimized.

Show comment
Hide comment
@jayhasyee

jayhasyee Sep 6, 2017

I can imagine some frequently used dispatch: logging. I've used Redux for this, and I was glad by its performance. I think the performance improving is a cardinal purpose, because Redux is a very essential library in the most of React projects. If we can make it smaller and faster, that can only be good.

jayhasyee commented Sep 6, 2017

I can imagine some frequently used dispatch: logging. I've used Redux for this, and I was glad by its performance. I think the performance improving is a cardinal purpose, because Redux is a very essential library in the most of React projects. If we can make it smaller and faster, that can only be good.

@jayhasyee

This comment has been minimized.

Show comment
Hide comment
@jayhasyee

jayhasyee Sep 6, 2017

@gaearon I tried my snippet with regular and Object.create(null) actions. Both of them worked.
With regular actions I measured 70-90 ms.
With the other that was 200-300 ms.
I am not sure that covers all of cases that isPlainObject performs. But I can agree, that the lazy assertion is our first approximation, and removing Lodash may be an other issue.

Idea: we should use Lodash's test cases.

jayhasyee commented Sep 6, 2017

@gaearon I tried my snippet with regular and Object.create(null) actions. Both of them worked.
With regular actions I measured 70-90 ms.
With the other that was 200-300 ms.
I am not sure that covers all of cases that isPlainObject performs. But I can agree, that the lazy assertion is our first approximation, and removing Lodash may be an other issue.

Idea: we should use Lodash's test cases.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Sep 6, 2017

Contributor

What I'm trying to say is whatever the cost of isPlainObject is, the cost of calling subscribers and reducers will likely dwarf it in real projects. Can we please test this on a real project with 60 dispatches per second before proceeding?

Contributor

gaearon commented Sep 6, 2017

What I'm trying to say is whatever the cost of isPlainObject is, the cost of calling subscribers and reducers will likely dwarf it in real projects. Can we please test this on a real project with 60 dispatches per second before proceeding?

@jimbolla

This comment has been minimized.

Show comment
Hide comment
@jimbolla

jimbolla Sep 6, 2017

Contributor

react-redux also uses lodash's isPlainObject to test the results of mapXToProps. It only does it during dev builds, not production. It seems like the intent of this code is the same; to make sure the developer isn't doing anything wacky. By the time it gets to prod build, the issue should have been resolved.

Contributor

jimbolla commented Sep 6, 2017

react-redux also uses lodash's isPlainObject to test the results of mapXToProps. It only does it during dev builds, not production. It seems like the intent of this code is the same; to make sure the developer isn't doing anything wacky. By the time it gets to prod build, the issue should have been resolved.

@lukescott

This comment has been minimized.

Show comment
Hide comment
@lukescott

lukescott Oct 26, 2017

I think object.constructor === Object would only be an issue with cross-frames if:

  • The frame is the same origin
  • You compare a variable from one frame to another: An Object in one frame is different from an Object in another.

But if you're using postMessage, the communication is serialized, so it shouldn't be an issue. Typically taking a variable from another frame is a bad idea in general.

lukescott commented Oct 26, 2017

I think object.constructor === Object would only be an issue with cross-frames if:

  • The frame is the same origin
  • You compare a variable from one frame to another: An Object in one frame is different from an Object in another.

But if you're using postMessage, the communication is serialized, so it shouldn't be an issue. Typically taking a variable from another frame is a bad idea in general.

@timdorr timdorr added this to the 4.0 milestone Nov 3, 2017

@timdorr timdorr changed the base branch from master to next Nov 3, 2017

@timdorr

This comment has been minimized.

Show comment
Hide comment
@timdorr

timdorr Nov 3, 2017

Member

I'm going to make this held off for 4.0, so we can get more extensive testing via the prerelease cycle. It's now rebased against the next branch.

Just to be clear, I'm on the same side of not seeing this being about a speed optimization, as dispatches should be relatively infrequent in most applications and not a bottleneck. Instead, it's a good chance to drop an external dependency that brings a fair amount of bytes with it. It's not huge, but every little bit helps.

But the key blocker here is equivalency of the plain object check. I'd love a simple function for doing that. What would be most helpful here is a test harness I can use to ensure this is equivalent. Something around message passing via iframes and fun edge case stuff. I think we can do it 👍

Member

timdorr commented Nov 3, 2017

I'm going to make this held off for 4.0, so we can get more extensive testing via the prerelease cycle. It's now rebased against the next branch.

Just to be clear, I'm on the same side of not seeing this being about a speed optimization, as dispatches should be relatively infrequent in most applications and not a bottleneck. Instead, it's a good chance to drop an external dependency that brings a fair amount of bytes with it. It's not huge, but every little bit helps.

But the key blocker here is equivalency of the plain object check. I'd love a simple function for doing that. What would be most helpful here is a test harness I can use to ensure this is equivalent. Something around message passing via iframes and fun edge case stuff. I think we can do it 👍

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Nov 3, 2017

Contributor

I'd be fine with making the check more relaxed but not more constrained.

Contributor

gaearon commented Nov 3, 2017

I'd be fine with making the check more relaxed but not more constrained.

@markerikson

This comment has been minimized.

Show comment
Hide comment
@markerikson

markerikson Nov 5, 2017

Contributor

Interesting to read the history of isPlainObject.js , and the discussion in PR #131 where we previously swapped Lodash for homegrown utils the first time. Note the prior discussion about sizes, and also see Dan's comments about how he wants isPlainObject to behave.

Contributor

markerikson commented Nov 5, 2017

Interesting to read the history of isPlainObject.js , and the discussion in PR #131 where we previously swapped Lodash for homegrown utils the first time. Note the prior discussion about sizes, and also see Dan's comments about how he wants isPlainObject to behave.

@timdorr

This comment has been minimized.

Show comment
Hide comment
@timdorr

timdorr Nov 8, 2017

Member

OK, I've brought back our home-grown isPlainObject with a much faster implementation and with less bytes. I also brought back our previous tests to ensure it works.

To prove it out in the browser context, here's a test-case of the exact same code: https://gist.github.com/timdorr/326ed608a9cbe67f247c2fbc709cdba3

I've provided both a true and false case. Performance is still pretty good:

next: 4690.358ms
nodash: 807.397ms

Byte savings are still there too:

28582 next/redux.js
23763 nodash/redux.js
 7135 next/redux.min.js
 6340 nodash/redux.min.js

This should satisfy everyone's concerns, I believe. But let me know what obvious stuff I missed 😄

Member

timdorr commented Nov 8, 2017

OK, I've brought back our home-grown isPlainObject with a much faster implementation and with less bytes. I also brought back our previous tests to ensure it works.

To prove it out in the browser context, here's a test-case of the exact same code: https://gist.github.com/timdorr/326ed608a9cbe67f247c2fbc709cdba3

I've provided both a true and false case. Performance is still pretty good:

next: 4690.358ms
nodash: 807.397ms

Byte savings are still there too:

28582 next/redux.js
23763 nodash/redux.js
 7135 next/redux.min.js
 6340 nodash/redux.min.js

This should satisfy everyone's concerns, I believe. But let me know what obvious stuff I missed 😄

@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton Nov 8, 2017

Contributor

Are null prototype objects, Object.create(null) considered plain objects for y'all?

Contributor

jdalton commented Nov 8, 2017

Are null prototype objects, Object.create(null) considered plain objects for y'all?

@timdorr

This comment has been minimized.

Show comment
Hide comment
@timdorr

timdorr Nov 8, 2017

Member

I consider that a very rare enough edge case to warrant not covering it. It's certainly acceptable to start rejecting it in a major revision.

Member

timdorr commented Nov 8, 2017

I consider that a very rare enough edge case to warrant not covering it. It's certainly acceptable to start rejecting it in a major revision.

@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton Nov 8, 2017

Contributor

Cool! I like while loop walking approach. I'll probably use it for Lodash too 😸

Contributor

jdalton commented Nov 8, 2017

Cool! I like while loop walking approach. I'll probably use it for Lodash too 😸

@timdorr

This comment has been minimized.

Show comment
Hide comment
@timdorr

timdorr Nov 8, 2017

Member

Yeah, it's neat.

Just so others understand its purpose: It handles cross-realm objects by walking up the prototype chain until it reaches Object and checks if that "Object" has the same prototype as our potential plain object.

In the case of something coming from an iframe, that Object is different than your own local Object because they come from two different JavaScript contexts. So, we use this technique to get to that definition of Object for the object instance.

It serves as a good perf boost because you can short circuit a fair number of cases before they would get to the slower toString() calls (that's the part that slows down lodash/isPlainObject and is-plain-object).

Member

timdorr commented Nov 8, 2017

Yeah, it's neat.

Just so others understand its purpose: It handles cross-realm objects by walking up the prototype chain until it reaches Object and checks if that "Object" has the same prototype as our potential plain object.

In the case of something coming from an iframe, that Object is different than your own local Object because they come from two different JavaScript contexts. So, we use this technique to get to that definition of Object for the object instance.

It serves as a good perf boost because you can short circuit a fair number of cases before they would get to the slower toString() calls (that's the part that slows down lodash/isPlainObject and is-plain-object).

@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton Nov 8, 2017

Contributor

@timdorr

It serves as a good perf boost because you can short circuit a fair number of cases before they would get to the slower toString() calls (that's the part that slows down lodash/isPlainObject and is-plain-object).

Yep, now imagine if you put that effort into improving Lodash (instead of ripping it out).
I get it. I'm here now, so I can catch this improvement, but I can't stumble upon all-the-things. Giving a heads up to maintainers and helping them out improves your project (that deps it) as well as everyone else that depends on it. 👍

Contributor

jdalton commented Nov 8, 2017

@timdorr

It serves as a good perf boost because you can short circuit a fair number of cases before they would get to the slower toString() calls (that's the part that slows down lodash/isPlainObject and is-plain-object).

Yep, now imagine if you put that effort into improving Lodash (instead of ripping it out).
I get it. I'm here now, so I can catch this improvement, but I can't stumble upon all-the-things. Giving a heads up to maintainers and helping them out improves your project (that deps it) as well as everyone else that depends on it. 👍

@timdorr

This comment has been minimized.

Show comment
Hide comment
@timdorr

timdorr Nov 8, 2017

Member

I still want the byte savings. Lodash would be helpful if we made more extensive use of it, but for this simple case, keeping it in house and only testing the cases we care about is best.

Member

timdorr commented Nov 8, 2017

I still want the byte savings. Lodash would be helpful if we made more extensive use of it, but for this simple case, keeping it in house and only testing the cases we care about is best.

@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton Nov 8, 2017

Contributor

I still want the byte savings.

Ya'll haven't even used the webpack plugins that reduce its size.

keeping it in house and only testing the cases we care about is best.

I donnoo Redux used Lodash, removed it, went back, it's a whole thing. The argument for using Lodash before was reduced maintenance burden and more eyes on it.

Contributor

jdalton commented Nov 8, 2017

I still want the byte savings.

Ya'll haven't even used the webpack plugins that reduce its size.

keeping it in house and only testing the cases we care about is best.

I donnoo Redux used Lodash, removed it, went back, it's a whole thing. The argument for using Lodash before was reduced maintenance burden and more eyes on it.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Nov 8, 2017

Contributor

I would feel more comfortable if we attempted to contribute this upstream to Lodash first before forking.

Contributor

gaearon commented Nov 8, 2017

I would feel more comfortable if we attempted to contribute this upstream to Lodash first before forking.

@timdorr

This comment has been minimized.

Show comment
Hide comment
@timdorr

timdorr Nov 8, 2017

Member

Ya'll haven't even used the webpack plugins that reduce its size.

We don't use webpack.

Member

timdorr commented Nov 8, 2017

Ya'll haven't even used the webpack plugins that reduce its size.

We don't use webpack.

@timdorr

This comment has been minimized.

Show comment
Hide comment
@timdorr
Member

timdorr commented Nov 8, 2017

@jdalton

This comment has been minimized.

Show comment
Hide comment
@jdalton

jdalton Nov 8, 2017

Contributor

@timdorr

Ya'll haven't even used the webpack plugins that reduce its size.
We don't use webpack.

Ah, you all did at one point. No worries, despite the name, the plugin works for rollup too 😀

lodash/lodash#3483

Thanks for the PR!

@gaearon

I would feel more comfortable if we attempted to contribute this upstream to Lodash first before forking.

🤘 Teamwork makes the dream work! This is in time to land for Lodash v5 (Jan) which will be a 95% smaller ES module package (out of the box small w/o using plugins). The focus of Lodash v5 is simplifying things down, leveraging new language features where appropriate, and moving full steam ahead with ESM (since all modern evergreen browser will support it) and we'll use @std/esm for Node.

Contributor

jdalton commented Nov 8, 2017

@timdorr

Ya'll haven't even used the webpack plugins that reduce its size.
We don't use webpack.

Ah, you all did at one point. No worries, despite the name, the plugin works for rollup too 😀

lodash/lodash#3483

Thanks for the PR!

@gaearon

I would feel more comfortable if we attempted to contribute this upstream to Lodash first before forking.

🤘 Teamwork makes the dream work! This is in time to land for Lodash v5 (Jan) which will be a 95% smaller ES module package (out of the box small w/o using plugins). The focus of Lodash v5 is simplifying things down, leveraging new language features where appropriate, and moving full steam ahead with ESM (since all modern evergreen browser will support it) and we'll use @std/esm for Node.

@timdorr

This comment has been minimized.

Show comment
Hide comment
@timdorr

timdorr Nov 9, 2017

Member

Cool, we've got that in there for whenever v5 can land. I'll revisit using it there, when we can get some nice perf and size benefits.

For now, I'd like to proceed with our own solution. It gets us these benefits today, meaning I can get a 4.0 beta out in the next day or two. Switching back is very easy (delete some files and change some imports), so it's not a blocker to adoption IMHO. If this proves to be error-prone, I will happily revert the change and leave things untouched. But I'd like to prove that out with betas and RCs in the real world, rather than just the limited set of edge cases my brain can dream up. We have some exceptionally creative users out there, so I'm sure they can find the breaking points 😄

Member

timdorr commented Nov 9, 2017

Cool, we've got that in there for whenever v5 can land. I'll revisit using it there, when we can get some nice perf and size benefits.

For now, I'd like to proceed with our own solution. It gets us these benefits today, meaning I can get a 4.0 beta out in the next day or two. Switching back is very easy (delete some files and change some imports), so it's not a blocker to adoption IMHO. If this proves to be error-prone, I will happily revert the change and leave things untouched. But I'd like to prove that out with betas and RCs in the real world, rather than just the limited set of edge cases my brain can dream up. We have some exceptionally creative users out there, so I'm sure they can find the breaking points 😄

@timdorr timdorr merged commit c34941b into next Nov 16, 2017

1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details

@timdorr timdorr deleted the nodash branch Nov 16, 2017

timdorr added a commit that referenced this pull request Nov 16, 2017

Optimize dispatch plain object check (#2599)
* Remove lodash.

This boosts perf by not exhaustively checking every action of it's object-ness. We also no longer need to bundle any of lodash, so this saves a good number of bytes too!

* More robust plain object checks.

@evilj0e evilj0e referenced this pull request Nov 30, 2017

Closed

BeerJS #5: Brittania #5

seantcoyote added a commit to seantcoyote/redux that referenced this pull request Jan 14, 2018

Optimize dispatch plain object check (reduxjs#2599)
* Remove lodash.

This boosts perf by not exhaustively checking every action of it's object-ness. We also no longer need to bundle any of lodash, so this saves a good number of bytes too!

* More robust plain object checks.

tomipaul added a commit to tomipaul/redux that referenced this pull request Apr 8, 2018

Optimize dispatch plain object check (reduxjs#2599)
* Remove lodash.

This boosts perf by not exhaustively checking every action of it's object-ness. We also no longer need to bundle any of lodash, so this saves a good number of bytes too!

* More robust plain object checks.

matthargett added a commit to matthargett/react-redux that referenced this pull request Apr 24, 2018

@Dabolus Dabolus referenced this pull request May 11, 2018

Closed

Update to Redux v4 #76

timdorr added a commit to reduxjs/react-redux that referenced this pull request May 31, 2018

Simplify object check and eliminate lodash depdency (#936)
* Simplify object check and eliminate lodash depdency, mirroring reduxjs/redux#2599 .

* Add missing files.

* Replace isPlainObject with unmodified version from Redux

* Also replace the spec with the unmodified version

@markerikson markerikson referenced this pull request Sep 4, 2018

Closed

Optimize isPlainObject #3120

josepot added a commit to josepot/react-redux-lean that referenced this pull request Sep 21, 2018

Simplify object check and eliminate lodash depdency (reduxjs#936)
* Simplify object check and eliminate lodash depdency, mirroring reduxjs/redux#2599 .

* Add missing files.

* Replace isPlainObject with unmodified version from Redux

* Also replace the spec with the unmodified version
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment