Evergreen: a React UI Framework built by Segment
evergreen.segment.com
evergreen.segment.com
https://at-ui.github.io/at-ui/
https://developer.microsoft.com/en-us/fabric
https://vmware.github.io/clarity/
http://appnexus.github.io/lucid/
https://ng-lightning.github.io/ng-lightning/
http://www.jetbrains.org/ring-ui/
https://www.lightningdesignsystem.com/
Some of them (atlaskit, MS fabric, Jetbrains, vmware etc) are geared towards building an integration withing those company's products. Whilst they can be used independently (without assets in Fabrics case, and other restrictions in the others), my take is the Evergreen (and ant, etc) are geared towards isolated products, similar to Bootstrap.
If you're building an addon for use in an Atlassian product, or an Office 365 product, these are a great way to stay consistent with the host application's look and feel.
And if you use it for something else you may not comply with the license.
I really like Blueprint JS but I think we'll end up building on top of Ant Design. It's a huge collection of work; they've also started to push Ant Pro which is higher-order components targeting building of admin apps (more opinionated, more than just a UI facade).
I like Blueprint a lot more than Ant, but Blueprint doesn't pretend to support responsive applications[1], which was somewhat important to us. Blueprint exposes a couple building blocks (like PopOver) which really help in building more custom functionality. It actually looks like Evergreen be closer to Blueprint in this regard so I might piss off all the devs and evaluate Evergreen.
[1]https://github.com/palantir/blueprint/wiki/Frequently-asked-...
I use Basscss' grid and flex helper classes to define how my I can create a 3-column responsive layout with something like:
<div class="clearfix">
<div class="col md-col-4">
<SomeBlueprintComponent />
</div>
<div class="col md-col-4">
<SomeBlueprintComponent />
</div>
<div class="col md-col-4">
<SomeBlueprintComponent />
</div>
</div>
There's also a couple of other helpers like `max-width-*` which ensure responsiveness as the screen grows larger. Things like adding the `Classes.FILL` (which causes a button/control to go full width of its container) are useful for making things seem more like mobile (where buttons often are full width of the device, minus padding)All in all, while it's a slight bummer than Blueprint isn't just responsive out of the box, I haven't really found that to be a deterrent to getting things done.
While BlueprintJS is more intuitive, I find that it lacks a lot of built-in components compared to Ant Design.
End of the day, until it's rewritten with modularity in mind it will always be a drag to properly implement it in React.
Or the expectation is that one has to make a new UI anyway every several years to keep up with the changing fashion, so rewrites are inevitable?
/s
Same with gmail which was in beta for years for some reason - probably because they wanted to avoid liability for lost data etc.
Also note that these frameworks lock you into design & feel of their choice. This might work for some use cases and for now, but when the requirements change you often end up fighting the framework. I don't have a solution to that though. :)
I'd argue this depends on your needs. If you're using one of these for your consumer-facing product, perhaps so. Otherwise, if your UI is not what you're selling or your product/team is big enough to end up creating one of these from scratch anyway, then no. In the latter case, that's probably why there's so many of these to begin with.
> Also note that these frameworks lock you into design & feel of their choice.
Some of these frameworks actually let you re-theme them. For example, Ant Design can mostly be re-themed.
There's a big fear that projects that become unmaintained suddenly stop working; this isn't correct.
Besides, all webapps are rebuilt in a 3-5 year cycle anyway so it really doesn't matter.
I know of at least one company with such a stack. Just like I know others with Web Forms, Stucts, SEAM, JSP, Zope and many other stacks in production.
Not everyone re-writes their webapps, specially in companies where software is a cost center and totally unrelated to their main business.
Sure, not everyone re-writes old apps. But enough companies do it to make it a decent professional specialty to cultivate. And it doesn't hurt knowing both the modern stacks and multiple generations of legacy stacks when working with large organizations. Sign me up.
And I thought places I worked at tended to be terrible :/
While true, it only applies if you don't want to upgrade your lower level dependencies, ever. And given that this is a React based framework, so it's not based directly on the web platform, if it's not maintained, you'll have to port the framework yourself.
Coversely, if it is maintained, you may be forced to keep up and upgrade whatever this is based on, or backport fixes if the project moves on to a newer incompatible version of the lower level dependency.
> Besides, all webapps are rebuilt in a 3-5 year cycle anyway so it really doesn't matter.
Eh? :D I still iterate on 13 or 9 year old codebases for my clients without re-building anything.
React was released in 2013, has only had minor breaking chanhes since then, and doesn't show any signs of disappearing anytime soon.
New version of repeat is interesting:
Nicoburns said that "performance question is not solved" - I think we can agree than svelte and lit are fast in general, that was the point I wanted to make that it is the implementation that matters here.
You named Web Components, I've been embracing them for a while, but if you tried to switch from Google's Polymer to LitElement it wouldn't go smooth as you could have imagined. Both Polymer and LitElement are based on Shadow Dom and WC features curated by Google, but are not 100% backward compatible. That is to say, Web Components have been divided from within the same tech. No need to mention the rival concepts of "everything HTML" of Polymer 2.0 and fixing it to be "all JS and webpack-ready" in 3.0, and consequential deprecation of Bower.
And here you mention some Svelte and Stencil which I've never heard of before. Why need them? We have webcomponents.org already.
Web components are a low-level primitive - they are clunky to use directly.
Polymer and LitElement - are libraries - you can author WC's with them. And yes they are different (I used both), but you don't really have to migrate from one to another.
Web components are not divided - Lit-element can work within vuejs or polymer or angular for example. VueJS authored WC's can work within lit-element or polymer.
https://custom-elements-everywhere.com/ - see this for more information about interoperability (sometimes it depends on templating syntax).
You asked about Svelte and Stencil - https://svelte.technology/, https://stenciljs.com/ - those compile your code into web components - different approach than polymer that is a suite of quite a few higher-level abstractions that you might not want to pay for (20kb of js).
Don't know what you mean by saying it has no relation; I've been using that site for searching components while developing my PWA based on Polymer. I can install components with yarn or npm just fine, using instructions and examples from there.
Also, I haven't seen a lot of companies saying "Well, Angular is working great for us, but React is hot and trendy so let's rewrite the current UI in it". Rather, I think UI framework switches happen for two reasons:
- They've accumulated so much technical debt with their existing solution that progress has slowed to a crawl, developer morale is really low, etc. A migration strategy can be found that doesn't have such an upfront cost, and will dramatically improve velocity as features are converted.
- The design is totally changing, or the product is being rethought, and so it's not an invisible code rewrite, it's essentially building a new product.
I think in both of these cases, it's a good use of developer time.
I agree, and this is why I use React (or rather Preact) for both apps and interactive elements on the page. The big caveat is that in practice it's really easy to end up with a React project that is much more difficult to maintain compared to a monolithic framework (Ember, Angular, Vue, even), because of all the other crap that might be used to take care of all the stuff React doesn't do.
For example, I recently took on a React project that used a whole bunch of other packages for state management, routing, etc., and a number of those packages were no longer supported (or outright compromised). While it's nice that React is still React, a lot of these other packages are tightly woven into the whole 'fabric' (react-swipeable-redux-router type stuff).
For my part, when I start a React project I try to minimize these problems by generally avoiding react-specific packages. So instead of react-router (which had its share of non-backwards-compatible updates), I'll just use page.js for routing. In some cases I might use the reactified version (Redux comes to mind, but I avoid that most of the time for smaller stuff).
This still isn't a panacea, and as a result I've been moving more and more stuff to a more 'vanilla' Railsy backend (Elixir/Phoenix, specifically). While the ecosystem does seem to be stabilizing a bit, it's still insane, and thankfully there are or will be ways to still add a bunch of 'dynamic' shit to the front-end without drowning in this insanity [1].
Using one of these frameworks helped us avoid that cost upfront and get the product out the door. If our company is still around in several years, I'll happily maintain it myself (or hire the original author).
EDIT: This comment assumes the framework of choice is open source.
(Disclaimer: made by my coworkers)
Personally, I've found Ant Design to be the most comprehensive, feature and behavior-wise.
All those things can be fixed, but I would rather go with a library with accessibility in mind.
Is there a React UI framework that focuses on tiny build size and browser compatibility?
" WARNING While open source, the intended consumers of this repository are Elastic products. Read the FAQ for details."
Doesn't instill confidence.
All that said, it certainly works fine as a general kit, and we build it with that practicality, it's just not something we officially support.
As far as stability, my team is pretty well resourced (and growing if there are any engineers interested!). We're using the library in many places around Elastic and its not going away anytime soon.
I've looked through most of the kits out there and they all have their pros and cons. Likely our biggest selling point is that it aims to be fully accessible and comes with a lot of fun charting libs. That puts its sweet spot for use in enterprise applications. It's also completely themable with about 8 lines of Sass variables.
https://habd.as/awesome-react-components/
https://habd.as/awesome-react-boilerplates/
Just added evergreen to the components list as it doesn't look like more than a UI kit.
https://github.com/material-components/material-components-w...
Obviously don't use that as a sole factor to determine what to go with, but with this many options, heuristics may be helpful to narrow down which ones to further investigate
It offers APIs compatible with React-native (which is obviously a huge time saver for cross platform UI dev).
Its disadvantage is that it does not offer (by intent and philosophy) any components outside of React native.
Issue #2: Many (most?) of the form components show no indication of being selected when using keyboard navigation. This is the main issue I have with most web UI toolkits. (For example, Semantic UI is a notorious offender, even though it's frequently recommended at HN, including multiple times in the comments on this page.)
Issue #3: There are multiple problems in Firefox, including two carets displayed in each Select component.
Issue #2 and #3 almost make me miss the notices that used to be displayed at the bottom of web pages, such as "Best viewed in Internet Explorer 4 at 800x600 resolution". A lot of pages nowadays should have a warning like "Best used in Chrome with a mouse or touchscreen".
No real point here, but I do find it curious that there is this tendency to build new UI frameworks all the time.
Personally, I still like html + js (and I have used React).
The're frameworks and design systems. A React UI framework refines or enhances the React process to build UI components or design systems.
Bootstrap e.g. is 2 things in 1, it's a process/framework and design system that sits directly on top of html, css & js.
So real world customers don't care about anything else. If it happens to work, or a team member decides to go at it on their own outside project budget, it is a nice to have feature that's it.
It's a super-lightweight base class for web components, and a descendant of the Polymer framework.
A Material Design framework uses this: https://github.com/material-components/material-components-w...
I agree in principle but it's up to browser vendors to implement specs, and it is always the same offender that is dragging his feet.
On mobile Web 100% of the browsers support Web Components.
https://www.webcomponents.org/
So what are the many popular browsers you refer to? As anything else is meaningless.
Your statement makes no sense whatsoever, they are "only missing" 2 of the most fundamental features of web components? that would actually help getting rid of all these incompatible UI toolkits? I don't call that supporting Web Components at all if you can't write custom elements natively. You obviously do not understand how the lack of support for custom element and shadow DOM affects Web Components adoption.
Not supporting 2/3 of a spec is not being compliant with that spec, obviously.
That leaves only IE11/Edge with polyfills.
what polyfills are you talking about? And no, Polymer is not a polyfill for custom element. Please link me to a library that will polyfill the entire shadow DOM and Custom Element spec so that I can write the same code without polyfills on platforms that support both specs and only load the polyfills on platforms that do not.
Quote from the readme.
" A suite of polyfills supporting the Web Components specs:
Custom Elements v1: allows authors to define their own custom tags (spec, tutorial, polyfill).
Shadow DOM v1: provides encapsulation by hiding DOM subtrees under shadow roots (spec, tutorial, shadydom polyfill, shadycss polyfill). "
https://github.com/vuejs/vue-web-component-wrapper
"You will also need the Shady DOM + Custom Elements polyfill." from Vue docs. Same polyfills are used by svelte etc.
Plus there are polyfills available for the meantime.
So what other browsers are many popular?
Apparently you haven't read my first comment either, since you can't tell the difference between "a spec is implemented" and "planning to implement a spec" which you obviously count as "a spec is implemented" for you or you would have refrained from making your first comment.
And no, there is no polyfills for shadow DOM or Custom Element, that's a lie. Polymer is not a Polyfill for Web Components, it's his own framework.
As for your question, I'm talking about browsers that do not support Custom Elements right now. Edge does not.
Firefox already on beta.
As for Edge it is already in development, and to be honest it doesn't matter with its insignificant market share.
When Microsoft employees use only Chrome at BUILD to show Azure and .NET Core MVC features, the writing is on the wall how relevant the browser is on the market.
Still you keep running away to clarify what "many browsers" means.
Maybe it is my lack of native English skills, but Edge being a single browser is far away from being "many browsers", even if we include Firefox until they get out of beta, two still does not make "many browsers".
Market shares are not the same across countries, clients or even industries. That's the first mistake you are making. If I develop a product, I target whatever browser my customers use, not some world wide statistic that has very little local significance.
You just don't get to ignore what goes against your point just to feel that you are winning an argument, that's childish.
> 100% on mobile Web.
Which is False, Firefox on Android doesn't support web components.
> Firefox already on beta.
Which doesn't matter if support has not shipped. "will ship" is not "has shipped". I am only interested in current support, as we speak, I was never talking about "will eventually ship" since I don't work with eventual features, obviously.
Mobile web is all about Safari and Chrome.
Again you keep avoiding to explain what "many browsers" means.
Edge cannot be ignored if one is serious about any kind of business: that's 3-4 out of every 100 desktop users (existing or potential customers), or 'just' 2/100 if one includes mobile.
— Honestly, it seems that you are trolling. But I post the above stats in case you are not. But I also back it up with my own personal 'anecdata': I build business-to-business ecommerce, in our specific market our users are primarily (>95%) using desktop browsers, we have many thousands of existing business relationships, we cannot mandate which browsers they use — we draw the line at having the site simply work in all "modern browsers", which obviously includes Edge.
It doesn't really matter whether it's "many browsers" that don't support Web Components, or whether it's just one major browser. For many businesses, choosing WC is simply not a viable option for the foreseeable future.
[0] No affiliation, just googled it. [1] https://netmarketshare.com/browser-market-share.aspx
I have written already in multiple answers, it is the customers that decide which browsers should a given project support, by explicitly stating them on the project delivery contract.
So your customers care about EDGE, fine. Many don't.
Er, really? I use Edge. It's just what's standard on the Windows machine I bought. I can't imagine that it has insignificant market share...
As for actual market share, http://gs.statcounter.com/browser-market-share
If it doesn't make the list, it is a nice to have only, in case someone on the team bothers with it.
Microsoft by using mostly Chrome at BUILD 2018 has given the sign to many businesses that it isn't worthwhile to list EDGE as a requirement.
So Edge is the only browser missing 100% native support right now.
https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Rel...
> On mobile Web 100% of the browsers support Web Components.
Wait. Which is it? Or are you ignoring Firefox Mobile?
Also polyfills are separate thing from polymer - they are reused by ALL other frameworks including vuejs for example, so I'm not sure what you meant by that comment.
Everything else that builds their little platform on top of the browser is not interesting to me.
And TypeScript is a JavaScript superset with optional type annotations, which can be ignored if one so chooses.
Those are not standard, some people like VDOM other not, and not everybody want to bind data the same way. So if we all contributed components in vanilla JS / Web Components, this still doesn't solve what should the API of those webcomponent look like.
With Web Components you're back in the land of saving element references, querySelector, addEventListener, and string-only attributes. It sucks. If you want something more like what React provides, where attributes (props) can be objects, functions, other React elements, etc. then you need to use a library (e.g. Polymer) that's just as non-standard as React is.
> The only difference between if this were a web component vs a React component is that the consumer would not capitalize the name. Instead of `<Button appearance="primary">` they would do `<evergreen-button appearance="primary">`.
If you're not using React, you obviously can't do `onClick={...some function here...}` with Web Components, you have to use the shitty DOM APIs.
But I would expect this still would not work as expected with props like `children` or other props that accept React elements. It seems like the web component would be expecting Node instances, not React elements. Since components can decide whether or not to render their children, they wouldn't be backed by Nodes yet when the web component received them. So it seems like it'd have to know whether it's dealing with React and use ReactDOM.render directly.
IMO saying 60kb of react+vdom code vs 6kb of templating library that builds on top of template literals is equally non-standard is not a fair comparison.
That's what makes the grandparent's statement incorrect:
> The only difference between if this were a web component vs a React component is that the consumer would not capitalize the name. Instead of `<Button appearance="primary">` they would do `<evergreen-button appearance="primary">`. That's it.
^ wrong.
It's a bit disheartening to see titles like "Ember ninja" and "Angular guru", if only because recruiters don't know that both of those things are just JavaScript frameworks.
I'm excited for Web Components but I wonder how it will play out practically. Do people put "HTML Expert" on their resumes today?
Because their current system might already be using Bootstrap, so they need someone who understands it to be able to continue the work.
The reason I asked it is that, if you're building an HTML+CSS framework for use in React, then why wouldn't you separate out the HTML+CSS part, and then depend on this. That way it would be easy to re-use 90% of the work, if you then want to use the components with Vue or some other framework, or even for plain static pages.
They are React component frameworks for common functionality with a unified style approach.
Something purpose-built for React is usually much better than something where React is bolted on to an existing framework, like Reactstrap (React + Boostrap) because those usually are built with jQuery and just handle state and functionality in a way that's not easy to integrate with React cleanly, so you end up re-implementing the actual functionality again.
Just something to consider if you're looking at using Evergreen.
It's responding to the device and the ways the user will interact with it. For example, the combobox example in Evergreen doesn't actually use a <select> in the background, so users on mobile devices will actually have to use the dropdown implementation rather than the browser displaying a proper native mobile select. That's a much worse experience. Not to mention Evergreen will be completely inaccessible for users who need assistive technology, which potentially poses legal issues...
You'd think in 2018 going back to a page would be a solved problem, but apparently each new framework needs to re-solve this in a new orignal way.
Just tried it in Firefox 62 on Ubuntu. Works good there too.
To me the Reddit web app is fast, the show part I think is the server side.
I built a SPA recently and learned pretty quickly to replace `on('scroll', handler)` with a set-flag-and-sweep-at-slower-interval solution to bring down CPU usage.
While something like React alone isn't slow, building a SPA means you're taking on a lot more responsibility, and there's a lot more things that can go wrong.
Even something like "when user clicks an item, make loader spin until server response, and then render the detail page with the data" can feel much, much slower even though it's not from a clock-time standpoint.
Aside: Using a slow device as your main testing device is a life-changer if you want to catch this stuff early. It's hard to ignore this stuff when you have to feel the pain yourself on every refresh. Good reason to always keep your old phone around.
So no, I do not believe reddit's new design is "performant" at all.
One has to wonder - if Reddit's engineers can't get React right (I'm sure they hire smart people), is it really not a problem with React in the end?
It has nothing to do with the round trip latency, the CPU is pegged.
So for many people, the benefits you get on the development side outweight the performance overhead
Also worth noting the ones I listed aren't transitive dependencies. Those are both explicit dependencies of this project
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
...
var btnClass = classNames({
btn: true,
'btn-pressed': this.state.isPressed,
'btn-over': !this.state.isPressed && this.state.isHovered
});
Look like the button example is a good enough convention for me, I don't need any of the other conventions. Can anyone tell me why this is not sufficient?: const classNames = (pojo, c=[]) => {
for (let k in pojo) if (pojo[k]) c.push(k);
return !!c.length && c.join(" ");
}
Do I need array-flattening support, multiple argument support? The size of this library probably comes from it supporting a handful of different coding styles. I would say the size (50 lines) is too large, if anything. Dependency worthy? I'm not convinced. I am very much so against requiring trivial utility functions from other people. Roll your own if it's trivial! It's better than depending on something over the network. it("should work with no classes", () => {
expect(classNames({}).to.be.false
})
it("should work with a single class", () => {
expect(classNames({a:true})).to.equal("a")
})
it("should work with booleans", () => {
expect(classNames({a:true, b: false}).to.equal("a b")
})
it("should work with falsy and truthy values", () => {
expect(classNames({a: 5, b: ""}).to.equal("a b")
})
This isn't redux. It's a trivial utility function. Your kind of thinking is too often applied without thinking. Before depending on someone's code, ask yourself if you can roll your own in under 5 minutes. The answer could easily be yes. There is no good reason to depend on someone else's code if it's trivial. Having more dependencies than you need is a cardinal sin that way too many javascript developers commit. it("should work with booleans", () => {
expect(classNames({a:true, b: false}).to.equal("a b")
})
Shouldnt this just equal "a" though? See, already a bug in your homegrown solution!A few people in this thread have regurgitated the same reasoning you have. The problem is that your reasoning is NOT an invariant under complexity. This reasoning does not apply nearly as much to trivial utility functions such as:
const isObj = o => !!o && typeof o === "object"
and classNames, etc. as it does to larger, more complex code.> will consult you about your intentions when you wrote the code etc.
No, no they won't. No one will consult me on what my 2-line classNames functions does. It's 2 non-obfuscated lines. These aren't undergrads in CS101.
And you can't write this particular utility function in 5 minutes and support all the uses-cases, particularly if you are going to write a bunch of unit tests.
The reason to depend on someone else's code in trivial use-cases is entirely because they are trivial. There's nothing you're doing aside from wasting time by writing it. lodash is literally a massive library of mostly "trival" functions that no one is every going to write themselves because WHY waste the time?
The only cardinal sin at play here is thinking that wasting your time reinventing the wheel is time well spent. This approach is what I'd expect from either a very young developer or a very self-centered one.
Why does everyone in JS land treat dependencies like they're just some free magic, as if an intimate familiarity with the source code is injected into your entire team's brains the moment you type 'npm install'? I've worked with far too many people that blow out the package.json file for every little thing then wonder how every other dev on their team seems to be paralysed by the smallest task.
Every time someone on your team runs into a dependency boundary they need to stop reading code, pull up a browser, and start reading docs. You can't trace the path of execution through a black box dependency, which means if you use a bunch of them in one place your developers are going to have to hold a hell of a lot of information in their head while they analyse that code. If they drop something, it's back to the docs again. At the extreme, it's a context switching nightmare.
Dependencies cost time, effort and brain power. Make sure you're getting enough in return.
Dependency boundary? If you can't figure out what a function called classNames does in the context of a React render function in which the output of classNames is put as a value in to "className" attributes, you need to find a new job.
Dependencies cost time, effort and brain power when they actually require those things. Be thoughtful when using something that actually requires investigation. But honestly, a trivial function should be self-documenting or it really isn't trivial, is it? If I had an npm library called array-flatten are you seriously going to read the docs, or assume it flattens nested arrays?
Of course it's easier to read a trivial function than the docs for a trivial function. That's what makes it trivial, it's not abstracting away anything meaningful. And of course I can easily figure out what classNames outputs.
You know what I can't figure out trivially? What inputs it takes. It's a polymorphic function. Me and Bob load up a new codebase, I open a few files and see classNames used a couple of times with an object parameter. I can now be pretty confident what the API of the function is. Bob opens up a couple of different files and sees it used with an array parameter a few times. Now he's pretty confident he's got the hang of it too. We both go off to write new components. I've got a bunch of this everywhere:
{ foo: true, bar: true, baz: true }
And Bob has a bunch of this everywhere:
[foo ? 'bar' : null, baz ? 'boop' : null]
Bam, inconsistent code. Could have easily been solved by reading the docs before using something though. And hey, at least we'll both remember for next time...
...Unless our team imports 100 of these libraries and tries to enforce a consistent use of them across the project.
There's only so much API surface area one dev can keep at the front of their mind while coding. Good devs understand this and minimize it. Bad devs pile in trivial dependencies because they don't understand their cost.
Oh, and how do I know whether flattenArray is recursive or not? What if it is and I only want to flatten one level? Does it take a second integer parameter? Or an options object? Since we're talking about JS, does it flatten Array-like objects? Is that the same API or a different one? It's almost like your example proves my point...
Yeah, and in CR you should be told not to use the object form when you have "true" as the value, as it's pointless. That's what string form is for. The "docs" are literally 5 lines where you learn you can send object literals, arrays and strings.
> There's only so much API surface area one dev can keep at the front of their mind while coding. Good devs understand this and minimize it. Bad devs pile in trivial dependencies because they don't understand their cost.
Yes, because if you implement a similar feature the remaining members of your team all know it through osmosis. The surface area of these functions is tiny, but apparently your implementation requires no investigation by anyone.
> Oh, and how do I know whether flattenArray is recursive or not?
Holy cow, man. Do you literally hand-implement EVERY utility function you've ever needed?
> It's almost like your example proves my point...
Your point seems to be: you can't manage to infer ANYTHING from a function signature AND that apparently somehow your team members can ALWAYS infer everything needed from any function YOU write.
Use code inspection and you'll never open the docs for flattenArray or anything like it again. If this is the amount of effort required for flattenArray for you, how to you actually use large libraries with HUGE surface areas?
What a dumbass argument. So instead of writing a one line abstraction, I should invest a bunch of CR time explaining to my whole team which of 3 different APIs they should be using in this dependency I've brought in?
> Holy cow, man. Do you literally hand-implement EVERY utility function you've ever needed?
No, just the trivial ones. Have you been actually reading this thread?
> Your point seems to be: you can't manage to infer ANYTHING from a function signature
No, my point is that you can't infer the full API of a function from the arguments passed to it's invokation when the function is polymorphic.
> AND that apparently somehow your team members can ALWAYS infer everything needed from any function YOU write.
If the function is trivial, which is exactly what we've been talking about this whole time, then No. Fucking. Shit. The function is trivial and they have the source code right there.
It's not a one-liner because it doesn't support the same feature set. It supports a basic use case that may be great for trivial apps, but in the real world it isn't.
> No, just the trivial ones. Have you been actually reading this thread?
And said trivial ones must still be "learned" by your co-workers. You've saved exactly zero time.
> No, my point is that you can't infer the full API of a function from the arguments passed to it's invokation when the function is polymorphic.
You can with a glorified text-editor these days with Code Inspection. I guess that's advanced stuff we shouldn't expect our co-workers to use?
> If the function is trivial, which is exactly what we've been talking about this whole time, then No. Fucking. Shit. The function is trivial and they have the source code right there.
Yet, if the function is trivial AND is imported via npm, it suddenly requires reading docs. On one hand you argue "triviality requires reading docs" and then suggest that you can implement a similar trivial function and everyone can just look at the source code.
And you don't see the irony here.
What I'm saying is that it's EASIER to understand the source code than it is to understand the documentation for classnames. That's because it abstracts nothing away. It's replacing one simple API (template strings) with another one that's very similar and of roughly the same power. By turning it into a dependency you're adding an artificial barrier between it and your code base, that makes it harder for everyone to grok. Not much harder, but enough to be a pain in the ass in any codebase where that same tradeoff is made over and over.
If you can't understand that, then I don't know what to do for you. Keep writing shit JS code and making the web worse than it already is.
No, we're talking about 2-3 line functions. Stop arguing with a straw man. You're taking what you know to be true about complex code, and then asserting that those things are also true with simple code. That doesn't work.
> And you can't write this particular utility function in 5 minutes and support all the uses-cases
The beauty is that because we are rolling our own function, we only need to support the single function signature we decide we're going to stick to in our codebase. Supporting every use-case becomes a moot point.
The author of the library has to support the 10^5 people who use his code, meaning he's more likely to merge silly pull requests like "should take objects", "should flatten the input array", "should allow multiple arguments", "should work with X", "should do Y" because people have different styles.
> The reason to depend on someone else's code in trivial use-cases is entirely because they are trivial. There's nothing you're doing aside from wasting time by writing it
It only takes time if you are not able to do basic programming. I find basic programming to be a much more enjoyable and productive approach than depending on potentially dozens of trivial libraries whose APIs are not the way I would design them, and could change at any time. Learning dozens of APIs takes just as much time as implementing them for a certain set of functions. That set is different for everyone, but it is not the null set for anyone.
The library in question is literally 50 lines of code. About 30 when you remove the exports and comments at the top. I find it somewhat ironic that you are so opposed to using utility libraries and you didn't even bother to look at the one in play here.
> The beauty is that because we are rolling our own function, we only need to support the single function signature we decide we're going to stick to in our codebase. Supporting every use-case becomes a moot point.
No it doesn't. All the use-cases are useful. You use strings when you need default classes and objects when you have conditional classes. You can't implement both of those in two lines of code.
> The author of the library has to support the 10^5 people who use his code, meaning he's more likely to merge silly pull requests like "should take objects",
It's always taken objects as properties and for good reason: it's a clean way to separate conditional classes from unconditional ones.
But sure dude, all those features are insane. Put his code up to a solid 30 lines. Really saving the bacon by rolling your own that doesn't do the same thing.
> Learning dozens of APIs takes just as much time as implementing them for a certain set of functions. That set is different for everyone, but it is not the null set for anyone.
Yeah, that's why everyone writes their own lodash. It's just a set of trivial functions.
const cmpClass = classnames('componentsMainClass', props.className, { dynamicClassesHere });
I like that the component's main class stands out and is easy to find, that allowing the consumer to pass along their own class is trivial, and that the dynamic classes are grouped together.So I'd argue multi argument and falsy thinning are welcome features. I've never used array flattening.
Does it really need to be a dependency? I guess that's a matter of opinion. I like that the various React projects I deal with on a regular basis all handle classes in a consistent manner. I also don't usually mind dependencies that don't pull the entire world in with them.
This is a matter of convention. Another, equally valid convention:
classNames({
mainClass: true, // first key is main class
[props.className]: true, // derived
otherClass: true, // rest
yetAnotherClass: true // ...
})
At the end of the day, everyone has to learn their codebase's convention, and that's all that really matters. One convention isn't better or worse than any other, but it's best to have one and stick with it. I don't need a library which supports 10 different conventions if my chosen convention only requires 2 lines of code. Your convention could be implemented in a few lines of code, as well, and then you'd be forced to stick with it, which is probably better. Using this library, 5 different developers could be using 5 different conventions. The helper function I suggest forces a single convention, which lowers complexity. classNames({
mainClass: true,
[props.className]: props.className,
otherClass: somePredicate
})
The props.className one in particular is pretty garish. Probably should do !!props.className to help explain intent a bit, which adds to the tedium. Once you've added falsy thinning and arbitrary arguments, you're 99% of the way to classnames. const classNames = [
“btn”,
this.props.isSelected && “btn-selected”
].filter(Boolean).join(“ “)Pretty neat, actually.
Why is this something you can't do on your own in a few lines of code?
const classNames = (o, c=[]) => {
for (let k in o) if (o[k]) c.push(k) // booleanish
return c.join(" ")
}
This is not cool at all! Why import a trivial function over NPM to do this for you? Better to lower your dependency count and have a "util.js" file for helpers like this.Doing that for one dependency is bad enough, but for 100s it's a nightmare.
Personally, I prefer to just pull the pieces I need out of an open source library (unless it's very well maintained, or huge). It's like doing a code review at the same time, so you're aware of what's going on in your application.
Don't know about you, but we have actual goals and I'd never meet them if I tried your method.
Not quite, that would imply time and effort. I'm talking about reinventing the toothpick (2-3 lines of code), which is much different than reinventing a complex library for the sake of reinventing it.
> Rolling your own diffing algorithm is exactly what actual engineering entails
That's nice, but you're addressing a straw man. No one actually said rolling your own diffing algorithm is not what engineering entails. It was said that no one is suggesting you recreate a non-trivial dependency for the sake of reducing your dependency count.
I can use it in an example if it helps: If you are hired to write a basic website and you choose React, then you probably shouldn't reinvent React as your first step in writing the website. React is a fine dependency because it does a lot.
Humor me -- the next time you use classNames for a small project, try and see if you can't replace all of your calls to classNames with very basic template strings or other trivial code. It should not take any effort. For example I've seen things similar to "classNames({myClass: true})" in code before. Can you see what is wrong with this line? When people get comfortable with abstractions, they completely forget how to write the simplest code.
Re-inventing 1000 versions of a tooth pick is reinventing the wheel.
> That's nice, but you're addressing a straw man.
You keep using that term and I'm not sure you understand what it means.
> It was said that no one is suggesting you recreate a non-trivial dependency for the sake of reducing your dependency count.
And my argument is that dependency count is one of the dumbest metrics to be interested in. Size, sure as that impacts bundle size, which in-turn, effects latency. But "count" is meaningless.
> Humor me -- the next time you use classNames for a small project
I use styled-components exclusively for React projects now.
> For example I've seen things similar to "classNames({myClass: true})" in code before.
So? Bad code is bad, that's not a library failure. Now that is a straw man.
> Can you see what is wrong with this line?
Of course I can, because I'm actually good at my job. I also wouldn't do that. Using your toaster in a bathtub is also REALLY stupid, but that doesn't mean we should ban toasters.
> When people get comfortable with abstractions, they completely forget how to write the simplest code.
No that's called laziness and it has nothing to do with dependencies. You have twice in this thread accused me of straw men inaccurately, and now wrote a paragraph dedicated to a huge straw man.
To quote yourself: Doing that for one dependency is bad enough, but for 100s it's a nightmare.
'Forking' a project's dependencies (which is effectively what this is...) is often fraught with as much trouble as just having the damn dependency in the first place.
It's like everyone in JS land is allergic to writing a piece of code that isn't just playing lego with things written by a real developer.
export default function classNames(...args) {
return args.filter(valid).map(single);
}
function valid(arg) {
return arg && (!Array.isArray(arg) || arg.length);
}
function single(arg) {
if (typeof arg === 'string') {
return arg;
} else if (Array.isArray(arg)) {
return classNames(...arg);
} else {
return Object.keys(arg).filter(k => ………
This is getting similar…Thats partly the point. The whole API doesn't really need to be covered in order to achieve the same utility. I think the library clearly over-engineered the simple task of string concatenation, and their API is redundant.
Their API caters to too many styles and that increases its complexity. It takes 2 seconds to grok the two lines in my utility, whereas it takes 5 minutes to make sure you know all 50 combinatorial ways to concatenate a string with the classNames library. There is too much indecision in the API, so they decided to support everything they could think of. Now I have to be ready for the possibility that the 5 people on my team can't agree on a convention simply because the library allows every possible convention one could desire.
That's a whole lot of complaints for 50 lines of code.
> Other times you have class names that have prop dependencies so you use object style
> merge in some always-on defaults so you have string style
There's some irony here -- all of this just to avoid dealing with string templates:
`${class1} ${class2} ${class3}`
> You'll often need to combine themNeed is definitely not the right word here. The classNames utility is a completely unnecessary abstraction.
Your solution doesn't do anything I'd expect someone wants that lib for, like merging in a map of classes.
I don't think this lib is the best pyre to die on to make a point I generally agree with.
By that argument, we can just avoid everything by not making our apps dynamic!
> The classNames utility is a completely unnecessary abstraction.
The only necessary abstraction in programming is assembly since 0's and 1's are hard to reason about. The "need" in this case refers to needing to mix different primitives to make your app dynamic. Your arbitrary example above doesn't do anything because you still have conditional logic to determine what class1 class2 and class3 are, you are just doing a bunch of ugly crap in the render function rather than abstracting it. Or implementing your own version because you're smart.
It's a stupid hill to die on here... you want to argue about importing the entire lodash library because you like .chain, have at it. But I guess you can keep patting yourself on the back for avoiding importing a no-dependency 50-line library.
But be prepared because it is the de-facto standard way of building classNames in React, also because it was part of the standard utilities provided by React.
The cost of using it is the same as locally, and creation cost is lower per-project if you let npm manage your own libs. Plus, bug fixes are automatically propagated.
[1] https://github.com/sindresorhus/ama/issues/10#issuecomment-1...
const arrify = a => a && (Array.isArray(a) ? a : [a])
vs. introducing a potential attack vector.No, it really isn't. The library does not dictate how things should be done, that's the fantastic thing about using your own utilities. In my implementation, we return the value itself if it's falsy. In yours, we return an empty array. Again, trivial "fix" (not that there's anything to "fix", it's a matter of convention, not correctness).
I feel like, a lot of ppl still create horrible UIs based on good components, because they lack the bright overview.
Responsive (in terms of interaction with components) and lightweightedness were our top priorities when we started developing (~3 years ago) and no third party solutions seemed to fit the bill back then. Always a fear as well of reliance on third parties for such an important part of the product - is a very large technical risk for the entire business.
We're pleased with the results, our entire app is smaller than the Apple homepage (usable after ~1MB of network transfer) and often starts up faster than our C++ native Windows predecessor. Bloating third party solutions could add significant %'s onto the download size - the example HN React Clone is a comparible size to our product: http://www.hnclone.win/
There was a lot of resistance from users initially when we announced the future of our product would be in the browser and not the native desktop app they were currently using, but we do get emails from users saying after using it for a while they forget they are working in the browser which is amazing.
If we started developing today, I think we'd still roll our own.
https://github.com/segmentio/evergreen/blob/master/src/icon/...
This looks good, though it also feels like it leans towards native controls; see Select vs. Select Menu, for instance. Material and Grommet have a unified style thing going on that this doesn't seem to. But this has more controls and seems more mature.
https://ant.design/ is the main page, https://ant.design/docs/react/introduce for react, and for angular: https://ng.ant.design/docs/introduce/en
Can't we embrace web components already and have those UI frameworks work in all popular solutions out there? Every time something new comes out existing solutions are being rewritten from scratch.
Why specifically this one?
I take it the main thing is their methodology for applying styles rather than css classes which might or might not make the code more readable.
Also, custom select inputs always ignore a big percentage of the functionality that native select inputs deliver.
Props to @jeroenransijn, @rowno and others!