D3: Browserify/CommonJS Support

Created on 11 Aug 2016  Â·  4Comments  Â·  Source: d3/d3

What is the current situation regarding browserify/commonJS support? I know this was mentioned in several issues, including #2220 however I'm unsure as to whether this has been, or is going to be, implemented. Please excuse my current lack of in-depth knowledge on JS ES6 modularisation etc.

I've attempted to import D3 via browserify, however I get an error (cannot read property ordinal of undefined) which I assume is related to d3 not binding to the window globally.

NOTE: I'm using nvd3 and angular-nvd3 via browserify successfully.

Most helpful comment

It sounds like you’re trying to access d3.scale.ordinal and the error is that d3.scale doesn’t exist anymore in v4; it was renamed to d3.scaleOrdinal as part of the great namespace flattening described in the release notes.

But to answer the broader question, per the README, the released bundle supports AMD, CommonJS and vanilla environments. So, one option is to download the d3.zip attached to the latest release and then require("./d3") to load this released bundle (d3.js) directly.

More commonly, I’d expect you to use npm install d3 and then require("d3") to load D3 from node_modules using the entry point defined in the package.json. Due to the fragmented nature of modern JavaScript development, there are several viable entry points that could be used by browserify:

  • The main entry point is d3.node.js, and is intended for a CommonJS/Node environment. It is simply a pass-through to require the individual D3 modules. The main difference between this and the browser entry point is that it guarantees that the symbols resolve to the same references, rather than inlined copies, if you also require the individual modules (e.g., d3-shape) directly. (In the case of d3-request, it also enables a polyfill for XMLHttpRequest which isn’t available in Node.)
  • The browser entry point is d3.js; this is the same as the released UMD bundle hosted on d3js.org and in the d3.zip release attachment. This bundle has the dependent D3 modules inlined, rather than using pass-through requires, and is intended for a browser environment so you can load everything with a single script tag. I believe this is also the entry point that browserify will chose by default, per browser-resolve.
  • The module (formerly jsnext:main) entry point is index.js, and is intended for an ES2015 environments. You’ll want to use this if you are using ES2015, for example with babelify, webpack or Rollup.

On the last point, note that D3 modules do not have default exports, so you’ll want to import everything as a namespace if you want everything:

import * as d3 from "d3";

All 4 comments

It sounds like you’re trying to access d3.scale.ordinal and the error is that d3.scale doesn’t exist anymore in v4; it was renamed to d3.scaleOrdinal as part of the great namespace flattening described in the release notes.

But to answer the broader question, per the README, the released bundle supports AMD, CommonJS and vanilla environments. So, one option is to download the d3.zip attached to the latest release and then require("./d3") to load this released bundle (d3.js) directly.

More commonly, I’d expect you to use npm install d3 and then require("d3") to load D3 from node_modules using the entry point defined in the package.json. Due to the fragmented nature of modern JavaScript development, there are several viable entry points that could be used by browserify:

  • The main entry point is d3.node.js, and is intended for a CommonJS/Node environment. It is simply a pass-through to require the individual D3 modules. The main difference between this and the browser entry point is that it guarantees that the symbols resolve to the same references, rather than inlined copies, if you also require the individual modules (e.g., d3-shape) directly. (In the case of d3-request, it also enables a polyfill for XMLHttpRequest which isn’t available in Node.)
  • The browser entry point is d3.js; this is the same as the released UMD bundle hosted on d3js.org and in the d3.zip release attachment. This bundle has the dependent D3 modules inlined, rather than using pass-through requires, and is intended for a browser environment so you can load everything with a single script tag. I believe this is also the entry point that browserify will chose by default, per browser-resolve.
  • The module (formerly jsnext:main) entry point is index.js, and is intended for an ES2015 environments. You’ll want to use this if you are using ES2015, for example with babelify, webpack or Rollup.

On the last point, note that D3 modules do not have default exports, so you’ll want to import everything as a namespace if you want everything:

import * as d3 from "d3";

@mbostock thanks for such a detailed response. Very helpful.

@mbostock , why in the package.json, there is no "browser" entry point? I use webpack to bundle app. I found transition() is not defined, and i try to include whole d3.min.js but no way to tell webpack how to use. I manually change jsdelivr to browser, it works fine. I do not know why we have no 'browser' key in the package.json file?
"main": "dist/d3.node.js", "unpkg": "dist/d3.min.js", "browser": "dist/d3.min.js", "module": "index",

@kidsit The browser entry isn’t standardized and means different things to different tools.

D3 previously supplied a browser entry for use by unpkg to determine which file it served by default; from unpkg’s perspective, the browser entry meant “intended to be consumed by a browser directly”, such as a UMD. However the meaning of the browser entry from Browserify’s perspective was a CommonJS module intended to be transformed by Browserify into a bundle to be consumed by browsers. See https://github.com/unpkg/unpkg/issues/63 for context.

I’m not sure how Webpack interprets the browser entry or what sort of file it expects to consume, but your best bet is pointing Webpack at the module entry point and consuming D3’s source as ES modules, which should be the default behavior of resolve.mainFields, since D3 provides a module entry point. Having Webpack consume the Rollup-generated UMD is not recommended.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sachi-d picture sachi-d  Â·  3Comments

ClashTheBunny picture ClashTheBunny  Â·  4Comments

ramtob picture ramtob  Â·  3Comments

doraeimo picture doraeimo  Â·  3Comments

vicapow picture vicapow  Â·  4Comments