Closed Mustack closed 7 years ago
Thanks for the effort, but we have decided a long time ago that polyfill for this won't be bundled with stampit, especially since only the IE11 is affected by it. In the install section there is an explanation how to handle this.
Furthermore, stampit itself is slowly getting deprecated and replaced by modularized approach residing in repo https://github.com/stampit-org/stamp/tree/master/packages. Not that it would solve your problem in any way, but there is not much of the point to send PR to this one.
Hi @FredyC,
I agree that this can be fixed via a polyfill and this is likely a valid use case for application developers. However, using a polyfill is not a valid use case for library developers such as yourself and others.
As such any library developer wanting to use stampit or @stamp packages have to either pollute globals or pass along this problem up the dependency chain.
When such a simple solution exists (~20 lines of code) why restrict your audience to people who:
I think that even on library level it makes sense to include this ponyfill that simply checks if Object.assign
is available and if not, it would include it. I wouldn't consider that polluting globals as you are only adding functionality by spec, nothing that shouldn't be there. Or do it configurable and allow a user of your library decide if they want to use it or they have own solution in place.
We wanted stampit as small in size as possible, so even including 20 lines just for a single use case feels like unnecessary evil.
I also think these are valuable goals. They are valuable goals for my own libraries as well, but now if I want to use \@stamp\stampit I have to pass along that problem.
Or do it configurable and allow a user of your library decide if they want to use it or they have own solution in place.
Why not provide this configurability in \@stamp\stampit then? I.e. Allow users to provide their own assign function.
@jyboudreau Such configurability is not that easy on our level as we would need to create separate bundles that would include it. Sorry, but IE11 is not worth the effort :) If you really want it that way, you can try to create PR, but I doubt it would be useful.
Comparing goals of your library and stampit doesn't seem right. On one hand, you would want your library to be small (if I understood correctly?), but at the expense of increasing the size of its dependencies? Including the fact that size would be bigger for everyone even people who don't need it. I fail to find the logic in it :)
@FredyC Good points. We'll look at our options and might provide a PR for configuration.
Right now since we're bundling with WebPack and Babel I believe we are able to transform the global assign polyfill into a non-global one. Thanks for your help.
Without an internal Object.assign
reimplementation:
Estimating dist/stampit.umd.min.js: 5.16 KB, GZIP : 1.8 KB
With it:
Estimating dist/stampit.umd.min.js: 5.26 KB, GZIP : 1.84 KB
The implementation look like this:
export const assign = Object.assign || function assign(to) {
for (let s = 1; s < arguments.length; s += 1) {
const from = arguments[s];
for (const key in Object.keys(from)) {
to[key] = from[key];
}
}
return to;
};
I know it's unsafe, but works for the internal object merging.
I would rather release stampit v3 with this thing, but we should clearly state that "IE11 unit tests where never run, we do not have an ability to run stampit tests in IE11, use on YOUR OWN RISK...".
(Also cross posted to #319.)
Something only I know (sorry @FredyC I should have told you, my bad) is that the compose()
standard does not require a super robust Object.assign
implementation. So, the little internal "polyfil" from above works just fine under any corner case conditions.
This PR is fine but introduces a dependency which, as @FredyC pointed, is something we strongly advocate against.
So, I put up the new PR #321 which adds the internal "polyfil" from above.
UPD:
@Mustack @jyboudreau You are not the first but third or fourth people who came across the polyfiling issue. So, I believe we should listen to the community and have the assign
function built-in.
I disagree with the conclusion of this thread, and the logic behind it.
Object.assign is not a function
errors, and call it a day.Sorry @ericelliott but I have to disagree too few points you made.
1)
because this issue exists in every library
This is untrue. Huge exaggeration. Not in every, but in some.
2)
significantly bloat every download bundle
In our case, as you have read above, it's 40-100 bytes. I find these bytes quite far from significantly. Thus, again, your statement is untrue for stampit.
3)
Polyfills can be completely automated
In my experience in 90% cases this is simply impossible due to project specifics. In fact, you are suggesting their widget to depend on a third party service. That additional request will slow down the app because JS won't start executing until things are polyfiled.
4) The core misconception is the word "polyfil" here. Strictly speaking stampit does not need polyfiling. It needs a very simple object merging function, not the fully fledged Object.assign
.
The most important here, @ericelliott , is that you are currently pushing toward stampit being a bad citizen. Why I think so?
Because IIRC there were at least 4 different people asking for that feature. This is a very high demand as for stampit-org. Trust me. I follow all of them.
Take into account that IE11 End Of Support is in 2025!
Fine. It's small. Do it.
FYI, mainstream support for IE11 ends on October 13, 2020. After that it goes into "extended support" and will only receive patches for critical vulnerabilities.
Fun bit of trivia: An earlier version of Stampit included a ponyfill for Object.assign() and we removed it because the community requested its removal.
You just can't win this game. ;)
@koresar You have some good points too, but I am not convinced that we should include something that has native support in many other environments. Doing this means that you will never be able to use any optimizations coming from native implementations.
Why it's a problem to do what I outlined above? Just have a separate bundle that would include dependencies and be exposed as stampit/compat
. People can easily alias that in Webpack in case of need and it won't influence others.
I love your idea Daniel. I welcome you to implement that. It would be awesome! We could ditch my pr #321
On 29 Aug. 2017 18:53, "Daniel K." notifications@github.com wrote:
@koresar https://github.com/koresar You have some good points too, but I am not convinced that we should include something that has native support in many other environments. Doing this means that you will never be able to use any optimizations coming from native implementations.
Why it's a problem to do what I outlined above? Just have a separate bundle that would include dependencies and be exposed as stampit/compat. People can easily alias that in Webpack in case of need and it won't influence others.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/stampit-org/stampit/pull/320#issuecomment-325599399, or mute the thread https://github.com/notifications/unsubscribe-auth/ABjCLw_52e22sGZ8_wdP1N5crt0A_-Omks5sc9GMgaJpZM4PEsgB .
Thanks to all for your consideration on this issue. I can tell you that after further troubleshooting, I found another dependency of my lib used native promises. This meant I needed a more scalable solution than opening PRs in each project. I ended up using babel transform runtime to solve this. I've also been able to remove the ponyfills that I was using in my own code.
If Stampit were the only dependency, using a "compat" version of stampit would probably be the most simple solution and I think I would have used that. I'm just sharing my experience for your consideration.
Thank you for the work you guys are doing on this project. It helps a lot.
@koresar I don't want to make any promises right now, I have enough stuff on my plate right now :)
@Mustack transform runtime can bloat the code quite a lot if not treated carefully. If you are using it for a lib transpilation a lot of code can be duplicated across various dependencies. It's probably not a solution I would go for.
The best solution I know for this problem is a polyfill CDN service. Advantages include:
No other solution can check all these boxes because other solutions require you to bundle the polyfills with your application code. Just to reiterate: That's a bad idea, and using polyfills/ponyfills in library code is littering.
@ericelliott I agree with you ... when you are developing an app. If you are lib author, then you can either include ponyfill by yourself or document that people need to use mentioned service. It's not exactly win-win scenario.
@FredyC That's not how libraries work. Libraries are multipliers. They have a multiplying impact on everything they touch. If you add a line of code, that's a line of code for EVERY APP using your library. You also have to consider that there are other library authors facing the same choices.
If you are a library author, it's your responsibility to consider how your decisions scale if all the other library authors are faced with the same choices (because they often are). So let's take a closer look at how this scales in practice.
Imagine the case where every library using ES5+ features (read: most modern JS libraries) decides to use polyfills or ponyfills rather than assume that the feature exists in the app. I'm looking at a small app right now (started a few months ago). There are 695 dependencies in node_modules
. Imagine for a moment that 25% decide to implement 20 lines of ponyfill. Now there are 3,500 lines of code that don't need to be there -- in a tiny app where the total LOC for the app source code itself is barely more than 10k lines. We've added 30% to our bundle size because some library authors thought, "this is only 20 lines, I really should do this here".
(695 * .25) * 20 = 3475 WASTED LOC
Now multiply that impact by the 10,000 apps using your code: You've unleashed 200,000 lines of wasted code on the world.
Now imagine you're a large enterprise. You're building a flagship product. Your app has over 1 million lines of code. You have 15k dependencies. Your biggest problems are bundle processing and load times. You've worked very hard to carefully split your entire app into 200k bundles for fast loading and chunking. You decide to dig and discover that 25% of your library module authors thought, "it's only 20 lines, let's just include this harmless ponyfill":
(15000 * .25) * 20 = 75,000 WASTED LOC
Your litter is just one more plastic jug on the side of the highway, but if everybody thinks that way, pretty soon there will be garbage draping the sides of the highway as far as the eye can see.
This is what I mean when I talk about being a responsible citizen as a library author.
Imagine that for every star, there are 100 apps using your code. Imagine that our ponyfill is only 10 lines. Stampit has over 2,500 stars:
(2552 * 100) * 10 = 2,552,000 WASTED LOC
Starting to get the big picture?
This impact is the reason that library CDNs exist. It's the reason why polyfill CDNs exist.
If you want to just create a library that works, sure, polyfill the thing and forget about it.
If you want to be viewed as a good citizen by enterprise scale companies that really do have to worry about the impact of scale, and if you want to do your part to reduce wasted bandwidth and improve connection speeds for all the users of all the apps using your libraries, these are the facts you need to consider.
Sounds like your next article, Eric. Good stuff.
Conclusion from Eric's comment: JavaScript needs a much better standard library.
I'm going to merge the PR #321 and publish v3.1.4 if there are no hard objectives in 24 hours.
thanks everyone for a very constructive discussion.
PS: yeah, @ericelliott , your comment sounds like great blog post!
Great write up @ericelliott. I agree with others about this making a good blog post. I always like your articles.
With that said, I'm still only partially convinced.
In my case i'm developing a WebRTC library. WebRTC is still very much a moving thing. I can't exactly develop this library to the standard and then tell my users to fill in the gaps, I would have no users. A big part of any WebRTC library's responsibility at this point is to remove the difficulty of filling the gap from the user.
Since we take so much care to fill these WebRTC gaps for each browser it's then easy to extend that mentality to smaller things like Object.assign that have known and easy polyfills.
In other words, if we're going to advertise to our users that our library supports Chrome, Firefox, IE11 and Safari as a selling point then we'd better make sure it does work in all those browsers. It's already difficult enough to use WebRTC across different browsers without us making it slightly more difficult for our users.
Some parallels could be drawn to other libraries. Like JQuery, which I don't think would have been very popular if it just implemented everything to the standard at the time.
In the end I don't think being a good web citizen is as black and white as you paint it. There will always be some compromise between idealism and pragmatism.
@jyboudreau You make a great counterpoint to my argument, but WebRTC is a special case because there are few implementations, and the specs are in flux.
Something as well established as Object.assign()
is a completely different matter -- the specs are not in flux, and there's a standards-compliant implementation in every modern browser.
If you want to polyfill stuff in your library that's already filling in a lot of browser gaps, that's fine, but if every library using Object.assign
decided to polyfill it, that would add significant wasted space and bandwidth to virtually every JS app everywhere.
In other words, it's important to look at your particular use-case, and we're not letting users do that for themselves if we include a ponyfill for everybody by default.
Stampit v3.2.0 released. https://github.com/stampit-org/stampit/releases/tag/v3.2.0
TL;DR: We support all ES5-compatible environments now: IE11, node.js 0.*, IoT devices like puck.js, etc.
Last thought about the 100 bytes. :)
How much bytes (memory and CPU resources) is a HTTP request usually?
If 10,000 apps is using the library:
10000 * 5100 = 51,000,000 B
waste of traffic.10000 * 100 = 10,000 B
waste of traffic.Scientific?
¯\_(ツ)_/¯
Fixes https://github.com/stampit-org/stampit/issues/319