Componentify it

ball

Original image by Jonathan Kos-Read, licensed with Creative Commons BY-ND 2.0

One of the most amazing things about Web development is the scale of bicycle inventions. Pretty much every developer at some point decides to conquer a common problem by rewriting it from scratch. Reusing existing solutions is often difficult - they are likely to be tied to internal styles, libraries, build processes. This creates a nurturing ground where same features are implemented many, many times not only because developers think they can do it better, but also because there are too much of efforts to reuse existing solution without bringing up all the dependencies.

This blogpost is about Component approach. Components are designed to have as little dependencies as possible, relying on common web technologies, easily reusable and extendable. With component approach it's trivial to unplug parts of the app and replace them with other parts or improved version of the same component. There are certain principles to be considered when releasing new components, since the Component itself doesn't really limit you in any way. It is possible that later on we'll have some monster components with huge amount of dependencies lurking around - but then again using such components is completely up to you.

When an aspect of a component may be useful to others, consider writing that as a component as well. If it requires reasonable effort to write the code in the first place, chances are someone else could use it too.

Building better components

Make a new component

Component comes with a handy console command. Assuming that you have component npm package installed - try running component help

To create a new component you can run component create mynewcomponent. This command will ask you (quite) a few questions, and then will create a new folder with some basic files.

If you try compiling newly generated component, you might get a following error:

$ component build
error : ENOENT, open '/Users/alex/red-badger/mytestcomponent/template.js'

This happens because there is template.js file specified in component.json, but is not generated by component create. You can either create this file manually, or remove it from component.json. After that component build should generate your first component under /build folder.

Each component can contain any amount of:

  • JS files, with mandatory index.js or main.js file assigned to a "main" directive in component.json
  • CSS files
  • HTML files
  • Local and external dependencies to other components

All assets must be explicitly listed in component.json, otherwise they are ignored. This is another clever feature of Component since the folder might contain temp files, npm packages, generated files. When Component is instructed to pick only certain files, it will not only limit the build to these files, but also fetch them from Github (ignoring everything else you could've pushed there on purpose or by accident). This way building components with dependencies becomes much faster.

Component doesn't have to contain any JavaScript logic, and can simply export HTML template or CSS style:

You can componentify any bit of style, markup or functionality into a reusable package. As long as it makes sense.

Entry point

A fairly common pattern for a UI component is to ask for a DOM selector where the component would insert itself.

You can also use component/dom component for basic DOM manipulations. Dom component is obviously not a jQuery replacement, and lacks lots of jQuery functionality. You can live well also without dom component and manipulate DOM directly with document methods like document.getElementById, document.querySelectorAll. Adding and removing classes to elements can be slightly more challenging without any libraries, but there is a special component for that too - component/classes

Here is an example of component main.js using dom component and appending itself to the target element:

In this case dom component would be specified in the dependencies section of component.json:

Using CoffeeScript, LiveScript, LESS and JADE with components

If you are going to release a public component, it make sense to package it with conventional JS/CSS/HTML files to reduce amount of dependencies and increase reusability. For internal components we've mostly used LiveScript, CoffeeScript, LESS styles and JADE templates. And to complete the LiveScript picture, we've repackaged Prelude.ls library into a component and used it as dependency.

Notable npm packages for component builds:

In Gruntfile you can configure builder to use extra components:

And in grunt.initConfig section:

Global and local components

When using components extensively in your app you might end up with lots of public and private components. All public components and their dependencies will be automatically installed into a /components folder. It's a good idea to put your private components into a /local folder next to the /components folder. You can also have dependencies between your local component:

Syntax for local dependencies slightly differs from the global dependencies - there is no version, and you just list all local components as array.

In the root of both /local and /components folders you will need a main component.json file, which will tell the build process which components needs to be included in the final main.js file:

paths will tell the builder to look for /local folder in addition to /components folder.

Later in the html file you simply include this generated main.js.

The content of this file is evaluated, now you can require and start using any of the components on your pages:

Most of Red Badger components include example html file with everything you need to start using that component on your pages.

Check for existing implementation

Before implementing your own component, it might be worth of checking for existing implementation. Most of the components are listed here:

https://github.com/component/component/wiki/Components

Component.io site is another slick way of browsing and searching for existing components. In many cases you'd want to start with existing component and either use it as dependency or fork and add your own functionality. Standard component/components are especially easy starting point for extending.

Conclusion

Component approach requires some extra efforts. You have to abstract and package bits of UI, make them fairly independent and think of the possible reuse cases. You can ignore the new components creation stage completely and just use existing components. We chose to componentify most of our recent World Risk Review project and this proved to be a brilliant decision. Instead of repetitive blocks of styles, markup and logic we managed to put most of the front end elements into components and reuse them when needed. Some of the components were also released as open source, and we hope to see even more useful components released in the future!

Alex Savin

Software engineer

More from Alex