4 ms·
I've thought about why widget libraries don't work on the web since 2008. In 2007 I was making iOS webapps, in 2008 Apple put out the SDK and the native apps we
by grayrest 11y ago
I've thought about why widget libraries don't work on the web since 2008. In 2007 I was making iOS webapps, in 2008 Apple put out the SDK and the native apps were better. I decided that the native apps were better because the devs didn't blow 60% of their time budget building a poor, custom widget library. The problems I've encountered:
The first and most basic is that the expectation on the web is that every project will have a unique look and feel. This greatly limits the adoption of frameworks based on desktop widget library concepts (dojo, ext, sencha, cappuccino, sproutcore). The times I've used these frameworks, I spend as much time fighting the look and feel as I would building an interface from scratch. This isn't a problem if you're look and feel insensitive and desktop style widget libraries do get picked up for internal corporate apps.
The second problem is size. The need to download everything, desire for reduced page load times, and lack of dead code elimination has historically made web devs more sensitive to the size of their libraries. This was a problem for libraries like YUI2, which had excellent components that simply had an option for anything somebody at yahoo wanted but adding a new widget would frequently add hundreds of K to the download. This is a reduced concern with the increased capabilities of mobile and I believe that the combination of HTTP2, having a standard module system, increased tooling (e.g. webpack), universal/isomorphic JS, and ServiceWorker provide the means to more or less eliminate this as a core problem.
The third problem is CSS. The language provides no tools for abstraction when the target markup (your widget) is fixed. Happily, this problem is solved via sass. You can separate style concerns into mixins (or placeholders) and compose them into either widget or instance specific rules and avoid the cascade.
The fourth problem is component composition. In order to get more code reuse, you need to be able to build up bigger widgets from small pieces and then make a lot of useful small pieces. Stateful components don't compose particularly well and I've spent a lot of time on this (in yui3, knockout, and angular) before I found React's virtual dom approach two years ago. With the vdom, it's possible to view components as functions projecting state onto a virutal DOM. Composition can then be solved by creating higher order components and using normal functional programming composition and code reuse. With care put in to how larger components are designed, it's possible (I've done it) to swap out sub components to customize behavior on a per-instance basis. I consider the core problem solved but I haven't seen the equivalent of an underscore for react components yet.
The fifth problem is widget interaction. I define widgets as components that are an isolated concern (and generally maintain internal state): Autocomplete instead of FooList. Since the components are generally stateful and produce events, you have to have a protocol for having them interact with each other and the rest of the app. As an example, a FOO widget is a React component has PropTypes that get compiled into a Falcor query and all its event handlers call a function `dispatch` with an object shaped like X. Everybody comes up with this in their app but without a consensus on what the approach is, everybody's widget libraries are parochial. This is an active area of development and Web Components is Google's take on the problem. Facebook is also very interested in this with Flux/GraphQL.
Once all the problems are solved (I believe we're relatively close) then we should see widget libraries come into their own. I'm estimating about 3 years before someone starts really winning the widget library battle and we get a "standard" set of widgets you're looking for. I believe that something from the React or Ember communities are the likely source and Polymer has an outside chance (I don't see how component composition works in Polymer).
- Flenser 11y ago> With care put in to how larger components are designed, it's possible (I've done it) to swap out sub components to customize behavior on a per-instance basis. Thank you for posting this. I've been wondering if this was possible. Can you share any insights that might help someone that wants to do this?
- grayrest 11y agoThe basic idea is to have your components take optional params that are themselves components. ESPseudoish code: // In your components... let DefaultListItem = (content) => <li className="foo">{content}</li> let DefaultList = (items, Li=DefaultListItem) => <ul>{items.map(Li)}</ul> let SortableItem = (content) => <li className="handle" on-drag={(e) => dispatch('dragStart', hash(content))>{content}</li> let SortableList = (items, Li=SortableItem) => <DefaultList {...this.props} /> let EditableList = (items, List=DefaultList, Li=SortableItem) => { <div><List {...this.props} /><button>Edit</button></div> } let SearchResultHighlighter = (text) => <span className="imagine-this-highlighted">{text}</span> // -- In use... let source = ['foo', 'bar', 'baz'] render(<SortableList items={ source.map(SearchResultHighlighter) } />) let ImageItem = (url) => <li><img src={url} /></li> render(<EditableList items={ source.map(x => x + '.jpg') } Li={ImageItem} />) There's a lot of design space to play around with. For a widely reusable library, I want something like Clojure's protocols or Rust's traits so I can indicate to people what the component needs/provides without them looking at the source.
- Flenser 11y agoThanks. I've been thinking about the component provides/needs issue as well. I was thinking of wrapping any passed in sub-component in "polyfill / rewire" component created from a factory that can be passed the propTypes that the parent component expects it's child to support and a map from props it will be passed to the props it actually supports. Ideally I'd like to be able to do something like switch between react-material and react-bootstrap on the fly.
- laichzeit0 11y ago