I'm trying to update a library to dynamically import d3.js
after the upgrade to v7, and this syntax handles the import:
import("d3").then((library) => {
var d3 = library;
console.log("d3:", d3);
})
.catch((err) => {
console.error(err);
});
The logged object is in this format (albeit much longer):
Whenever I try to simply extend by adding a property with d3.contextMenu = factory(d3);
, I get this TypeError
:
TypeError: Cannot add property contextMenu, object is not extensible
Doing a shallow clone like var d3 = {...library, contextMenu: factory(library)};
removes a lot of the module's context, e.x. the get
and set
methods are not copied at all.
So I tried to create a structured clone of the library before extending it with var d3 = structuredClone(library);
, but that gives a DOMExteption
:
DOMException: Failed to execute 'structuredClone' on 'Window': [object Module] could not be cloned.
When using the non-ESM syntax, this code covers all my bases and allows for extension of the module:
if (typeof module === "object" && module.exports) {
var d3 = require("d3");
module.exports = factory(d3);
} else if (typeof define === "function" && define.amd) {
try {
var d3 = require("d3");
} catch (e) {
d3 = root.d3;
}
d3.contextMenu = factory(d3);
define([], function () {
return d3.contextMenu;
});
} else if (root?.d3) {
root.d3.contextMenu = factory(root.d3);
}
But I need to add in ESM compatibility for the library, hence my code. What method can I use to extend the module with my function?
CodePudding user response:
As it is not possible to extend an inextensible object, you can either wrap the library or use it as the prototype of a new object. For example:
import('d3').then((library) => {
const d3 = Object.create(library);
d3.contextMenu = factory(library);
for (const prop in d3) console.log(prop);
})
.catch((err) => {
console.error(err);
});
To export:
module.exports = (async () => {
const library = await import('d3');
const d3 = Object.create(library);
d3.contextMenu = factory(library);
return d3;
})();
To then import into CommonJS module using require
:
(async () => {
const d3 = await require('./filename.js');
for (const prop in d3) console.log(prop);
})();