-
Notifications
You must be signed in to change notification settings - Fork 422
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
UMD is not compatible with JavaScript modules #124
Comments
Hmm, help me understand. Why would you define with UMD when you're using an ES module? Only other ES modules can consume it, so what's the point? |
The intention is to be able to import a UMD module from a JavaScript module and have it export to the global object. For example, in a browser script module context: import './umd-foo.js'; // exports Foo via UMD to window Currently it is not possible to attempt importing UMD-wrapped scripts as they are guaranteed to error when detecting the global context. Many of these scripts would be importable as JavaScript modules with the correct detection. |
I have similar questions around why. It's a little unclear when UMD would be useful or needed here if you're primarily using ESMs. Edit: appears our comments just crossed each other :) Will review. |
Please see my response above. Mainly this helps with using "legacy" script modules that leverage UMD in conjunction with JavaScript modules. For example, I recently attempted to import the Firebase JS SDK (which is distributed as UMD modules) from a JavaScript module. It would have worked and correctly populated the global object with the necessary properties, except it performed incorrect global detection. It is important to import dependencies where you need them (instead of globally) to support correct analysis of the dependency graph in one's app. It is also useful to be able to import "legacy" UMD modules from JavaScript modules to facilitate a general ecosystem transition towards JavaScript modules. |
Something like the loader spec needs to be finished to allow this sort of interop. My hope with the loader spec is that it would allow you to then create a wrapping script over it that would allow you to configure it to not load these scripts in a But who knows how it will work. The loader spec seems to be stalled. In any case, I do not think it is advisable to load UMD scripts as type="module" scripts because of the particular environmental constraints around type="module" scripts. UMD scripts are not type="module" scripts, they are type="text/javascript" scripts. |
Thanks for the feedback @jrburke. UMD's export to global has historically served as an affordance for web browsers, for scenarios where no supported module system has been detected but export to globals is considered a reasonable fallback by the library author. In practice, many libraries distribute a build artifact wrapped in UMD with global fallback in support of loading in a browser context. I referenced the Firebase SDK above, but I have also encountered UMD wrappers around the distributable form of other libraries such as jQuery and Redux (and certainly many other examples exist). Notably, in the jQuery case the wrapper explicitly performs a test for the availability of a global reference ( Given that the change required to make UMD "just work" as script modules is potentially quite small, it seems like a compelling trade-off of correctness for utility in support of transitioning our ecosystem towards JavaScript modules.
I would not characterize this issue as advocating for interop. Instead, it should be read as requesting reasonable fallback for the browser JavaScript module case - very similar to the existing fallback that exports to global - but that supports the case where the wrapper is evaluated in strict mode. That having been stated, I don't otherwise understand why the loader spec is necessary to address the described issue.
Philosophically speaking, UMD is an adaptable and/or progressive wrapper that leverages the available module system (or falls back where possible). It seems fitting that the "universal" in UMD extend to being imported as JavaScript modules where it is feasible. |
I would like to emphasize one detail because I think the problem statement in the issue may have been ambiguous (my apologies if this is the case): The issue does ask that UMD gracefully fallback when loaded in a browser and evaluated as strict mode code (such as when imported as a JavaScript module). The issue does not ask UMD to export a JavaScript module (or otherwise interop with the native module system) when loaded as a JavaScript module. |
This is my interpretation of the current state of the loader spec as well. It appears parked.
Thanks for the clarification. One thing that might be useful for the discussion here is a patch demonstrating the proposed change you would like made. The OP noted that the issue when evaluating UMD in script is the global gets incorrectly detected - is the change just correct detection? |
Yes, great point. I am happy to create one.
Yes, the proposed change would be correct detection of the global object in a strict mode context. |
Loading a UMD script as type="module" means effectively adding a "use strict" to the top of the module. However, the module may not have been authored to strict mode rules. So while you may come up for a better detection for the global in this case, it does not mean that all UMD modules will run as expected. I definitely ran into this with an AMD module optimizer: combining a bunch of modules and naively prepending "use strict" at the top of the bundled script would break some of the concatenated modules in some cases. Unless the UMD module was explicitly authored with "use strict" at the top of the file, before the UMD wrapper, the forcing of strict mode is a change in expectations, a breaking of the contract the UMD script was assuming. I will leave it to the active maintainers in this repo to sort out any possible changes for this repo, and I will try not to post on this issue any more. Maybe a "UMD for strict mode" example makes sense. But just be forewarned that loading existing non-strict mode UMD modules as type="module" with "use strict" behavior can lead to errors, regardless of the globals detection change. |
Thanks @jrburke , this is a very important point. I completely agree that one cannot reasonably expect a module crafted without the deliberate intention of running in strict mode to support running in strict mode. On the other hand, many modules today will work out of the box (indeed many are already authored with explicit support for strict mode). |
Even though UMD wasn't designed to be loaded from modules, it seems to be awful close to being useful in that context, even if it's still just writing to globals. The main benefit is that, like Chris said, modules can load their UMD dependencies directly and not have to do something like document that the app include them in some side bundle, and then of course you get the module loader's deduping. |
Description
When using UMD in a script that is evaluated as a JavaScript module (tested in Chrome Canary and Safari stable), the reference to the global object (presumably
window
) is incorrectly detected.Test case
Please refer to this test case for a demonstration of the problem: http://jsbin.com/yuvulec/1/edit?html
Analysis
JavaScript modules are always evaluated as JavaScript strict mode code [1]. In strict mode, an
undefined
ornull
this
is no longer coerced to the global object [2].What I expected
The following output in the console:
What actually happened
The text was updated successfully, but these errors were encountered: