7
votes

TL;DR: The documented way to import d3 into es6 modules fails. What is the correct way to do this? My guess is the documentation assumes I use a workflow that resolves these problems

Details: The readme for d3 4.x says:

D3 is written using ES2015 modules. Create a custom bundle using Rollup, Webpack, or your preferred bundler. To import D3 into an ES2015 application, either import specific symbols from specific D3 modules:

import {scaleLinear} from "d3-scale";

Or import everything into a namespace (here, d3):

import * as d3 from "d3";

Yet when I yarn add d3 and use a es6 script tag, this fails to work:

<html>
<head>
  <title>D3</title>
</head>
<body>
  <script type="module">
    import * as d3 from "./node_modules/d3"
  </script>
</body>
</html>

Failed to load module script: The server responded with a non-JavaScript MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.

Replacing the import with:

  import * as d3 from "./node_modules/d3/index.js"

..gives this error:

Uncaught TypeError: Failed to resolve module specifier 'd3-array'

2

2 Answers

5
votes

es6 and es2015 modules will not work with d3 because d3 has chosen to use rollup instead. You are seeing this error because the module cannot be resolved as specified in the file "./node_modules/d3/index.js" which has lines like export {default as ascending} from "./src/ascending"; which are missing the real file name which ends with '.js'. So in other words all these entries are mis-configured to not support native modules in browsers or Nodejs.

you can either use rollup or make all the text substitutions yourself using a script or manually. I use a perl one-liner because I dislike rollup and the extra dependencies were breaking between node 8 and node 10. it is unbelievably strange that this is necessary but I also haven't been supporting a kitchen sink of module loaders.

import * as d3 from "./node_modules/d3-something/index.js"

which has content like export {default as something} from './src/thing'. because these files do not use the natively supported syntax with a full relative path (it's missing the actual file extension), it won't work without rollup or whatever making these corrections. multiple popular projects have made this same decision to require extra modules to work properly and forego native support.

see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import

8
votes

@jimmont is correct: importing the module form of d3 packages does not work without local building due to the "bare" imports. These can be resolved by the CDN's D3 uses, in particular unpkg.com. Here's the story.

It turns out d3 uses package.json to allow it to export two formats from a single source, npm itself. To do so, it uses the module: field.

The easiest way to access either all of d3, or a submodule/repo (there are 30 of them!) unpkg is ideal:

To import all of d3:

import * as d3 from 'https://unpkg.com/d3?module'

To import sub-modules:

import * as selection from 'https://unpkg.com/d3-selection?module'