-
Notifications
You must be signed in to change notification settings - Fork 78
AMD? #39
Comments
Let's ping @jrburke to see if he might have any insight. I don't personally deal much with AMD, but I do distribute my libs with the UMD header which I believed was supposed to be require-compatible. |
The thing is: this project is a polyfill intended to strictly follow the spec and is not expected to be AMD compatible. That is the reason why I tried to find one that is interpreted as "this is spec only, ever, and nothing else", like "copy it to your environment, it doesn't matter where (just before the scripts you are using Promise), and it will just work without dependencies". Weird enough, every polyfill I found does the same with module loaders, so I may be missing something. Note: Moving the polyfill script tag to before the requireJS scripts is a way to workaround this problem, but doesn't actually solve it. It is not anyting related to AMD, AMD is working properly, THAT is the problem. |
AMD in the browser and CommonJS in node both have this annoying property that they sorta hijack and assume everything is loaded in that same way. So, if you're using an AMD loader in your app, you should be loading NPO with it, and if you're in node, you should be loading NPO as a standard module with I personally think both systems should have accommodations (and thus are not actually "behaving properly" though they're "behaving as designed") for people loading up polyfills that are intended to be standalone and patching the global env, but they don't, so my UMD is a compromise that makes it so you can still use NPO, but that's only if you go with the flow. |
I understand your idea behind using AMD in the browser and assuming ppl will load through it, but think this way:
Take a look in my specific problem here. I had I expected the code to work, but the build failed. Then I realized the polyfill was not actually a polyfill that mimics the native behavior, it was changing its behavior according to the presence, or not, of AMD. I hope you understand why I disagree with:
With the argument that this compromise is irrelevant when one is expected to override native behavior. The best backwards compatible solution in this case would be to not take out I am not saying jQuery is correct in their side, I am saying that in this specific case that solution is the correct one. |
By the way, here you express the intent of making it globally available even though AMD is in place, but as I mentioned it doesn't work. Maybe a named module is the proper way to go here, since this polyfill is intended to be concatenated with other scripts that are not AMD compatible (other polyfills). |
We are well outside of my expertise. I don't know or understand why AMD expects the things it expects. I use UMD because I don't want to care how you use the script. If I had no UMD, I'd get people (in fact, I did early on) complain that they want to load it with AMD. UMD is intended to be a don't-think-about-it wrapper. To the extent that AMD loaders are incompatible with that, I think that's their fault, not UMD's. I am not going to remove UMD, because there's too many people who rely on its behavior. But if there's some sort of specific tweak that doesn't break their use cases and enables yours, I'm happy to consider it. But I can't have a reasonable conversation about proper AMD design/behavior, because I've deliberately avoided that world. So an AMD expert should weigh in. |
If you're in a requireJS environment, can't you get what you need by doing a When you say
Can you point me at where you're doing that and tell me about what you're trying to do? (BTW I am not the AMD expert we are looking for.) |
@FagnerMartinsBrack the error in the original message sounds like the file is loaded by a hand-authored script tag in an HTML document instead of being loaded by the loader. If that is the case, when using an AMD loader, all AMD modules should be loaded by the loader. That, or load this shim in a script src tag before the tag for require.js. In that case, then you do not use npo as a dependency in a module, you can just use Promise as a global. Or, if doing a build, and the built file is loaded by the loader and this error occurs, the build tool does not know how to find the define() call in the npo.js file to give it a module name during a build. I just tried with the latest r.js, 2.1.15, and it does seem to find the define() call, so more info on what build tool was used and its version would probably help to pinpoint the problem. |
Yes, I can. But that is not how Promises natively works. I expect globals without changing my code.
Native environment (it works): <script src="require.main.js"></script>
<script src="require-2.1.15.js"></script>
<script src="polyfills.js"></script> require( [ "moduleA" ], function( moduleA ) {
Promise.resolve( moduleA() );
}); Environment with requireJS AND the native polyfill concatenated inside polyfills.js (it doesn't work) <script src="require.main.js"></script>
<script src="require-2.1.15.js"></script>
<script src="polyfills.js"></script> require( [ "moduleA" ], function( moduleA ) {
Promise.resolve( moduleA() );
});
Same code, but a polyfill with AMD support was concatenated inside Why was it concatenated and not used within an specific custom fancy build process? Because when I am handling polyfills I don't need to care about if I am using AMD or not. The native behavior doesn't care, so should the polyfill, otherwise it may work in some cases and it may not work in other cases. This is a huge abstraction leak between a polyfill and an AMD environment.
As I said several times, this is a polyfill, and the native implementation doesn't care if your environment is using AMD in the browser or not. So the reasoning for not including AMD would be that the native implementation doesn't use it either. The polyfill usage is usually to put a single script tag above the code that is using some feature, and then it should start using that feature.
In this case only @jrburke can tell if there is a way to enable AMD and also provide global access to the This is not a matter if AMD is working or not, is a matter of abstraction leaks, semantics and expectations of a polyfill. Maybe when ES6 module pattern lands it can be expected inside the polyfills code, but until then you are adding custom code to something that should just replace standard stuff. Hope I made the point clear. |
Yes I am aware of that, but in this specific case it doesn't make sense (see above). |
There are lots of people who use AMD and who expect there to be no such thing as a "real polyfill" in the sense of patching the global environment. They expect to be able to import a "Promise" module for any module that requires promises, and to call it whatever they want (not necessarily using the name I think the goal of keeping a polyfill entirely separate from the module system in use is admirable, but quite frankly it's unrealistic based on the expectations of the community. I use UMD because it's the easiest compromise for those who want to load NPO in AMD. Moreover, most people that I've run across in the AMD world do in fact load everything with AMD. So whether I like that or not, supporting that has paved the cowpath and made it easier for people. It's unfortunate that in your one circumstance and perspective, it's complicated it. But you're the first person to push back, and there are hundreds who've been happily using it in AMD and CommonJS environments now, for several months. |
Furthermore, stating personal opinion here, I think pretty much all the module systems have abjectly failed to recognize the validity of pure use-cases like the polyfill and the plugin. They variously just hand waive and/or push such handling complication details back on the user. I don't see this being fixed _at all_ in ES6 modules, unfortunately. |
Well, then I can't argue about that. The only thing I can hope is that people don't start creating every polyfill to be loaded using AMD, since the original feature may just be available as if you were not aware if your environment uses AMD or not.
I don't understand what you mean. |
By the way I don't know details of how ES6 modules is supposed to work, so I may be stating some wrong assumptions here. |
I go back to an earlier sentiment that I've echoed a few times. I think the shortcoming is that there is not, to my knowledge, a simple way for me to express a piece of code which will act either as a direct native-global-patching polyfill, OR as an AMD-loaded module. I believe this to be a shortcoming in the module mechanisms (AMD and CommonJS, namely) that they don't give me a better way of serving both the concerns you have (which I would naturally tend to agree with!) and the concerns of those who want "no globals at all" kind of programming, and want to import everything. If someone comes up with a compellingly-better UMD'ish type pattern which I can wrap around my code that simultaneously achieves both goals, I'm more than happy to adjust. I think the ball is in the court of the AMD and/or CommonJS experts to suggest if there's something I've missed, or if there's something they need to do better to accommodate these concerns. :) |
If the desire is to have a UMD wrapper that only chooses one registration path, AMD, CJS or global, this type of UMD works: https://github.com/umdjs/umd/blob/master/returnExportsGlobal.js It includes support for a dependency, but that could be removed in this case. The story is messier in ES6: if you actually want to export a value as a module, that requires new syntax (and a browser that supports that syntax), and you cannot use a plain script src tag to load it. In general, polyfills are in a tough spot in any module system -- they are trying to provide "global", implicitly assumed capabilities. That is in conflict with a module system which is about explicit dependencies with local handles. You can certainly design a workflow that loads all polyfills up front, and go with a polyfill style where the polyfills do not register with a module system and do not have dependencies amongst themselves. Then, polyfills are not referenced as explicit module dependencies, because the idea is that they just exist, and then a module loader can load them all up first before calling the main modular code. For an module loader like requirejs:
Where 'polyfills' is a defined module that just has dependencies on all the polyfills. Trouble is, as @getify points out, users of a module system generally like to use the module loader to load all the code, and generally like dependencies to be all explicit in module definitions. It can be a benefit for the polyfill too, or at least the portability of the modules that use them. If the modules depend on the specific use of a particular polyfill (because the standard moves to a different place or has behavior that was not specified), those modules can still be used later even once all browser have the target of the polyfill. The trouble for a polyfill provider is trying to bridge those multiple at once, and tradeoffs have to be made. From what I can tell, the tradeoffs for this project seem reasonable. |
Just to clarify, I use a modified UMD for polyfills which intentionally patches the global @jrburke I would love to understand why the UMD (with |
Not sure I followed that last question, if you have some code you are thinking about that would help me follow along better. |
He is probably refering to this example: #39 (comment) |
Hi, when using this polyfill with requireJS in PhantomJS environment I am getting:
The expected here is that
Promise
is available globally, just like the native behavior and no error occurs.Any reason for using AMD in a project that is suppose to act as a polyfill of standards?
The text was updated successfully, but these errors were encountered: