If you use a module system, whether it is AMD, CommonJS, ESM or browser globals, you need to stick to it. In other words, every AMD module that uses Underscore should import it in the same way:
define(['underscore', ...], function(_, ...) {
// code that uses _
});
Older versions of Underscore used a lenient, hand-written UMD wrapper which let you get away with mixing browser globals and one other module system. In your case, that meant that as long as there was one module that imported Underscore the AMD way, all modules that were loaded later could assume its presence as a browser global. However, it is important to realize that code written in that way was never valid, even if it worked by accident. The very purpose of a module system is that you explicitly state your dependencies in a consistent way. Moreover, by assuming the presence of the browser global, you make one module implicitly dependent on another module that does the actual import.
Since version 1.10, Underscore is ESM-native and the UMD wrapper is generated by a bundling tool, which is stricter about enabling only one module system at a time. This explains why your (invalid!) setup no longer works. For the same reason, you can no longer use _.noConflict
in AMD or CommonJS environments. It never made sense to do such a thing in the first place, but some people mistakenly relied on it, so their code broke down at the 1.10 release.
Perhaps a comforting thought: even if multiple modules depend on Underscore, require.js will load it only once.