mapbox/earcut

Exposing Earcut as a module

mourner opened this issue ยท 4 comments

@mourner now that you're here... are you planning on adding a "module" export to Earcut's package.json? ๐Ÿ˜‡

@mrdoob Yes! And very soon. Started a branch recently here: https://github.com/mapbox/earcut/tree/modernize

The main stumbling block for me is deciding on what API to choose. Options:

Option 1

earcut.flatten = flatten;
earcut.deviation = deviation;
export default earcut;

Pros:

  • Non-breaking.

Cons:

  • The functions can't be tree-shaken (although they're small).
  • It doesn't feel right to do this in ES (anti-pattern).

Option 2

export default earcut;
export flatten;
export deviation;

Pros:

  • Convenient and non-breaking for module consumers.

Cons:

  • UMD build will have earcut function exported as earcut.default, which is breaking and doesn't feel right.
  • Mixing default and non-default exports is an anti-pattern.

Option 3

export {earcut, flatten, deviation};

Pros:

  • Simple, adheres to best practices.

Cons:

  • Breaking for both module and UMD consumers.
  • For UMD users, earcut.earcut(...) isn't great.
  • For module consumers, deviation and flatten names aren't clear out of context (if you import them without namespacing).

Option 4

export {
    earcut as triangulate,
    flatten as flattenGeometry,
    deviation as validateTriangulation
};

Pros:

  • Straightforward and explicit naming.
  • Adheres to best practices.

Cons:

  • Fully breaking for all users.

Thoughts, suggestions?

Ref #102 (@Andarist sorry for not responding earlier!)

Option 1 and Option 2 are not equivalent - the second one would most likely be breaking.

UMD build will have earcut function exported as earcut.default, which is breaking and doesn't feel right.

Looks slightly weird, but actually is 100% compatible with ESM and thus can be considered more "right" than not ๐Ÿ˜‰

Mixing default and non-default exports is an anti-pattern.

Depends on who do you ask really - default is actually pretty much a named export, just with a special support at the syntax level. Personally I wouldn't say that it is an anti-pattern - often it IMHO makes sense to export core util as default and low-level (for power users) stuff as named exports

That being said - I don't have a strong opinion about which one is better in this particular case: 2, 3 or 4 (I would just really discourage you from using option 1). My advice is not to be afraid of breaking changes though, especially when they are so minor as exports shape change - you can just bump a major version and be done with it. Think about what you would have done right now - what API would you export - without looking back at what you have right now.

Hi @mourner, this issue is almost 2 years old. I am curious if there is any plan to move forward with a fix, or if there is an ESM based solution for this that is suitable for use in production?

I think I may have run into this with Vite? I'm a little lost in module options and don't have my head wrapped around this. But when you're using vite to build for production, it doesn't seem to play well with Earcut. You get a Module object with the earcut function on a .default property.

Here's what import earcut from 'earcut' gives you in a fresh Vite project (dev mode works as expected, this is only when building for prod):

image

Done in earcut v3. I went with option 2 (mixing default and named exports), so you would use earcut like this:

import earcut, {flatten, deviation} from 'earcut';