mxmul / closure-loader

Webpack loader for Google Closure modules ✨
MIT License
29 stars 22 forks source link

global namespaces being polluted by deep-extend #31

Closed mxmul closed 6 years ago

mxmul commented 6 years ago

I'm seeing an issue where namespaces that are exposed as globals (e.g. via goog.exportSymbol) can get polluted (new keys are added to the global, or existing keys replaced with empty object) when imported by another Closure module. Example:

app.js:

goog.require('some.namespace.foo');
goog.require('some.namespace.bar');

console.log([
  some.namespace.foo,
  some.namespace.bar,
  window.some.namespace.foo,
  window.some.namespace.bar,
]);

foo.js

goog.provide('some.namespace');
goog.provide('some.namespace.foo');

some.namespace = some.namespace || {};

some.namespace.foo = 1;

goog.exportSymbol('some.namespace.foo', some.namespace.foo);

bar.js

goog.require('some.namespace');
goog.require('some.namespace.foo');
goog.provide('some.namespace.bar');

some.namespace.bar = 2

I would expect the output of app.js to be [1, 2, 1, undefined], but it is actually [1, 2, {}, 2]. I think that the root of the problem is that the module prefix generated by closure-loader uses deep-extend without an empty object as the first argument – so requiring any namespace that's available as a global may mutate it.