D3: Duplicate code in 4.0 build.

Created on 5 Jan 2016  Â·  3Comments  Â·  Source: d3/d3

These are private functions that were duplicated so as to avoid additional dependencies. Maybe they should be made an external dependency so that the default build is slightly smaller?

function number$2(x) {
  return +x;
}
function identity$3(x) {
  return x;
}
function constant$1(x) {
  return function constant() {
    return x;
  };
}
var pi$1 = Math.PI;
var tau$1 = 2 * pi$1;
var epsilon$1 = 1e-12;
var pi$2 = Math.PI;
var halfPi$1 = pi$2 / 2;
var tau$2 = 2 * pi$2;
var slice$4 = Array.prototype.slice;
function bind$2(curve, args) {
  if (args.length < 2) return curve;
  args = slice$4.call(args);
  args[0] = null;
  return function(context) {
    args[0] = context;
    return curve.apply(null, args);
  };
};
function ascending$2(a, b) {
  return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
var requoteRe$1 = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;

function requote$1(string) {
  return string.replace(requoteRe$1, "\\$&");
};

Most helpful comment

This issue pertains only to a small amount of duplicate code in the new D3 4.0 build, where I duplicated the code intentionally to avoid introducing dependencies between modules. The subsequent discussion seems to have evolved into a more general one about how to create custom builds in D3 4.0, so allow me to elaborate a bit, even though it doesn’t pertain directly to this issue.

Yes, D3 4.0 uses ES6 modules. And multiple NPM packages / git repositories.

You have a few options if you want to create a custom build from the ES6 modules. If you’re using a “smart” bundler that doesn’t pull-in unused code, namely Rollup, then the most convenient option is to create a top-level index file that imports from the top-level mbostock/d3 module, as you describe:

import {
  rgb,
  timer
} from "d3";

Equivalently, you can include the desired symbols from their corresponding D3 module:

import {
  rgb
} from "d3-color";

import {
  timer
} from "d3-timer";

This is exactly how the d3 package itself is built. (See index.js.)

Note that Rollup isn’t perfect at eliminating unused code because it is conservative about side-effects. It’s possible that the above approach will pull in a small amount of dead code (see rollup/rollup#305). I expect @Rich-Harris et al. will improve side-effect detection in the future.

A more surgical, but also more brittle (since the file structure is not considered part of the public API) approach is to reference the ES6 source files in each module directly. I haven’t tested this, but in theory:

import {rgb} from "d3-color/src/color";
import {timer} from "d3-timer/src/timer";

That should pull in only the necessary code, even if you’re using a less-smart bundler such as Webpack. Presumably you could use something like Babel to convert ES6 to CommonJS and then route that through Browserify, too, if you prefer.

You can also create a custom D3 build from each D3 package’s released AMD distribution. For example:

npm install d3-color d3-timer
cat node_modules/d3-color/build/d3-color.js node_modules/d3-timer/build/d3-timer.js > d3.js
uglifyjs -c -m -o d3.min.js -- d3.js

This is much more coarse than building from the ES6 modules, however, since you can only slice the code at the package level. Also, the resulting AMD bundle defines d3-color and d3-timer separately (d3_color and d3_timer globals in a vanilla environment), so you’d need to change downstream code accordingly, or combine those into a single d3 global.

All 3 comments

it's fine.

i'v thinking in v4, it should build an all in one version, but also d3 can be used as lodash-style:

in lodash index page, it said:

// In Node.js:

// load the modern build
var _ = require('lodash');
// or a method category
var array = require('lodash/array');
// or a method (great for smaller builds with browserify/webpack)
var chunk = require('lodash/array/chunk');

so d3 also can be used like this:

var array = require('d3/array');
var time = require('d3/timer');

If you bundle to a version with es6 modules then there is a solution for having an all in on build where only parts get required. This is hopefully future proof.

import { timer } from 'd3'

I have looked at the 4 branch (I am assuming that this is for the v4.0 release). I see a rollup configuration file, perhaps you have aready considered this as a possibility. What can I do do help make v4 a reality with es6 modules

This issue pertains only to a small amount of duplicate code in the new D3 4.0 build, where I duplicated the code intentionally to avoid introducing dependencies between modules. The subsequent discussion seems to have evolved into a more general one about how to create custom builds in D3 4.0, so allow me to elaborate a bit, even though it doesn’t pertain directly to this issue.

Yes, D3 4.0 uses ES6 modules. And multiple NPM packages / git repositories.

You have a few options if you want to create a custom build from the ES6 modules. If you’re using a “smart” bundler that doesn’t pull-in unused code, namely Rollup, then the most convenient option is to create a top-level index file that imports from the top-level mbostock/d3 module, as you describe:

import {
  rgb,
  timer
} from "d3";

Equivalently, you can include the desired symbols from their corresponding D3 module:

import {
  rgb
} from "d3-color";

import {
  timer
} from "d3-timer";

This is exactly how the d3 package itself is built. (See index.js.)

Note that Rollup isn’t perfect at eliminating unused code because it is conservative about side-effects. It’s possible that the above approach will pull in a small amount of dead code (see rollup/rollup#305). I expect @Rich-Harris et al. will improve side-effect detection in the future.

A more surgical, but also more brittle (since the file structure is not considered part of the public API) approach is to reference the ES6 source files in each module directly. I haven’t tested this, but in theory:

import {rgb} from "d3-color/src/color";
import {timer} from "d3-timer/src/timer";

That should pull in only the necessary code, even if you’re using a less-smart bundler such as Webpack. Presumably you could use something like Babel to convert ES6 to CommonJS and then route that through Browserify, too, if you prefer.

You can also create a custom D3 build from each D3 package’s released AMD distribution. For example:

npm install d3-color d3-timer
cat node_modules/d3-color/build/d3-color.js node_modules/d3-timer/build/d3-timer.js > d3.js
uglifyjs -c -m -o d3.min.js -- d3.js

This is much more coarse than building from the ES6 modules, however, since you can only slice the code at the package level. Also, the resulting AMD bundle defines d3-color and d3-timer separately (d3_color and d3_timer globals in a vanilla environment), so you’d need to change downstream code accordingly, or combine those into a single d3 global.

Was this page helpful?
0 / 5 - 0 ratings