Import a package as an extension of another package with ES6 syntax

Viewed 80

In order to extend map projections in D3 it's suggested to require the packages like this:

const d3 = require("d3")
require("d3-geo-projection")(d3)

That way, you can use for example d3-geo-projection's geoAiry method from the parent package:

d3.geoAiry()

Using import I'm doing this:

import * as d3 from 'd3'
import * as d3geo from 'd3-geo-projection'

But then the methods are not unified:

d3.geoMercator()
d3geo.geoAiry()

I tried this, but it doesn't work:

import * as d3 from 'd3'
import * as d3geo from 'd3-geo-projection'
d3geo(d3)

So, in short, what is the equivalent of require("d3-geo-projection")(d3) in ES6 syntax?

1 Answers

Technically, you can use d3.assign() to copy all properties from one import into the other, loosely speaking.

import * as d3 from 'd3';
import * as d3geo from 'd3-geo-projection';

Object.assign(d3, d3geo);

This will make all your properties available under the d3 object which is what you asked for:

d3.geoMercator()
d3.geoAiry()
// ...

However, should you do it that way? In my opinion, you should refrain from aggregating both your imports into one object. That seems to be some pre-ES6 reflex many developers give in to because they where taught to do it that way to ensure encapsulation by summing code into objects. The notion of encapsulation in JS has slightly changed with the introduction of modules, though.

Mike Bostok himself has his own take on the matter which he described in his answers to a GitHub issue dealing with exactly the question you posted. He encouraged dropping the use of import * as d3 altogether in favor of importing only those parts of a module you are actually going to use. Personally, I second that recommendation as I think it is the way modules should be used in modern JS code for sake of clarity and brevity. The only exception I would be willing to accept for my own code was the use of a lot, say 20+, of the exported members from a single module, although that might also indicate some code-smell suggesting you should consider refactoring your own module breaking it down into smaller pieces.

For even more modularization I usually prefer the usage of the individual modules instead of the whole d3 bundle which looks like this:

import { select, selectAll } from "d3-selection";
import { min, max } from "d3-array";
import { geoAiry } from "d3-geo-projection";
// ...
Related