d3 / d3-shape

Graphical primitives for visualization, such as lines and areas.
https://d3js.org/d3-shape
ISC License
2.47k stars 305 forks source link

Why do you collect code in a single bundle? #121

Closed retyui closed 6 years ago

retyui commented 6 years ago

Is your feature request related to a problem? Please describe. I try reduce my bundels size. In my project I use some imports:

import { area } from 'd3-shape';

I would like to have the opportunity to do so:

import area from 'd3-shape/lib/area';

Describe the solution you'd like Why do you collect code in a single js bundle? Use flatten struct! Like as: lodash-es, date-fns, react-router, ramda, recompose

mbostock commented 6 years ago

The D3 modules include UMD bundles for convenient consumption in browsers either as vanilla script tags or via require (AMD).

If you are in an environment that supports ES modules, you shouldn’t be using the UMD bundle. You should configure your environment (such as your bundler) to consume the module entry point (index.js) rather than the main entry point.

If you use a tree-shaking bundler such as Rollup or Webpack, the bundler should automatically prune unused code, so you don’t need to import from the source files directly.

In general, I don’t provide support for people’s bundlers and environments, since they vary so widely and I’m not familiar with all of them. So if you have further questions, please consider using Stack Overflow rather than posting an issue here. Thank you!

retyui commented 6 years ago

If a tree-shaking worked, then why did these plugins appear: npm lodash-webpack-plugin lodash-webpack-plugin npm babel-plugin-lodash babel-plugin-lodash npm babel-plugin-transform-imports babel-plugin-transform-imports npm babel-plugin-date-fns babel-plugin-date-fns I can help you add the ES version to the build process!

retyui commented 6 years ago

1) Direct import

import area from 'd3-shape/src/area';
console.log(area());

Result:

Version: webpack 4.8.3
Time: 654ms
Built at: 2018-05-24 23:03:51
  Asset      Size  Chunks             Chunk Names
main.js  4.96 KiB       0  [emitted]  main

2) Indirect import

import { area } from 'd3-shape';
console.log(area());

Result:

Version: webpack 4.8.3
Time: 502ms
Built at: 2018-05-24 23:06:06
  Asset      Size  Chunks             Chunk Names
main.js  18.7 KiB       0  [emitted]  main

4.96 KiB VS 18.7 KiB The difference is 4 times greater!!!

retyui commented 6 years ago

@mbostock I hope you see a clear problem

mbostock commented 6 years ago

Please use Stack Overflow tag d3.js to ask for help. Stack Overflow provides a better collaborative forum: thousands of D3-related questions have been asked there, and some answers may be relevant to you.

When asking for help, please include a link to demonstrate the issue, preferably as an Observable notebook. It is often impossible to debug from code snippets alone. Isolate the issue and reduce your code as much as possible before asking for help. The less code you post, the easier it is for someone to debug, and the more likely you are to get a helpful response.

If you have a question about D3’s behavior and want to discuss it with other users, also consider the d3-js Google Group or joining the d3-js Slack.

Thank you! 🤗

ffflabs commented 6 years ago

@mbostock I gave it a try and he's right. Generating an es6 module with rollup importing {area} from index

import {area} from './index.js';
export default area;

results in a 15kb module, whereas

import area from './src/area.js';
export default area;

creates e 9kb mofule

the former brings along the definitions for MonotoneX and MonotoneY which are not used. I can't see why. Perthaps rollup has a bug when determining tree shaking?

retyui commented 6 years ago

@mbostock @amenadiel A good idea is to use this plugin annotate-pure-calls This helps with 'tree-shaking' curried entry point. Works similar to sideEffects field in pkg.json, only sideEffects targets webpack@4+ and #PURE comments target uglifyJS

ffflabs commented 6 years ago

I only get those #PURE comments when I do (for example) import * as d3 from 'd3-selection. Which also freezes the object.

BTW, doing that also exports event as a getter. For example, using

import * as d3 from 'd3-selection';
export default d3;

results in a module that ends with:

var d3 = /*#__PURE__*/Object.freeze({
create: create,
creator: creator,
local: local,
matcher: matcher$1,
mouse: mouse,
namespace: namespace,
namespaces: namespaces,
clientPoint: point,
select: select,
selectAll: selectAll,
selection: selection,
selector: selector,
selectorAll: selectorAll,
style: styleValue,
touch: touch,
touches: touches,
window: defaultView,
get event () { return event; },
customEvent: customEvent
});

export default d3;

I'm missing something here :slightly_smiling_face:

BTW @mbostock I see no harm in building an es6 module for d3-shape into the dist folder that exported:

export { arc,
 area,
 line,
 pie,
 areaRadial,
 areaRadial as radialArea,
 lineRadial$1 as lineRadial,
 lineRadial$1 as radialLine,
 pointRadial,
 linkHorizontal,
 linkVertical,
 linkRadial,
 symbol,
 symbols,
 circle as symbolCircle,
 cross as symbolCross,
 diamond as symbolDiamond,
 square as symbolSquare,
 star as symbolStar,
 triangle as symbolTriangle,
 wye as symbolWye,
 basisClosed as curveBasisClosed,
 basisOpen as curveBasisOpen,
 basis as curveBasis,
 bundle as curveBundle,
 cardinalClosed as curveCardinalClosed,
 cardinalOpen as curveCardinalOpen,
 cardinal as curveCardinal,
 catmullRomClosed as curveCatmullRomClosed,
 catmullRomOpen as curveCatmullRomOpen,
 catmullRom as curveCatmullRom,
 linearClosed as curveLinearClosed,
 curveLinear,
 monotoneX as curveMonotoneX,
 monotoneY as curveMonotoneY,
 natural as curveNatural,
 step as curveStep,
 stepAfter as curveStepAfter,
 stepBefore as curveStepBefore,
 stack,
 expand as stackOffsetExpand,
 diverging as stackOffsetDiverging,
 none as stackOffsetNone,
 silhouette as stackOffsetSilhouette,
 wiggle as stackOffsetWiggle,
 ascending as stackOrderAscending,
 descending$1 as stackOrderDescending,
 insideOut as stackOrderInsideOut,
 none$1 as stackOrderNone,
 reverse as stackOrderReverse 
};

Now, you could achieve the same picking imports from d3-shape/index.js BUT, if we try to do the same importing from the d3/index.js module, it isn't trivial at all, since you don't really know where do each export come from. So, for the main d3 package, it would be nice to have an es6 module in dist listing every export as

export { version,
 bisectRight as bisect,
 bisectRight,
 bisectLeft,
 ascending,
 bisector,
 cross,
 descending,
 deviation,
 extent,
 histogram,
 freedmanDiaconis as thresholdFreedmanDiaconis,
 scott as thresholdScott,
 thresholdSturges,
 max,
 mean,
 median,
 merge,
 min,
 pairs,
 permute,
 threshold as quantile,
 sequence as range,
 scan,
 shuffle,
 sum,
 ticks,
 tickIncrement,
 tickStep,
 transpose,
 variance,
 zip,
 axisTop,
 axisRight,
 axisBottom,
 axisLeft,
 brush,
 brushX,
 brushY,
 brushSelection,
 chord,
 ribbon,
 ....
  now,
 timer,
 timerFlush,
 timeout$1 as timeout,
 interval$1 as interval,
 transition,
 active,
 interrupt,
 voronoi,
 zoom,
 transform$1 as zoomTransform,
 identity$8 as zoomIdentity 
};

because it would make so much easier to import just needed methods without digging into d3 componets to find out where do each of them come from.

However, this is just a loosely related opinion regarding this issue in particular, so you might as well disregard it.