Closed omgovich closed 3 years ago
Hello once again!
For me, if I'm understanding you correctly, a non-treeshakeable library is a non-starter. I've copied functions from tinycolor2
and I likely will do again because I refuse to install that bloatware.
Because nobody likes them.
I refuse to use anything that isn't, personally. If it's not treeshakable, it's a net-negative to any application I use. I'm better off manually copying functions 100% of the time.
Those other libraries didn't fail to pick up because they weren't treeshakeable.
You can provide chainable functions that are tree-shakeable and offer that API. It shouldn't be hard (theoretically)
The thing I noticed when I've been replacing react-color
with react-colorful
is that most of the developers don't want to think about input formats at all. They love tools that accept any input.
I also want to provide a universal value parser as popular libraries do.
But a universal parser will pull in about 70% of all library sources (all color model parsers and many conversion algorithms). That means that splitting the library into separate methods (to make it tree-shakeable) won't save many kilobytes, but makes DX way worse.
I believe that we can create a library that will cost 3-4 KB gzip. That's not much. I mean it doesn't feel like tree-shaking is needed for such a small library. I would prefer to provide better and familiar DX than trying to win less than 1 KB.
I would prefer to create a tree-shakeable solution, but I don't believe that somebody will use the library if they have to write code like that:
import { flow, parseAnyColor, saturate, toHsla } from 'colord' // ~2,5–3 KB
const processColor = flow(parseAnyColor, [saturate, 10], toHsla);
processColor('#F00')
instead of
import colord from 'colord' // 4 KB
colord('#F00').saturate(10).toHsla()
So the idea I have is to be similar to the popular libraries but be lighter and faster: optimize everything we can optimize.
Maybe I'm not right, but it just feels like a tree-shakeable version won't work. I mean it won't be popular because it's too complicated for most of the developers.
Combined way. We could go with the dayjs's approach:
// default behavior
import { colord } from 'colord' // 2KB
colord('red') // can't parse
// extend
import { colord, extend } from 'colord' // 2 KB + ~0,2KB
import { colorNamesPlugin } from '@colord/names' // 1,5 KB
extend(colorNamesPlugin)
colord('red') // ok
I mean if that's what you're aiming for then that's what you're aiming for. I certainly have no place to say anything in that regard.
But for my use, and use in my workplace, I've turned down libraries a lot smaller than 3-4kb if I thought it could be done better.
Actually, you've got me thinking about making the library extendable (see example above). It might make the library unique in terms of DX and size. Thanks!
import { colord, extend } from 'colord'
import { namesPlugin } from 'colord-names'
import { cmykPlugin } from 'colord-cmyk'
extend(namesPlugin, cmykPlugin)
colord('red').toCmyk()
Would that be an option to make the library semi-tree shakable? I mean, having just one method to parse all the color models, but also provide a set of methods that can be used in a composable rather than a chainable fashion:
import { parse, grayscale, saturate } from "colord"
saturate(grayscale(parse("red")))
// additionally
import { parseRgba } from "colord"
parseRgba("...")
But in that case we might need to come up with some smart indermediate object format.
What if a developer needs to parse any color except the color name? I think it's a common case.
parseHexOrRgbOrHslOrHsv(HEX|RGB|HSL) // 1 KB
parse(NAME|HEX|RGB|HSL) // 2,5 KB
Most of the projects I've seen don't know which color they receive but that's probably not a color name. That means that they need to run:
const color = parseHex(something) || parseRgb(something) || // ...
saturate(grayscale(color))
It's now an option. I would rather have one method that can't be extendable this way:
import colord from 'colord' // default parsers and methods
colord(HEX|RGB|HSL).toRgba()
// +
import 'colord-names' // extends colord's parsers, public methods and types
colord(NAME|HEX|RGB|HSL).toName()
I like how dayjs
works. It's chainable (which is super clear and comfortable to use) but provides plugins to extend functionality. Yeah, it's not 100% tree-shakeable, but still. It feels like DX is more important here than 300 extra bytes
It's been a long time, @molefrog @rschristian!
I decided to use our experience from
react-colorful
to create a new color conversion and manipulation tool. It's calledcolord
(🎨Color + 👑Lord).Actually, the color tool market is quite crowded already, but several packages have most of the market: https://www.npmjs.com/package/color-convert (37M downloads weekly) — 13 KB, has 1 dependency https://www.npmjs.com/package/color (11M downloads weekly) — 22.4 KB, has 2 dependencies https://www.npmjs.com/package/tinycolor2 (3M downloads weekly) — 14,4 KB
The idea is to create a tool that will support most of their features but will be better, lighter, faster, and TS-oriented.
This PR is the first concept that I would like to share with you to hear your thoughts.
The API is going to be similar to tinycolor2's one and the library won't be tree-shakeable (like all popular color conversion tools).
Tinycolor2 is not the most popular color tool, but I like their API. It's pretty simple to understand.
Why I'm not going to create a tree-shakeable library? Because nobody likes them. Example: I know 2 tree-shakeable color conversion tools: https://www.npmjs.com/package/color-fns https://www.npmjs.com/package/@swiftcarrot/color-fns Just 2k downloads weekly just because nobody wants to dig into color models and do extra work. Only geeks like me can use libraries of this kind =)
So I think our way is to copy the API of the popular libraries (it means to be not tree-shakeable), but make the library faster/lighter, and provide better DX.
Current bundle size: 3KB min, 1.14 KB gzip.
Any feedback is welcome ❤️